/* * 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 org.umu.cops.stack.COPSError.ErrorTypes; import org.umu.cops.stack.COPSHeader.OPCode; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Core PDP agent for provisioning */ public class COPSPdpAgent extends Thread { private static final 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; /** * The PEP ID */ protected transient COPSPepId _pepId; /** * Maps a PEP-ID to a connection * TODO - Refactor COPSPdpConnection to extend PCMMPdpConnection. Until then, the value must remain an Object */ protected Map _connectionMap; // map < String(PEPID), COPSPdpConnection > ConnectionMap; /** * Policy data processing object */ private COPSPdpDataProcess _process; /** * Holds all of the threads to manage by PEP ID */ protected final Map threadMap; /** * 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(final int port, final short clientType, final COPSPdpDataProcess process) { _serverPort = port; _kaTimer = KA_TIMER_VALUE; _acctTimer = ACCT_TIMER_VALUE; _clientType = clientType; _connectionMap = new ConcurrentHashMap<>(); _process = process; this.threadMap = new ConcurrentHashMap<>(); } /** * 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 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(final String pepID, final COPSError error) throws COPSException, IOException { final COPSPdpConnection pdpConn = (COPSPdpConnection)_connectionMap.get(pepID); final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType, error, null, null); 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(final String pepID) throws COPSException, COPSPdpException { COPSPdpConnection pdpConn = (COPSPdpConnection) _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(final 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 final Socket socket = serverSocket.accept(); // COPSDebug.out(getClass().getName(),"New connection accepted " + // socket.getInetAddress() + // ":" + socket.getPort()); // We're waiting for an OPN message try { final COPSMsg msg = COPSTransceiver.receiveMsg(socket); logger.info("Message received - " + msg); if (msg.getHeader().getOpCode().equals(OPCode.OPN)) { handleClientOpenMsg(socket, msg); } else { logger.error("Not an open message, closing socket"); try { socket.close(); } catch (Exception ex) { logger.error("Unexpected exception 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("Unexpected exception 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 * TODO - Refactor PCMMPdpAgent#handleClientOpenMsg() as it contains much of this same logic */ protected void handleClientOpenMsg(final Socket conn, final COPSMsg msg) throws COPSException, IOException { final COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg; _pepId = cMsg.getPepId(); // Validate Client Type if (msg.getHeader().getClientType() != _clientType) { // Unsupported client type final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType, new COPSError(ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA), null, null); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Unexpected exception writing data", unae); } throw new COPSException("Unsupported client type"); } // PEPId is mandatory if (_pepId == null) { // Mandatory COPS object missing final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType, new COPSError(ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA), null, null); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Unexpected exception writing data", unae); } throw new COPSException("Mandatory COPS object missing (PEPId)"); } // Support if ( (cMsg.getClientSI() != null) || (cMsg.getPdpAddress() != null) || (cMsg.getIntegrity() != null)) { // Unsupported objects final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType, new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null); try { closeMsg.writeData(conn); } catch (IOException unae) { logger.error("Exception writing data", unae); } throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)"); } // Connection accepted final COPSClientAcceptMsg acceptMsg; if (_acctTimer != 0) acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer), new COPSAcctTimer(_acctTimer), null); else acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer),null, null); acceptMsg.writeData(conn); final 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); } }