/* * Copyright (c) 2004 University of Murcia. All rights reserved. * -------------------------------------------------------------- * For more information, please see . */ package org.umu.cops.prpep; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.umu.cops.COPSStateMan; import org.umu.cops.stack.*; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * COPSPepReqStateMan manages Request State using Client Handle (RFC 2748 pag. 21) * in PEP. * * The client handle is used to identify a unique request state for a * single PEP per client-type. Client handles are chosen by the PEP and * are opaque to the PDP. The PDP simply uses the request handle to * uniquely identify the request state for a particular Client-Type over * a particular TCP connection and generically tie its decisions to a * corresponding request. Client handles are initiated in request * messages and are then used by subsequent request, decision, and * report messages to reference the same request state. When the PEP is * ready to remove a local request state, it will issue a delete message * to the PDP for the corresponding client handle. A handle MUST be * explicitly deleted by the PEP before it can be used by the PEP to * identify a new request state. Handles referring to different request * states MUST be unique within the context of a particular TCP * connection and client-type. * * @version COPSPepReqStateMan.java, v 2.00 2004 * */ public class COPSPepReqStateMan extends COPSStateMan { private final static Logger logger = LoggerFactory.getLogger(COPSPepReqStateMan.class); /** The PolicyDataProcess is used to process policy data in the PEP */ protected final COPSPepDataProcess _process; /** The Msg Sender is used to send COPS messages */ private final COPSPepMsgSender _sender; /** * Sync State */ protected transient boolean _syncState; /** * Constructor for this class * @param clientType - the PEP client type * @param clientHandle - the client-handle * @param process - the data processor * @param socket - the socket connection */ public COPSPepReqStateMan(final short clientType, final COPSHandle clientHandle, final COPSPepDataProcess process, final Socket socket) { this(clientType, clientHandle, process, socket, new COPSPepMsgSender(clientType, clientHandle, socket)); } /** * Constructor for sub-classes * @param clientType - the PEP client type * @param clientHandle - the client-handle * @param process - the data processor * @param socket - the socket connection * @param sender - responsible for sending COPS messages to the PEP */ protected COPSPepReqStateMan(final short clientType, final COPSHandle clientHandle, final COPSPepDataProcess process, final Socket socket, final COPSPepMsgSender sender) { super(clientType, clientHandle, socket); this._process = process; _syncState = true; // Inits an object for sending COPS messages to the PDP _sender = sender; } /** * Init Request State * @throws COPSPepException */ public void initRequestState() throws COPSException { // If an object for retrieving PEP features exists, // use it for retrieving them final Map clientSIs; if (_process != null) clientSIs = _process.getClientData(this); else clientSIs = new HashMap<>(); // Send the request // TODO - do we really want to send when this is empty??? _sender.sendRequest(clientSIs); // Initial state _status = Status.ST_INIT; } /** * Finalize Request State * * @throws COPSPepException * */ public void finalizeRequestState() throws COPSException { _sender.sendDeleteRequest(); _status = Status.ST_FINAL; } /** * Process the message Decision * @param dMsg a COPSDecisionMsg * @throws COPSPepException */ protected void processDecision(final COPSDecisionMsg dMsg) throws COPSException { logger.info("Processing decision message - " + dMsg); final Map> decisions = dMsg.getDecisions(); final Map removeDecs = new HashMap<>(); final Map installDecs = new HashMap<>(); for (final Set copsDecisions: decisions.values()) { final COPSDecision cmddecision = copsDecisions.iterator().next(); String prid = ""; switch (cmddecision.getCommand()) { case INSTALL: for (final COPSDecision decision : copsDecisions) { final COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); switch (obj.getSNum()) { case COPSPrObjBase.PR_PRID: prid = obj.getData().str(); break; case COPSPrObjBase.PR_EPD: installDecs.put(prid, obj.getData().str()); break; default: break; } } break; case REMOVE: for (final COPSDecision decision : copsDecisions) { final COPSPrObjBase obj = new COPSPrObjBase(decision.getData().getData()); switch (obj.getSNum()) { case COPSPrObjBase.PR_PRID: prid = obj.getData().str(); break; case COPSPrObjBase.PR_EPD: removeDecs.put(prid, obj.getData().str()); break; default: break; } } break; } } //** Apply decisions to the configuration // TODO - why is this collection never getting populated??? final Map errorDecs = new HashMap<>(); _process.setDecisions(this, removeDecs, installDecs, errorDecs); _status = Status.ST_DECS; if (_process.isFailReport(this)) { logger.info("Sending FAIL report"); _sender.sendFailReport(_process.getReportData(this)); } else { logger.info("Sending SUCCESS report"); _sender.sendSuccessReport(_process.getReportData(this)); } _status = Status.ST_REPORT; if (!_syncState) { _sender.sendSyncComplete(); _syncState = true; _status = Status.ST_SYNCALL; } } /** * Process the message NewRequestState * @throws COPSPepException */ protected void processOpenNewRequestState() throws COPSPepException { if (_process != null) _process.newRequestState(this); _status = Status.ST_NEW; } /** * Process the message DeleteRequestState * @param dMsg a COPSDecisionMsg * @throws COPSPepException */ protected void processDeleteRequestState(final COPSDecisionMsg dMsg) throws COPSPepException { if (_process != null) _process.closeRequestState(this); _status = Status.ST_DEL; } /** * Process the message SycnStateRequest. * The message SycnStateRequest indicates that the remote PDP * wishes the client (which appears in the common header) * to re-send its state. * @param ssMsg a COPSSyncStateMsg * @throws COPSPepException */ protected void processSyncStateRequest(final COPSSyncStateMsg ssMsg) throws COPSException { _syncState = false; // If an object for retrieving PEP features exists, // use it for retrieving them final Map clientSIs; if (_process != null) clientSIs = _process.getClientData(this); else clientSIs = new HashMap<>(); // Send request // TODO - do we really want to send the request when the map is empty??? _sender.sendRequest(clientSIs); _status = Status.ST_SYNC; } public void processClosedConnection(final COPSError error) throws COPSPepException { if (_process != null) _process.notifyClosedConnection(this, error); _status = Status.ST_CCONN; } public void processNoKAConnection() throws COPSException { if (_process != null) _process.notifyNoKAliveReceived(this); _status = Status.ST_NOKA; } /** * Creates and sends an accounting report * @throws COPSException */ public void processAcctReport() throws COPSException { final Map report; if (_process != null) report = _process.getAcctData(this); else report = new HashMap<>(); // TODO - do we really want to send when the map is empty??? _sender.sendAcctReport(report); _status = Status.ST_ACCT; } }