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.prpep;
9 import java.io.IOException;
10 import java.net.Socket;
11 import java.util.Date;
12 import java.util.Enumeration;
13 import java.util.Hashtable;
14 import java.util.Vector;
16 import org.umu.cops.common.COPSDebug;
17 import org.umu.cops.stack.COPSClientCloseMsg;
18 import org.umu.cops.stack.COPSContext;
19 import org.umu.cops.stack.COPSDecision;
20 import org.umu.cops.stack.COPSDecisionMsg;
21 import org.umu.cops.stack.COPSError;
22 import org.umu.cops.stack.COPSException;
23 import org.umu.cops.stack.COPSHandle;
24 import org.umu.cops.stack.COPSHeader;
25 import org.umu.cops.stack.COPSKAMsg;
26 import org.umu.cops.stack.COPSMsg;
27 import org.umu.cops.stack.COPSSyncStateMsg;
28 import org.umu.cops.stack.COPSTransceiver;
31 * COPSPepConnection represents a PEP-PDP Connection Manager.
32 * Responsible for processing messages received from PDP.
34 public class COPSPepConnection implements Runnable {
36 /** Socket connected to PDP */
37 protected Socket _sock;
39 /** Time to wait responses (milliseconds), default is 10 seconds */
40 protected int _responseTime;
42 /** COPS Client-type */
43 protected short _clientType;
46 Accounting timer value (secs)
48 protected short _acctTimer;
51 Keep-alive timer value (secs)
53 protected short _kaTimer;
56 * Time of the latest keep-alive received
58 protected Date _lastRecKa;
61 Opcode of the latest message sent
63 protected byte _lastmessage;
66 Maps a COPS Client Handle to a Request State Manager
68 protected Hashtable _managerMap;
69 // map < String(COPSHandle), COPSPepReqStateMan>;
72 COPS error returned by PDP
74 protected COPSError _error;
77 * Creates a new PEP connection
78 * @param clientType PEP's client-type
79 * @param sock Socket connected to PDP
81 public COPSPepConnection(short clientType, Socket sock) {
83 _clientType = clientType;
89 _responseTime = 10000;
90 _lastmessage = COPSHeader.COPS_OP_CAT;
92 _managerMap = new Hashtable(20);
96 * Gets the response time
97 * @return Response time value (msecs)
99 public int getResponseTime() {
100 return _responseTime;
104 * Gets the socket connected to the PDP
105 * @return Socket connected to PDP
107 public Socket getSocket() {
112 * Gets keep-alive timer
113 * @return Keep-alive timer value (secs)
115 public short getKaTimer () {
120 * Gets accounting timer
121 * @return Accounting timer value (secs)
123 public short getAcctTimer () {
128 * Gets active COPS handles
129 * @return An <tt>Enumeration</tt> holding all active handles
131 protected Enumeration getHandles() {
132 return _managerMap.keys();
136 * Gets all request state managers
137 * @return A <tt>Hashatable</tt> holding all request state managers
139 protected Hashtable getReqStateMans() {
144 * Checks whether the socket to the PDP is closed or not
145 * @return <tt>true</tt> if the socket is closed, <tt>false</tt> otherwise
147 public boolean isClosed() {
148 return _sock.isClosed();
154 * @throws java.io.IOException
156 protected void close()
162 * Gets the opcode of the lastest message sent
163 * @return Message opcode
165 public byte getLastmessage() {
171 * @param respTime Response time value (msecs)
173 public void setResponseTime(int respTime) {
174 _responseTime = respTime;
178 * Sets keep-alive timer
179 * @param kaTimer Keep-alive timer value (secs)
181 public void setKaTimer (short kaTimer) {
186 * Sets accounting timer
187 * @param acctTimer Accounting timer value (secs)
189 public void setAcctTimer (short acctTimer) {
190 _acctTimer = acctTimer;
194 * Message-processing loop
197 Date _lastSendKa = new Date();
198 Date _lastSendAcc = new Date();
199 _lastRecKa = new Date();
201 while (!_sock.isClosed()) {
202 if (_sock.getInputStream().available() != 0) {
203 _lastmessage = processMessage(_sock);
204 _lastRecKa = new Date();
210 int _startTime = (int) (_lastRecKa.getTime());
211 int cTime = (int) (new Date().getTime());
213 if ((int)(cTime - _startTime) > _kaTimer*1000) {
215 // Notify all Request State Managers
216 notifyNoKAAllReqStateMan();
220 _startTime = (int) (_lastSendKa.getTime());
221 cTime = (int) (new Date().getTime());
223 if ((int)(cTime - _startTime) > ((_kaTimer*3/4) * 1000)) {
224 COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA);
225 COPSKAMsg msg = new COPSKAMsg();
229 COPSTransceiver.sendMsg(msg, _sock);
230 _lastSendKa = new Date();
235 if (_acctTimer > 0) {
236 int _startTime = (int) (_lastSendAcc.getTime());
237 int cTime = (int) (new Date().getTime());
239 if ((int)(cTime - _startTime) > ((_acctTimer*3/4)*1000)) {
240 // Notify all Request State Managers
241 notifyAcctAllReqStateMan();
242 _lastSendAcc = new Date();
248 } catch (Exception e) {};
250 } catch (Exception e) {
251 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_SOCKET, e);
254 // connection closed by server
255 // COPSDebug.out(getClass().getName(),"Connection closed by server");
258 } catch (IOException e) {};
260 // Notify all Request State Managers
262 notifyCloseAllReqStateMan();
263 } catch (COPSPepException e) {};
267 * Gets a COPS message from the socket and processes it
268 * @param conn Socket connected to the PDP
269 * @return COPS message type
270 * @throws COPSPepException
271 * @throws COPSException
272 * @throws IOException
274 protected byte processMessage(Socket conn)
275 throws COPSPepException, COPSException, IOException {
276 COPSMsg msg = COPSTransceiver.receiveMsg(conn);
278 if (msg.getHeader().isAClientClose()) {
279 handleClientCloseMsg(conn, msg);
280 return COPSHeader.COPS_OP_CC;
281 } else if (msg.getHeader().isADecision()) {
282 handleDecisionMsg(conn, msg);
283 return COPSHeader.COPS_OP_DEC;
284 } else if (msg.getHeader().isASyncStateReq()) {
285 handleSyncStateReqMsg(conn, msg);
286 return COPSHeader.COPS_OP_SSQ;
287 } else if (msg.getHeader().isAKeepAlive()) {
288 handleKeepAliveMsg(conn, msg);
289 return COPSHeader.COPS_OP_KA;
291 throw new COPSPepException("Message not expected (" + msg.getHeader().getOpCode() + ").");
296 * Handle Client Close Message, close the passed connection
298 * @param conn a Socket
299 * @param msg a COPSMsg
302 * <Client-Close> ::= <Common Header>
306 * Not support [<Integrity>]
309 private void handleClientCloseMsg(Socket conn, COPSMsg msg) {
310 COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg;
311 _error = cMsg.getError();
313 // COPSDebug.out(getClass().getName(),"Got close request, closing connection " +
314 // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]");
318 if (cMsg.getIntegrity() != null) {
319 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED,
320 "Unsupported objects (Integrity) to connection " + conn.getInetAddress());
324 } catch (Exception unae) { };
330 * @return a COPSError
333 protected COPSError getError() {
338 * Handle Keep Alive Message
340 * <Keep-Alive> ::= <Common Header>
343 * Not support [<Integrity>]
345 * @param conn a Socket
346 * @param msg a COPSMsg
349 private void handleKeepAliveMsg(Socket conn, COPSMsg msg) {
350 COPSKAMsg cMsg = (COPSKAMsg) msg;
352 // COPSDebug.out(getClass().getName(),"Get KAlive Msg");
356 if (cMsg.getIntegrity() != null) {
357 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED,
358 "Unsupported objects (Integrity) to connection " + conn.getInetAddress());
361 // should we do anything else?? ....
363 } catch (Exception unae) { };
367 * Method handleDecisionMsg
369 * <Decision Message> ::= <Common Header: Flag SOLICITED>
371 * *(<Decision>) | <Error>
373 * <Decision> ::= <Context>
375 * [<Named Decision Data: Provisioning>]
376 * <Decision: Flags> ::= <Command-Code> NULLFlag
377 * <Command-Code> ::= NULLDecision | Install | Remove
378 * <Named Decision Data> ::= <<Install Decision> | <Remove Decision>>
379 * <Install Decision> ::= *(<PRID> <EPD>)
380 * <Remove Decision> ::= *(<PRID> | <PPRID>)
382 * Very important, this is actually being treated like this:
383 * <Install Decision> ::= <PRID> | <EPD>
384 * <Remove Decision> ::= <PRID> | <PPRID>
386 * @param conn a Socket
387 * @param msg a COPSMsg
390 private void handleDecisionMsg(Socket conn, COPSMsg msg)
391 throws COPSPepException {
392 COPSDecisionMsg dMsg = (COPSDecisionMsg) msg;
393 COPSHandle handle = dMsg.getClientHandle();
394 Hashtable decisions = dMsg.getDecisions();
396 for (Enumeration e = decisions.keys() ; e.hasMoreElements() ;) {
398 COPSContext context = (COPSContext) e.nextElement();
399 Vector v = (Vector) decisions.get(context);
401 Enumeration ee = v.elements();
402 if (ee.hasMoreElements()) {
403 COPSDecision decision = (COPSDecision) ee.nextElement();
405 // Get the associated manager
406 COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(handle.getId().str());
408 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG);
410 // Check message type
411 if (decision.getFlags() == COPSDecision.F_REQSTATE) {
412 if (decision.isRemoveDecision())
413 // Delete Request State
414 manager.processDeleteRequestState(dMsg);
416 // Open new Request State
417 handleOpenNewRequestStateMsg(conn, handle);
420 manager.processDecision(dMsg);
427 * Method handleOpenNewRequestStateMsg
429 * @param conn a Socket
430 * @param handle a COPSHandle
433 private void handleOpenNewRequestStateMsg(Socket conn, COPSHandle handle)
434 throws COPSPepException {
436 COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(handle.getId().str());
438 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG);
440 manager.processOpenNewRequestState();
444 * Method handleSyncStateReqMsg
446 * <Synchronize State> ::= <Common Header>
450 * @param conn a Socket
451 * @param msg a COPSMsg
454 private void handleSyncStateReqMsg(Socket conn, COPSMsg msg)
455 throws COPSPepException {
456 COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg;
457 // COPSHandle handle = cMsg.getClientHandle();
458 // COPSHeader header = cMsg.getHeader();
461 if (cMsg.getIntegrity() != null) {
462 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOSUPPORTED,
463 "Unsupported objects (Integrity) to connection " + conn.getInetAddress());
466 COPSPepReqStateMan manager = (COPSPepReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str());
467 if (manager == null) {
468 COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG);
470 manager.processSyncStateRequest(cMsg);
475 * Method createRequestState
477 * @param clientHandle a String
478 * @param process a COPSPepDataProcess
480 * @return a COPSPepmanager
482 * @throws COPSException
483 * @throws COPSPepException
486 protected COPSPepReqStateMan addRequestState(String clientHandle, COPSPepDataProcess process)
487 throws COPSException, COPSPepException {
488 COPSPepReqStateMan manager = new COPSPepReqStateMan(_clientType,clientHandle);
489 if (_managerMap.get(clientHandle) != null)
490 throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle);
492 manager.setDataProcess(process);
493 _managerMap.put(clientHandle,manager);
494 manager.initRequestState(_sock);
499 * Method deleteRequestState
501 * @param manager a COPSPepReqStateMan
503 * @throws COPSException
504 * @throws COPSPepException
507 protected void deleteRequestState(COPSPepReqStateMan manager)
508 throws COPSException, COPSPepException {
509 manager.finalizeRequestState();
512 private void notifyCloseAllReqStateMan()
513 throws COPSPepException {
514 if (_managerMap.size() > 0) {
515 for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {
516 String handle = (String) e.nextElement();
517 COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle);
519 man.processClosedConnection(_error);
524 private void notifyNoKAAllReqStateMan()
525 throws COPSPepException {
526 if (_managerMap.size() > 0) {
527 for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {
528 String handle = (String) e.nextElement();
529 COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle);
531 man.processNoKAConnection();
536 private void notifyAcctAllReqStateMan()
537 throws COPSPepException {
538 if (_managerMap.size() > 0) {
539 for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {
540 String handle = (String) e.nextElement();
541 COPSPepReqStateMan man = (COPSPepReqStateMan) _managerMap.get(handle);
543 man.processAcctReport();