/* * Copyright (c) 2004 University of Murcia. All rights reserved. * -------------------------------------------------------------- * For more information, please see . */ package org.umu.cops.prpdp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.umu.cops.stack.*; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Core PDP agent for provisioning */ public class COPSPdpAgent extends Thread { public final static Logger logger = LoggerFactory.getLogger(COPSPdpAgent.class); /** Well-known port for COPS */ public static final int WELL_KNOWN_PDP_PORT = 3288; /** Default keep-alive timer value (secs) */ public static final short KA_TIMER_VALUE = 30; /** Default accounting timer value (secs) */ public static final short ACCT_TIMER_VALUE = 0; /** PDP host port */ private int _serverPort; /** Client-type of connecting PEP */ private short _clientType; /** Accounting timer (secs) */ private short _acctTimer; /** Keep-alive timer (secs) */ private short _kaTimer; /** Maps a PEP-ID to a connection */ private final Map _connectionMap; // map < String(PEPID), COPSPdpConnection > ConnectionMap; /** * Policy data processing object */ private COPSPdpDataProcess _process; /** * Creates a PDP Agent * * @param clientType COPS Client-type * @param process Object to perform policy data processing */ public COPSPdpAgent(short clientType, COPSPdpDataProcess process) { _serverPort = WELL_KNOWN_PDP_PORT; _kaTimer = KA_TIMER_VALUE; _acctTimer = ACCT_TIMER_VALUE; _clientType = clientType; _connectionMap = new ConcurrentHashMap<>(); _process = process; } /** * Creates a PDP Agent * * @param port Port to listen to * @param clientType COPS Client-type * @param process Object to perform policy data processing */ public COPSPdpAgent(int port, short clientType, COPSPdpDataProcess process) { _serverPort = port; _kaTimer = KA_TIMER_VALUE; _acctTimer = ACCT_TIMER_VALUE; _clientType = clientType; _connectionMap = new ConcurrentHashMap<>(); _process = process; } /** * Sets the keep-alive timer value * @param kaTimer Keep alive timer value (secs) */ public void setKaTimer (short kaTimer) { _kaTimer = kaTimer; } /** * Sets the accounting timer value * @param acctTimer Accounting timer value (secs) */ public void setAcctTimer (short acctTimer) { _acctTimer = acctTimer; } /** * Gets the value of the keep-alive timer * @return Keep-alive timer value (secs) */ public short getKaTimer () { return _kaTimer; } /** * Gets the accounting timer value * @return Accounting timer value (secs) */ public short getAcctTimer () { return _acctTimer; } /** * Gets the connection map * @return A Hashtable holding the connection map */ public Hashtable getConnectionMap() { return new Hashtable(_connectionMap); } /** * Gets the client-type * @return The client-type */ public short getClientType() { return _clientType; } /** * Disconnects a PEP * @param pepID PEP-ID of the PEP to be disconnected * @param error COPS Error to be reported as a reason * @throws COPSException * @throws IOException */ public void disconnect (String pepID, COPSError error) throws COPSException, IOException { COPSPdpConnection pdpConn = _connectionMap.get(pepID); COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, _clientType); COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); closeMsg.add(cHdr); if (error != null) closeMsg.add(error); closeMsg.writeData(pdpConn.getSocket()); pdpConn.close(); } /** * Requests a COPS sync for a PEP * @param pepID PEP-ID of the PEP to be synced * @throws COPSException * @throws COPSPdpException */ public void sync (String pepID) throws COPSException, COPSPdpException { COPSPdpConnection pdpConn = _connectionMap.get(pepID); pdpConn.syncAllRequestState(); } /** * Removes a PEP from the connection map * @param pepID PEP-ID of the PEP to be removed */ public void delete (String pepID) { _connectionMap.remove(pepID); } /** * Runs the PDP process */ public void run() { try { final ServerSocket serverSocket = new ServerSocket (_serverPort); //Loop through for Incoming messages // server infinite loop while (true) { // Wait for an incoming connection from a PEP Socket socket = serverSocket.accept(); // COPSDebug.out(getClass().getName(),"New connection accepted " + // socket.getInetAddress() + // ":" + socket.getPort()); // We're waiting for an OPN message try { COPSMsg msg = COPSTransceiver.receiveMsg(socket); if (msg.getHeader().isAClientOpen()) { handleClientOpenMsg(socket, msg); } else { // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); try { socket.close(); } catch (Exception ex) { logger.error("Error closing socket", ex); } } } catch (Exception e) { // COPSException, IOException // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION, // "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e); try { socket.close(); } catch (Exception ex) { logger.error("Error closing socket", ex); } } } } catch (IOException e) { logger.error("Error caught while processing socket messages", e); } } /** * Handles a COPS client-open message * @param conn Socket to the PEP * @param msg COPSMsg holding the client-open message * @throws COPSException * @throws IOException */ private void handleClientOpenMsg(Socket conn, COPSMsg msg) throws COPSException, IOException { COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg; COPSPepId pepId = cMsg.getPepId(); // Validate Client Type if (msg.getHeader().getClientType() != _clientType) { // Unsupported client type COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); COPSError err = new COPSError(COPSError.COPS_ERR_UNSUPPORTED_CLIENT_TYPE, (short) 0); COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); closeMsg.add(cHdr); closeMsg.add(err); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Error writing COPS data", unae); } throw new COPSException("Unsupported client type"); } // PEPId is mandatory if (pepId == null) { // Mandatory COPS object missing COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); COPSError err = new COPSError(COPSError.COPS_ERR_MANDATORY_OBJECT_MISSING, (short) 0); COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); closeMsg.add(cHdr); closeMsg.add(err); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Error writing close message", unae); } throw new COPSException("Mandatory COPS object missing (PEPId)"); } // Support if ( (cMsg.getClientSI() != null) || (cMsg.getPdpAddress() != null) || (cMsg.getIntegrity() != null)) { // Unsupported objects COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg.getHeader().getClientType()); COPSError err = new COPSError(COPSError.COPS_ERR_UNKNOWN_OBJECT, (short) 0); COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(); closeMsg.add(cHdr); closeMsg.add(err); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Error writing close message", unae); } throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)"); } // Connection accepted COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg.getHeader().getClientType()); COPSKATimer katimer = new COPSKATimer(_kaTimer); COPSAcctTimer acctTimer = new COPSAcctTimer(_acctTimer); COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg(); acceptMsg.add(ahdr); acceptMsg.add(katimer) ; if (_acctTimer != 0) acceptMsg.add(acctTimer); acceptMsg.writeData(conn); COPSPdpConnection pdpConn = new COPSPdpConnection(pepId,conn,_process); pdpConn.setKaTimer(_kaTimer); if (_acctTimer != 0) pdpConn.setAccTimer(_acctTimer); new Thread(pdpConn).start(); _connectionMap.put(pepId.getData().str(),pdpConn); } }