/**
@header@
*/
package org.pcmm;
import org.pcmm.objects.MMVersionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.umu.cops.prpdp.COPSPdpAgent;
import org.umu.cops.prpdp.COPSPdpException;
import org.umu.cops.stack.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
/**
* Core PDP agent for provisioning
*/
public class PCMMPdpAgent extends COPSPdpAgent {
public final static Logger logger = LoggerFactory.getLogger(PCMMPdpAgent.class);
/** Well-known port for PCMM */
public static final int WELL_KNOWN_PDP_PORT = 3918;
private COPSPepId _pepId;
private String _pepIdString;
/**
* PEP host name
*/
private String psHost;
/**
* PEP port
*/
private int psPort;
private Socket socket;
/**
* Policy data processing object
*/
private PCMMPdpDataProcess _process;
private MMVersionInfo _mminfo;
private COPSHandle _handle;
private short _transactionID;
/**
* Creates a PDP Agent
*
* @param clientType
* COPS Client-type
* @param process
* Object to perform policy data processing
*/
public PCMMPdpAgent(short clientType, PCMMPdpDataProcess process) {
this(clientType, null, WELL_KNOWN_PDP_PORT, process);
}
/**
* Creates a PDP Agent
*
* @param clientType
* COPS Client-type
* @param psHost
* Host to connect to
* @param psPort
* Port to connect to
* @param process
* Object to perform policy data processing
*/
public PCMMPdpAgent(short clientType, String psHost, int psPort, PCMMPdpDataProcess process) {
super(psPort, clientType, null);
this._process = process;
this.psHost = psHost;
}
/**
* XXX -tek- This is the retooled connect. Not sure if the while forever
* loop is needed. Socket accept --> handleClientOpenMsg --> pdpConn.run()
*
* Below is new Thread(pdpConn).start(); Does that do it?
*
*/
/**
* Connects to a PDP
*
* @param psHost
* CMTS host name
* @param psPort
* CMTS port
* @return true if PDP accepts the connection; false
* otherwise
* @throws java.net.UnknownHostException
* @throws java.io.IOException
* @throws COPSException
* @throws COPSPdpException
*/
public boolean connect(String psHost, int psPort) throws IOException, COPSException, COPSPdpException {
this.psHost = psHost;
this.psPort = psPort;
// Create Socket and send OPN
InetAddress addr = InetAddress.getByName(psHost);
try {
socket = new Socket(addr, psPort);
} catch (IOException e) {
logger.error("Error creating socket connection", e);
return (false);
}
logger.info("PDP Socket Opened");
// Loop through for Incoming messages
// server infinite loop
// while(true)
{
// We're waiting for an message
try {
logger.info("PDP COPSTransceiver.receiveMsg");
COPSMsg msg = COPSTransceiver.receiveMsg(socket);
if (msg.getHeader().isAClientOpen()) {
logger.info("PDP msg.getHeader().isAClientOpen");
handleClientOpenMsg(socket, msg);
} else {
try {
socket.close();
} catch (Exception ex) {
logger.error("Unexpected exception closing socket", ex);
}
}
} catch (Exception e) { // COPSException, IOException
try {
socket.close();
} catch (Exception ex) {
logger.error("Unexpected exception closing socket", ex);
}
return true;
}
}
return false;
}
/**
* 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() != getClientType()) {
// 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("Unexpected 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("Unexpected error writing COPS data", unae);
}
throw new COPSException("Mandatory COPS object missing (PEPId)");
}
setPepId(pepId);
// Support
if ((cMsg.getClientSI() != null) ) {
_mminfo = new MMVersionInfo(cMsg
.getClientSI().getData().getData());
logger.info("CMTS sent MMVersion info : major:"
+ _mminfo.getMajorVersionNB() + " minor:"
+ _mminfo.getMinorVersionNB());
} else {
// 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("Unexpected error writing COPS data", unae);
}
throw new COPSException("Unsupported objects (PdpAddress, Integrity)");
}
/*
*/
// Connection accepted
COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg
.getHeader().getClientType());
COPSKATimer katimer = new COPSKATimer(getKaTimer());
COPSAcctTimer acctTimer = new COPSAcctTimer(getAcctTimer());
COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg();
acceptMsg.add(ahdr);
acceptMsg.add(katimer);
if (getAcctTimer() != 0)
acceptMsg.add(acctTimer);
acceptMsg.writeData(conn);
// XXX - handleRequestMsg
try {
logger.info("PDP COPSTransceiver.receiveMsg");
COPSMsg rmsg = COPSTransceiver.receiveMsg(socket);
// Client-Close
if (rmsg.getHeader().isAClientClose()) {
logger.info("Client close description - " + ((COPSClientCloseMsg) rmsg).getError().getDescription());
// close the socket
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("Unexpected exception writing COPS data", unae);
}
throw new COPSException("CMTS requetsed Client-Close");
} else {
// Request
if (rmsg.getHeader().isARequest()) {
COPSReqMsg rMsg = (COPSReqMsg) rmsg;
_handle = rMsg.getClientHandle();
} else
throw new COPSException("Can't understand request");
}
} catch (Exception e) { // COPSException, IOException
throw new COPSException("Error COPSTransceiver.receiveMsg");
}
logger.info("PDPCOPSConnection");
PCMMPdpConnection pdpConn = new PCMMPdpConnection(pepId, conn, _process);
pdpConn.setKaTimer(getKaTimer());
if (getAcctTimer() != 0)
pdpConn.setAccTimer(getAcctTimer());
// XXX - handleRequestMsg
// XXX - check handle is valid
PCMMPdpReqStateMan man = new PCMMPdpReqStateMan(getClientType(), _handle.getId().str());
pdpConn.getReqStateMans().put(_handle.getId().str(),man);
man.setDataProcess(_process);
try {
man.initRequestState(conn);
} catch (COPSPdpException unae) {
logger.error("Error initializing the state manager's request state");
}
// XXX - End handleRequestMsg
logger.info("PDP Thread(pdpConn).start");
new Thread(pdpConn).start();
getConnectionMap().put(pepId.getData().str(), pdpConn);
}
/**
* @return the _psHost
*/
public String getPsHost() {
return psHost;
}
/**
* TODO - make the host immutable
* @param _psHost
* the _psHost to set
*/
@Deprecated
public void setPsHost(String _psHost) {
this.psHost = _psHost;
}
/**
* @return the _psPort
*/
public int getPsPort() {
return psPort;
}
/**
* TODO - make the port immutable
* @param _psPort
* the _psPort to set
*/
@Deprecated
public void setPsPort(int _psPort) {
this.psPort = _psPort;
}
/**
* @return the socket
*/
public Socket getSocket() {
return socket;
}
/**
* TODO - Ensure socket is not overly transient
* @param socket
* the socket to set
*/
@Deprecated
public void setSocket(Socket socket) {
this.socket = socket;
}
/**
* @return the _process
*/
public PCMMPdpDataProcess getProcess() {
return _process;
}
/**
* @param _process
* the _process to set
*/
public void setProcess(PCMMPdpDataProcess _process) {
this._process = _process;
}
/**
* Gets the client handle
* @return Client's COPSHandle
*/
public COPSHandle getClientHandle() {
return _handle;
}
/**
* Gets the PepId
* @return COPSPepId
*/
public COPSPepId getPepId() {
return _pepId;
}
public String getPepIdString() {
return _pepIdString;
}
/**
* Sets the PepId
* TODO - make PEP ID and the associate string immutable or remove altogether
* @param pepId - COPSPepId
*/
@Deprecated
public void setPepId(COPSPepId pepId) {
_pepId = pepId;
_pepIdString = pepId.getData().str();
}
/*
* (non-Javadoc)
*
* @see org.pcmm.rcd.IPCMMClient#isConnected()
*/
public boolean isConnected() {
return socket != null && socket.isConnected();
}
}