2 * Copyright (c) 2004 University of Murcia. All rights reserved.
3 * --------------------------------------------------------------
4 * For more information, please see <http://www.umu.euro6ix.org/>.
7 package org.umu.cops.prpdp;
9 import org.pcmm.objects.MMVersionInfo;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12 import org.umu.cops.stack.*;
13 import org.umu.cops.stack.COPSError.ErrorTypes;
14 import org.umu.cops.stack.COPSHeader.OPCode;
16 import java.io.IOException;
17 import java.net.InetAddress;
18 import java.net.Socket;
21 * Core PDP agent for managing the connection to one PDP.
23 public class COPSPdpAgent {
25 private static final Logger logger = LoggerFactory.getLogger(COPSPdpAgent.class);
27 /** Well-known port for COPS */
28 public static final int WELL_KNOWN_PDP_PORT = 3288;
29 /** Default keep-alive timer value (secs) */
30 public static final short KA_TIMER_VALUE = 30;
31 /** Default accounting timer value (secs) */
32 public static final short ACCT_TIMER_VALUE = 0;
37 protected final String _host;
42 protected final int _serverPort;
45 * Client-type of connecting PEP
47 protected final short _clientType;
50 * Accounting timer (secs)
52 protected final short _acctTimer;
55 * Keep-alive timer (secs)
57 protected final short _kaTimer;
60 * Policy data processing object
62 protected final COPSPdpDataProcess _process;
64 // Next two attributes are initialized when connected
66 * The Socket connection to the PEP
68 protected transient Socket _socket;
73 protected transient COPSHandle _handle;
75 // Next three attributes are initialized after the client accepts
77 * Holds the last PEP ID processed
79 protected transient COPSPepId _pepId;
82 * the PDP connection connection
84 protected transient COPSPdpConnection _pdpConn;
87 * The handle to the tread accepting messages from the PDP
89 protected transient Thread _thread;
94 * @param host PDP agent host name
95 * @param port Port to listen to
96 * @param clientType COPS Client-type
97 * @param process Object to perform policy data processing
99 public COPSPdpAgent(final String host, final int port, final short clientType, final COPSPdpDataProcess process) {
101 this._serverPort = port;
103 this._kaTimer = KA_TIMER_VALUE;
104 this._acctTimer = ACCT_TIMER_VALUE;
106 this._clientType = clientType;
107 this._process = process;
111 * Returns handle after connect() has successfully been executed
112 * @return - the handle
114 public COPSHandle getClientHandle() {
119 * Returns handle after connect() has successfully been executed
120 * @return - the handle
122 public Socket getSocket() {
128 * @throws java.net.UnknownHostException
129 * @throws java.io.IOException
130 * @throws COPSException
132 public void connect() throws IOException, COPSException {
133 // Create Socket and send OPN
134 final InetAddress addr = InetAddress.getByName(_host);
135 _socket = new Socket(addr, _serverPort);
136 logger.info("PDP Socket Opened. Waiting to receive client-open message");
137 final COPSMsg msg = COPSTransceiver.receiveMsg(_socket);
138 logger.debug("Message received of type - " + msg.getHeader().getOpCode());
139 if (msg.getHeader().getOpCode().equals(OPCode.OPN)) {
140 handleClientOpenMsg(_socket, msg);
144 } catch (Exception ex) {
145 logger.error("Unexpected error closing socket", ex);
151 * Disconnects a PEP and stops the listener thread
152 * @param error COPS Error to be reported as a reason
154 public void disconnect(final COPSError error) {
155 if (_pdpConn != null) {
156 sendCloseMessage(_socket, error.getErrCode(), error.getErrSubCode(), "Disconnecting from PDP requested");
159 logger.warn("Unable to locate PDP connection. Cannot close");
161 if (_thread != null) _thread.interrupt();
162 else logger.warn("Unable to locate PDP connection thread. Cannot stop it.");
164 if (_socket.isConnected())
167 } catch (IOException e) {
168 logger.error("Error closing socket", e);
178 * Requests a COPS sync for a PEP
179 * @throws COPSException
180 * @throws COPSPdpException
182 public void sync() throws COPSException {
183 if (_pdpConn != null) _pdpConn.syncAllRequestState();
184 else logger.warn("Unable to sync, not connected to a PEP");
188 * Handles a COPS client-open message and sets the _pepId, _handle, _pdpConn, & _thread objects in the process
189 * as well as starts the PDP connection thread for receiving other COPS messages from the PDP
190 * @param conn Socket to the PEP
191 * @param msg <tt>COPSMsg</tt> holding the client-open message
192 * @throws COPSException
193 * @throws IOException
195 protected void handleClientOpenMsg(final Socket conn, final COPSMsg msg) throws COPSException, IOException {
196 logger.info("Processing client open message");
198 if (_pepId != null) {
199 throw new COPSException("Connection already opened");
202 final COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
203 _pepId = cMsg.getPepId();
205 // Validate Client Type
206 if (msg.getHeader().getClientType() != _clientType) {
207 sendCloseMessage(conn, ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA,
208 "Unsupported client type");
211 // PEPId is mandatory
212 if (_pepId == null) {
213 sendCloseMessage(conn, ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA,
214 "Mandatory COPS object missing (PEPId)");
217 // TODO - Determine if I should be checking for the PDPAddress and Integrity objects on the message too???
220 if ( (cMsg.getClientSI() != null) || (cMsg.getPdpAddress() != null) || (cMsg.getIntegrity() != null)) {
221 sendCloseMessage(conn, ErrorTypes.UNSUPPORTED_CLIENT_TYPE,
222 "Unsupported objects (ClientSI, PdpAddress, Integrity)");
226 if ((cMsg.getClientSI() == null) ) {
227 sendCloseMessage(conn, ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA,
228 "Unsupported objects (PdpAddress, Integrity)");
230 final MMVersionInfo _mminfo = new MMVersionInfo(cMsg.getClientSI().getData().getData());
231 logger.debug("CMTS sent MMVersion info : major:" + _mminfo.getMajorVersionNB() + " minor:" +
232 _mminfo.getMinorVersionNB());
235 acceptConnection(conn);
237 _handle = handleAcceptResponse(conn);
238 if (_handle != null) {
239 // Connection accepted
240 _pdpConn = setputPdpConnection(conn, _handle);
241 _thread = new Thread(_pdpConn, "PDP Agent for PEP ID " + _pepId.getData().str());
244 throw new COPSException("Unable to connect to PDP");
249 * Creates and sends a client close message
250 * @param conn - the socket connection
251 * @param errorType - the error type to send
252 * @param msg - the error message to log
254 private void sendCloseMessage(final Socket conn, final ErrorTypes errorType, final ErrorTypes errorSubType,
256 final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType,
257 new COPSError(errorType, errorSubType), null, null);
259 logger.info("Sending client-close message. Reason: " + msg);
260 closeMsg.writeData(conn);
261 } catch (IOException unae) {
262 logger.error("Exception writing data", unae);
267 * Sends a client-accept message back to the PDP
268 * @param conn - the socket connection to the PDP
269 * @throws IOException
271 private void acceptConnection(final Socket conn) throws IOException {
272 final COPSClientAcceptMsg acceptMsg;
274 acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer),
275 new COPSAcctTimer(_acctTimer), null);
277 acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer) ,null, null);
278 acceptMsg.writeData(conn);
282 * Waits for the response back from the PDP and handles it appropriately. When successful, the handle to the
283 * client is returned.
284 * @param conn - the socket connection to the PDP
285 * @return - the handle or null if not successful
287 private COPSHandle handleAcceptResponse(final Socket conn) {
289 logger.debug("handleClientOpenMsg() - Waiting to receive message");
290 final COPSMsg rmsg = COPSTransceiver.receiveMsg(conn);
291 logger.debug("Received message of type - " + rmsg.getHeader().getOpCode());
293 if (rmsg.getHeader().getOpCode().equals(OPCode.CC)) {
294 logger.info("Received client-close message");
295 sendCloseMessage(conn, ErrorTypes.SHUTTING_DOWN, ErrorTypes.NA, "Received client-close message");
299 if (rmsg.getHeader().getOpCode().equals(OPCode.REQ)) {
300 final COPSReqMsg rMsg = (COPSReqMsg) rmsg;
301 return rMsg.getClientHandle();
303 sendCloseMessage(conn, ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA, "Received unknown object");
307 } catch (Exception e) {
308 logger.error("Error COPSTransceiver.receiveMsg", e);
314 * Creates the PDP connection object
315 * @param conn - the socket connection to the PDP
316 * @param handle - the client's handle
317 * @return - the PDP connection object
319 protected COPSPdpConnection setputPdpConnection(final Socket conn, final COPSHandle handle) {
320 logger.debug("PDPCOPSConnection");
321 final COPSPdpConnection pdpConn = new COPSPdpConnection(_pepId, conn, _process, _kaTimer, _acctTimer);
323 // XXX - handleRequestMsg
324 // XXX - check handle is valid
325 final COPSPdpReqStateMan man = new COPSPdpReqStateMan(_clientType, handle, _process, conn);
326 pdpConn.addStateMan(handle, man);
327 // XXX - End handleRequestMsg
329 logger.info("Starting PDP connection thread to - " + _host);