package org.umu.cops.ospdp;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;
import org.umu.cops.common.COPSDebug;
import org.umu.cops.stack.COPSAcctTimer;
import org.umu.cops.stack.COPSClientAcceptMsg;
import org.umu.cops.stack.COPSClientCloseMsg;
import org.umu.cops.stack.COPSClientOpenMsg;
import org.umu.cops.stack.COPSError;
import org.umu.cops.stack.COPSException;
import org.umu.cops.stack.COPSHeader;
import org.umu.cops.stack.COPSKATimer;
import org.umu.cops.stack.COPSMsg;
import org.umu.cops.stack.COPSPepId;
import org.umu.cops.stack.COPSTransceiver;
/**
* Core PDP agent for outsourcing.
*/
public class COPSPdpOSAgent extends Thread {
/** 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 IP
*/
private ServerSocket _serverSocket;
/**
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 Hashtable _connectionMap;
// map < String(PEPID), COPSPdpOSConnection > ConnectionMap;
/**
* Policy data processing object
*/
private COPSPdpOSDataProcess _process;
/**
* Creates a PDP Agent
*
* @param clientType COPS Client-type
* @param process Object to perform policy data processing
*/
public COPSPdpOSAgent(short clientType, COPSPdpOSDataProcess process) {
_serverPort = WELL_KNOWN_PDP_PORT;
_kaTimer = KA_TIMER_VALUE;
_acctTimer = ACCT_TIMER_VALUE;
_clientType = clientType;
_connectionMap = new Hashtable(40);
_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 COPSPdpOSAgent(int port, short clientType, COPSPdpOSDataProcess process) {
_serverPort = port;
_kaTimer = KA_TIMER_VALUE;
_acctTimer = ACCT_TIMER_VALUE;
_clientType = clientType;
_connectionMap = new Hashtable(40);
_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 PEPs connected to this PDP
* @return An Enumeration of all connected PEPs
*/
public Enumeration getConnectedPEPIds() {
return _connectionMap.keys();
}
/**
* Gets the connection map
* @return A Hashtable holding the connection map
*/
public Hashtable getConnectionMap() {
return _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 {
COPSPdpOSConnection pdpConn = (COPSPdpOSConnection) _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();
pdpConn = null;
}
/**
* 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 {
COPSPdpOSConnection pdpConn = (COPSPdpOSConnection) _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 {
_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) {};
}
} catch (Exception e) { // COPSException, IOException
// COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION,
// "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e);
try {
socket.close();
} catch (Exception ex) {};
}
}
} catch (IOException e) {
COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e);
return;
}
}
/**
* 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) {}
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) {}
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) {}
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);
COPSPdpOSConnection pdpConn = new COPSPdpOSConnection(pepId, conn, _process);
pdpConn.setKaTimer(_kaTimer);
if (_acctTimer != 0) pdpConn.setAccTimer(_acctTimer);
new Thread(pdpConn).start();
_connectionMap.put(pepId.getData().str(),pdpConn);
}
}