package org.umu.cops.ospdp; import java.io.IOException; import java.net.Socket; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import org.umu.cops.common.COPSDebug; import org.umu.cops.stack.COPSClientCloseMsg; import org.umu.cops.stack.COPSContext; import org.umu.cops.stack.COPSDeleteMsg; import org.umu.cops.stack.COPSError; import org.umu.cops.stack.COPSException; import org.umu.cops.stack.COPSHeader; import org.umu.cops.stack.COPSKAMsg; import org.umu.cops.stack.COPSMsg; import org.umu.cops.stack.COPSPepId; import org.umu.cops.stack.COPSReportMsg; import org.umu.cops.stack.COPSReqMsg; import org.umu.cops.stack.COPSSyncStateMsg; import org.umu.cops.stack.COPSTransceiver; /** * Class for managing an outsourcing connection at the PDP side. */ public class COPSPdpOSConnection implements Runnable { /** Socket connected to PEP */ private Socket _sock; /** PEP identifier */ private COPSPepId _pepId; /** Time of the latest keep-alive sent */ private Date _lastKa; /** Opcode of the latest message sent */ private byte _lastmessage; /** * Time of the latest keep-alive received */ protected Date _lastRecKa; /** Maps a Client Handle to a Handler */ protected Hashtable _managerMap; // map < String(COPSHandle), COPSPdpHandler> HandlerMap; /** * PDP policy data processor class */ protected COPSPdpOSDataProcess _process; /** Accounting timer value (secs) */ protected short _acctTimer; /** Keep-alive timer value (secs) */ protected short _kaTimer; /** COPS error returned by PEP */ protected COPSError _error; /** * Creates a new PDP connection * * @param pepId PEP-ID of the connected PEP * @param sock Socket connected to PEP * @param process Object for processing policy data */ public COPSPdpOSConnection(COPSPepId pepId, Socket sock, COPSPdpOSDataProcess process) { _sock = sock; _pepId = pepId; _lastKa = new Date(); _lastmessage = COPSHeader.COPS_OP_OPN; _managerMap = new Hashtable(20); _kaTimer = 0; _process = process; } /** * Gets the time of that latest keep-alive sent * @return Time of that latest keep-alive sent */ public Date getLastKAlive() { return _lastKa; } /** * Sets the keep-alive timer value * @param kaTimer Keep-alive timer value (secs) */ public void setKaTimer(short kaTimer) { _kaTimer = kaTimer; } /** * Gets the keep-alive timer value * @return Keep-alive timer value (secs) */ public short getKaTimer() { return _kaTimer; } /** * Sets the accounting timer value * @param acctTimer Accounting timer value (secs) */ public void setAccTimer(short acctTimer) { _acctTimer = acctTimer; } /** * Gets the accounting timer value * @return Accounting timer value (secs) */ public short getAcctTimer() { return _acctTimer; } /** * Gets the latest COPS message * @return Code of the latest message sent */ public byte getLastMessage() { return _lastmessage; } /** * Gets active handles * @return An Enumeration holding all active handles */ public Enumeration getHandles() { return _managerMap.keys(); } /** * Gets the handle map * @return A Hashtable holding the handle map */ public Hashtable getReqStateMans() { return _managerMap; } /** * Gets the PEP-ID * @return The ID of the PEP, as a String */ public String getPepId() { return _pepId.getData().str(); } /** * Checks whether the socket to the PEP is closed or not * @return true if closed, false otherwise */ public boolean isClosed() { return _sock.isClosed(); } /** * Closes the socket to the PEP * @throws IOException */ protected void close() throws IOException { _sock.close(); } /** * Gets the socket to the PEP * @return Socket connected to the PEP */ public Socket getSocket() { return _sock; } /** * Main loop */ public void run () { Date _lastSendKa = new Date(); _lastRecKa = new Date(); try { while (!_sock.isClosed()) { if (_sock.getInputStream().available() != 0) { _lastmessage = processMessage(_sock); _lastRecKa = new Date(); } // Keep Alive if (_kaTimer > 0) { // Timeout at PDP int _startTime = (int) (_lastRecKa.getTime()); int cTime = (int) (new Date().getTime()); if ((int)(cTime - _startTime) > _kaTimer*1000) { _sock.close(); // Notify all Request State Managers notifyNoKAAllReqStateMan(); } // Send to PEP _startTime = (int) (_lastSendKa.getTime()); cTime = (int) (new Date().getTime()); if ((int)(cTime - _startTime) > ((_kaTimer*3/4)*1000)) { COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA); COPSKAMsg msg = new COPSKAMsg(); msg.add(hdr); COPSTransceiver.sendMsg(msg, _sock); _lastSendKa = new Date(); } } try { Thread.sleep(500); } catch (Exception e) {}; } } catch (Exception e) { e.printStackTrace(); COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e); } // connection closed by server // COPSDebug.out(getClass().getName(),"Connection closed by client"); try { _sock.close(); } catch (IOException e) {}; // Notify all Request State Managers try { notifyCloseAllReqStateMan(); } catch (COPSPdpException e) {}; } /** * Gets a COPS message from the socket and processes it * @param conn Socket connected to the PEP * @return Type of COPS message */ private byte processMessage(Socket conn) throws COPSPdpException, COPSException, IOException { COPSMsg msg = COPSTransceiver.receiveMsg(conn); if (msg.getHeader().isAClientClose()) { handleClientCloseMsg(conn, msg); return COPSHeader.COPS_OP_CC; } else if (msg.getHeader().isAKeepAlive()) { handleKeepAliveMsg(conn, msg); return COPSHeader.COPS_OP_KA; } else if (msg.getHeader().isARequest()) { handleRequestMsg(conn, msg); return COPSHeader.COPS_OP_REQ; } else if (msg.getHeader().isAReport()) { handleReportMsg(conn, msg); return COPSHeader.COPS_OP_RPT; } else if (msg.getHeader().isADeleteReq()) { handleDeleteRequestMsg(conn, msg); return COPSHeader.COPS_OP_DRQ; } else if (msg.getHeader().isASyncComplete()) { handleSyncComplete(conn, msg); return COPSHeader.COPS_OP_SSC; } else { throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ")."); } } /** * Handle Client Close Message, close the passed connection * * @param conn a Socket * @param msg a COPSMsg * * * ::= * * [] * * Not support [] * */ private void handleClientCloseMsg(Socket conn, COPSMsg msg) { COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg; _error = cMsg.getError(); // COPSDebug.out(getClass().getName(),"Got close request, closing connection " + // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]"); try { // Support if (cMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } conn.close(); } catch (Exception unae) { }; } /** * Gets the occurred COPS Error * @return COPSError object */ protected COPSError getError() { return _error; } /** * Handle Keep Alive Message * * ::= * [] * * Not support [] * * @param conn a Socket * @param msg a COPSMsg * */ private void handleKeepAliveMsg(Socket conn, COPSMsg msg) { COPSKAMsg cMsg = (COPSKAMsg) msg; COPSKAMsg kaMsg = (COPSKAMsg) msg; try { // Support if (cMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } kaMsg.writeData(conn); } catch (Exception unae) { }; } /** * Handle Delete Request Message * * ::= * * * [] * * Not support [] * * @param conn a Socket * @param msg a COPSMsg * */ private void handleDeleteRequestMsg(Socket conn, COPSMsg msg) throws COPSPdpException { COPSDeleteMsg cMsg = (COPSDeleteMsg) msg; // COPSDebug.out(getClass().getName(),"Removing ClientHandle for " + // conn.getInetAddress() + ":" + conn.getPort() + ":[Reason " + cMsg.getReason().getDescription() + "]"); // Support if (cMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } // Delete clientHandler if (_managerMap.remove(cMsg.getClientHandle().getId().str()) == null) { // COPSDebug.out(getClass().getName(),"Missing for ClientHandle " + // cMsg.getClientHandle().getId().getData()); } COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); if (man == null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); } else { man.processDeleteRequestState(cMsg); } } /** * Handle Request Message * * ::= * * * *() * [] * ::= <*( )> * * Not support [] * * @param conn a Socket * @param msg a COPSMsg * */ private void handleRequestMsg(Socket conn, COPSMsg msg) throws COPSPdpException { COPSReqMsg reqMsg = (COPSReqMsg) msg; COPSContext cntxt = reqMsg.getContext(); COPSHeader header = reqMsg.getHeader(); //short reqType = cntxt.getRequestType(); short cType = header.getClientType(); // Support if (reqMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } COPSPdpOSReqStateMan man; man = (COPSPdpOSReqStateMan) _managerMap.get(reqMsg.getClientHandle().getId().str()); if (man == null) { man = new COPSPdpOSReqStateMan(cType, reqMsg.getClientHandle().getId().str()); _managerMap.put(reqMsg.getClientHandle().getId().str(),man); man.setDataProcess(_process); man.initRequestState(_sock); // COPSDebug.out(getClass().getName(),"createHandler called, clientType=" + // header.getClientType() + " msgType=" + // cntxt.getMessageType() + ", connId=" + conn.toString()); } man.processRequest(reqMsg); } /** * Handle Report Message * * ::= * * * *() * [] * * Not support [] * * @param conn a Socket * @param msg a COPSMsg * */ private void handleReportMsg(Socket conn, COPSMsg msg) throws COPSPdpException { COPSReportMsg repMsg = (COPSReportMsg) msg; // COPSHandle handle = repMsg.getClientHandle(); // COPSHeader header = repMsg.getHeader(); // Support if (repMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(repMsg.getClientHandle().getId().str()); if (man == null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); } else { man.processReport(repMsg); } } /** * Method handleSyncComplete * * @param conn a Socket * @param msg a COPSMsg * */ private void handleSyncComplete(Socket conn, COPSMsg msg) throws COPSPdpException { COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg; // COPSHandle handle = cMsg.getClientHandle(); // COPSHeader header = cMsg.getHeader(); // Support if (cMsg.getIntegrity() != null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED, "Unsupported objects (Integrity) to connection " + conn.getInetAddress()); } COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str()); if (man == null) { COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG); } else { man.processSyncComplete(cMsg); } } /** * Requests a COPS sync from the PEP * @throws COPSException * @throws COPSPdpException */ protected void syncAllRequestState() throws COPSException, COPSPdpException { if (_managerMap.size() > 0) { for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { String handle = (String) e.nextElement(); COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); man.syncRequestState(); } } } private void notifyCloseAllReqStateMan() throws COPSPdpException { if (_managerMap.size() > 0) { for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { String handle = (String) e.nextElement(); COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); man.processClosedConnection(_error); } } } private void notifyNoKAAllReqStateMan() throws COPSPdpException { if (_managerMap.size() > 0) { for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) { String handle = (String) e.nextElement(); COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle); man.processNoKAConnection(); } } } }