Merge changes I0d4117b1,Ib233ea80,I307b4ddd,I03338c43,Id8641e04, ...
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / ospdp / COPSPdpOSConnection.java
1 package org.umu.cops.ospdp;\r
2 \r
3 import org.slf4j.Logger;\r
4 import org.slf4j.LoggerFactory;\r
5 import org.umu.cops.stack.*;\r
6 \r
7 import java.io.IOException;\r
8 import java.net.Socket;\r
9 import java.util.Date;\r
10 import java.util.Enumeration;\r
11 import java.util.Hashtable;\r
12 \r
13 /**\r
14  * Class for managing an outsourcing connection at the PDP side.\r
15  */\r
16 public class COPSPdpOSConnection implements Runnable {\r
17 \r
18     public final static Logger logger = LoggerFactory.getLogger(COPSPdpOSConnection.class);\r
19 \r
20     /**\r
21         Socket connected to PEP\r
22      */\r
23     private Socket _sock;\r
24 \r
25     /**\r
26         PEP identifier\r
27     */\r
28     private COPSPepId _pepId;\r
29 \r
30     /**\r
31         Time of the latest keep-alive sent\r
32      */\r
33     private Date _lastKa;\r
34 \r
35     /**\r
36         Opcode of the latest message sent\r
37     */\r
38     private byte _lastmessage;\r
39 \r
40     /**\r
41      *  Time of the latest keep-alive received\r
42      */\r
43     protected Date _lastRecKa;\r
44 \r
45     /**\r
46         Maps a Client Handle to a Handler\r
47      */\r
48     protected Hashtable _managerMap;\r
49     // map < String(COPSHandle), COPSPdpHandler> HandlerMap;\r
50 \r
51     /**\r
52      *  PDP policy data processor class\r
53      */\r
54     protected COPSPdpOSDataProcess _process;\r
55 \r
56     /**\r
57         Accounting timer value (secs)\r
58      */\r
59     protected short _acctTimer;\r
60 \r
61     /**\r
62         Keep-alive timer value (secs)\r
63      */\r
64     protected short _kaTimer;\r
65 \r
66     /**\r
67         COPS error returned by PEP\r
68      */\r
69     protected COPSError _error;\r
70 \r
71     /**\r
72      * Creates a new PDP connection\r
73      *\r
74      * @param pepId PEP-ID of the connected PEP\r
75      * @param sock  Socket connected to PEP\r
76      * @param process   Object for processing policy data\r
77      */\r
78     public COPSPdpOSConnection(COPSPepId pepId, Socket sock, COPSPdpOSDataProcess process) {\r
79         _sock = sock;\r
80         _pepId = pepId;\r
81 \r
82         _lastKa = new Date();\r
83         _lastmessage = COPSHeader.COPS_OP_OPN;\r
84         _managerMap = new Hashtable(20);\r
85 \r
86         _kaTimer = 0;\r
87         _process = process;\r
88     }\r
89 \r
90     /**\r
91      * Gets the time of that latest keep-alive sent\r
92      * @return Time of that latest keep-alive sent\r
93      */\r
94     public Date getLastKAlive() {\r
95         return _lastKa;\r
96     }\r
97 \r
98     /**\r
99      * Sets the keep-alive timer value\r
100      * @param kaTimer Keep-alive timer value (secs)\r
101      */\r
102     public void setKaTimer(short kaTimer) {\r
103         _kaTimer = kaTimer;\r
104     }\r
105 \r
106     /**\r
107      * Gets the keep-alive timer value\r
108      * @return Keep-alive timer value (secs)\r
109      */\r
110     public short getKaTimer() {\r
111         return _kaTimer;\r
112     }\r
113 \r
114     /**\r
115      * Sets the accounting timer value\r
116      * @param acctTimer Accounting timer value (secs)\r
117      */\r
118     public void setAccTimer(short acctTimer) {\r
119         _acctTimer = acctTimer;\r
120     }\r
121 \r
122     /**\r
123      * Gets the accounting timer value\r
124      * @return Accounting timer value (secs)\r
125      */\r
126     public short getAcctTimer() {\r
127         return _acctTimer;\r
128     }\r
129 \r
130     /**\r
131      * Gets the latest COPS message\r
132      * @return   Code of the latest message sent\r
133      */\r
134     public byte getLastMessage() {\r
135         return _lastmessage;\r
136     }\r
137 \r
138     /**\r
139      * Gets active handles\r
140      * @return   An <tt>Enumeration</tt> holding all active handles\r
141      */\r
142     public Enumeration getHandles() {\r
143         return _managerMap.keys();\r
144     }\r
145 \r
146     /**\r
147      * Gets the handle map\r
148      * @return   A <tt>Hashtable</tt> holding the handle map\r
149      */\r
150     public Hashtable getReqStateMans() {\r
151         return _managerMap;\r
152     }\r
153 \r
154     /**\r
155      * Gets the PEP-ID\r
156      * @return   The ID of the PEP, as a <tt>String</tt>\r
157      */\r
158     public String getPepId() {\r
159         return _pepId.getData().str();\r
160     }\r
161 \r
162     /**\r
163      * Checks whether the socket to the PEP is closed or not\r
164      * @return   <tt>true</tt> if closed, <tt>false</tt> otherwise\r
165      */\r
166     public boolean isClosed() {\r
167         return _sock.isClosed();\r
168     }\r
169 \r
170     /**\r
171      * Closes the socket to the PEP\r
172      * @throws IOException\r
173      */\r
174     protected void close()\r
175     throws IOException {\r
176         _sock.close();\r
177     }\r
178 \r
179     /**\r
180      * Gets the socket to the PEP\r
181      * @return   Socket connected to the PEP\r
182      */\r
183     public Socket getSocket() {\r
184         return _sock;\r
185     }\r
186 \r
187     /**\r
188      * Main loop\r
189      */\r
190     public void run () {\r
191         Date _lastSendKa = new Date();\r
192         _lastRecKa = new Date();\r
193         try {\r
194             while (!_sock.isClosed()) {\r
195                 if (_sock.getInputStream().available() != 0) {\r
196                     _lastmessage = processMessage(_sock);\r
197                     _lastRecKa = new Date();\r
198                 }\r
199 \r
200                 // Keep Alive\r
201                 if (_kaTimer > 0) {\r
202                     // Timeout at PDP\r
203                     int _startTime = (int) (_lastRecKa.getTime());\r
204                     int cTime = (int) (new Date().getTime());\r
205 \r
206                     if ((cTime - _startTime) > _kaTimer*1000) {\r
207                         _sock.close();\r
208                         // Notify all Request State Managers\r
209                         notifyNoKAAllReqStateMan();\r
210                     }\r
211 \r
212                     // Send to PEP\r
213                     _startTime = (int) (_lastSendKa.getTime());\r
214                     cTime = (int) (new Date().getTime());\r
215 \r
216                     if ((cTime - _startTime) > ((_kaTimer*3/4)*1000)) {\r
217                         COPSHeader hdr = new COPSHeader(COPSHeader.COPS_OP_KA);\r
218                         COPSKAMsg msg = new COPSKAMsg();\r
219 \r
220                         msg.add(hdr);\r
221 \r
222                         COPSTransceiver.sendMsg(msg, _sock);\r
223                         _lastSendKa = new Date();\r
224                     }\r
225                 }\r
226 \r
227                 try {\r
228                     Thread.sleep(500);\r
229                 } catch (Exception e) {\r
230                     logger.error("Exception caught while sleeping", e);\r
231                 }\r
232 \r
233             }\r
234         } catch (Exception e) {\r
235             logger.error("Error processing COPS message from socket", e);\r
236         }\r
237 \r
238         // connection closed by server\r
239         // COPSDebug.out(getClass().getName(),"Connection closed by client");\r
240         try {\r
241             _sock.close();\r
242         } catch (IOException e) {\r
243             logger.error("Error closing socket", e);\r
244         }\r
245 \r
246         // Notify all Request State Managers\r
247         try {\r
248             notifyCloseAllReqStateMan();\r
249         } catch (COPSPdpException e) {\r
250             logger.error("Error closing state managers", e);\r
251         }\r
252     }\r
253 \r
254     /**\r
255      * Gets a COPS message from the socket and processes it\r
256      * @param    conn Socket connected to the PEP\r
257      * @return Type of COPS message\r
258      */\r
259     private byte processMessage(Socket conn)\r
260     throws COPSPdpException, COPSException, IOException {\r
261         COPSMsg msg = COPSTransceiver.receiveMsg(conn);\r
262 \r
263         if (msg.getHeader().isAClientClose()) {\r
264             handleClientCloseMsg(conn, msg);\r
265             return COPSHeader.COPS_OP_CC;\r
266         } else if (msg.getHeader().isAKeepAlive()) {\r
267             handleKeepAliveMsg(conn, msg);\r
268             return COPSHeader.COPS_OP_KA;\r
269         } else if (msg.getHeader().isARequest()) {\r
270             handleRequestMsg(conn, msg);\r
271             return COPSHeader.COPS_OP_REQ;\r
272         } else if (msg.getHeader().isAReport()) {\r
273             handleReportMsg(conn, msg);\r
274             return COPSHeader.COPS_OP_RPT;\r
275         } else if (msg.getHeader().isADeleteReq()) {\r
276             handleDeleteRequestMsg(conn, msg);\r
277             return COPSHeader.COPS_OP_DRQ;\r
278         } else if (msg.getHeader().isASyncComplete()) {\r
279             handleSyncComplete(conn, msg);\r
280             return COPSHeader.COPS_OP_SSC;\r
281         } else {\r
282             throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ").");\r
283         }\r
284     }\r
285 \r
286     /**\r
287      * Handle Client Close Message, close the passed connection\r
288      *\r
289      * @param    conn                a  Socket\r
290      * @param    msg                 a  COPSMsg\r
291      *\r
292      *\r
293      * <Client-Close> ::= <Common Header>\r
294      *                      <Error>\r
295      *                      [<Integrity>]\r
296      *\r
297      * Not support [<Integrity>]\r
298      *\r
299      */\r
300     private void handleClientCloseMsg(Socket conn, COPSMsg msg) {\r
301         COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg;\r
302         _error = cMsg.getError();\r
303 \r
304         // COPSDebug.out(getClass().getName(),"Got close request, closing connection " +\r
305         //  conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]");\r
306 \r
307         try {\r
308             // Support\r
309             if (cMsg.getIntegrity() != null) {\r
310                 logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
311             }\r
312 \r
313             conn.close();\r
314         } catch (Exception unae) {\r
315             logger.error("Unexpected exception while closing the connection", unae);\r
316         }\r
317     }\r
318 \r
319     /**\r
320      * Gets the occurred COPS Error\r
321      * @return   <tt>COPSError</tt> object\r
322      */\r
323     protected COPSError getError()  {\r
324         return _error;\r
325     }\r
326 \r
327     /**\r
328      * Handle Keep Alive Message\r
329      *\r
330      * <Keep-Alive> ::= <Common Header>\r
331      *                  [<Integrity>]\r
332      *\r
333      * Not support [<Integrity>]\r
334      *\r
335      * @param    conn                a  Socket\r
336      * @param    msg                 a  COPSMsg\r
337      *\r
338      */\r
339     private void handleKeepAliveMsg(Socket conn, COPSMsg msg) {\r
340         COPSKAMsg cMsg = (COPSKAMsg) msg;\r
341 \r
342         COPSKAMsg kaMsg = (COPSKAMsg) msg;\r
343         try {\r
344             // Support\r
345             if (cMsg.getIntegrity() != null) {\r
346                 logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
347             }\r
348 \r
349             kaMsg.writeData(conn);\r
350         } catch (Exception unae) {\r
351             logger.error("Unexpected exception writing COPS data", unae);\r
352         }\r
353     }\r
354 \r
355     /**\r
356      * Handle Delete Request Message\r
357      *\r
358      * <Delete Request> ::= <Common Header>\r
359      *                      <Client Handle>\r
360      *                      <Reason>\r
361      *                      [<Integrity>]\r
362      *\r
363      * Not support [<Integrity>]\r
364      *\r
365      * @param    conn                a  Socket\r
366      * @param    msg                 a  COPSMsg\r
367      *\r
368      */\r
369     private void handleDeleteRequestMsg(Socket conn, COPSMsg msg)\r
370     throws COPSPdpException {\r
371         COPSDeleteMsg cMsg = (COPSDeleteMsg) msg;\r
372         // COPSDebug.out(getClass().getName(),"Removing ClientHandle for " +\r
373         //  conn.getInetAddress() + ":" + conn.getPort() + ":[Reason " + cMsg.getReason().getDescription() + "]");\r
374 \r
375         // Support\r
376         if (cMsg.getIntegrity() != null) {\r
377             logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
378         }\r
379 \r
380         // Delete clientHandler\r
381         if (_managerMap.remove(cMsg.getClientHandle().getId().str()) == null) {\r
382             // COPSDebug.out(getClass().getName(),"Missing for ClientHandle " +\r
383             //  cMsg.getClientHandle().getId().getData());\r
384         }\r
385 \r
386         COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str());\r
387         if (man == null) {\r
388             logger.warn("State manager not found for ID - " + cMsg.getClientHandle().getId().str());\r
389         } else {\r
390             man.processDeleteRequestState(cMsg);\r
391         }\r
392 \r
393     }\r
394 \r
395     /**\r
396      * Handle Request Message\r
397      *\r
398      * <Request> ::= <Common Header>\r
399      *                  <Client Handle>\r
400      *                  <Context>\r
401      *                  *(<Named ClientSI>)\r
402      *                  [<Integrity>]\r
403      * <Named ClientSI> ::= <*(<PRID> <EPD>)>\r
404      *\r
405      * Not support [<Integrity>]\r
406      *\r
407      * @param    conn                a  Socket\r
408      * @param    msg                 a  COPSMsg\r
409      *\r
410      */\r
411     private void handleRequestMsg(Socket conn, COPSMsg msg) throws COPSPdpException {\r
412         COPSReqMsg reqMsg = (COPSReqMsg) msg;\r
413         COPSContext cntxt = reqMsg.getContext();\r
414         COPSHeader header = reqMsg.getHeader();\r
415         //short reqType = cntxt.getRequestType();\r
416         short cType   = header.getClientType();\r
417 \r
418         // Support\r
419         if (reqMsg.getIntegrity() != null) {\r
420             logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
421         }\r
422 \r
423         COPSPdpOSReqStateMan man;\r
424         man = (COPSPdpOSReqStateMan) _managerMap.get(reqMsg.getClientHandle().getId().str());\r
425         if (man == null) {\r
426             man = new COPSPdpOSReqStateMan(cType, reqMsg.getClientHandle().getId().str());\r
427             _managerMap.put(reqMsg.getClientHandle().getId().str(),man);\r
428             man.setDataProcess(_process);\r
429             man.initRequestState(_sock);\r
430 \r
431             // COPSDebug.out(getClass().getName(),"createHandler called, clientType=" +\r
432             //    header.getClientType() + " msgType=" +\r
433             //    cntxt.getMessageType() + ", connId=" + conn.toString());\r
434         }\r
435 \r
436         man.processRequest(reqMsg);\r
437     }\r
438 \r
439     /**\r
440      * Handle Report Message\r
441      *\r
442      * <Report State> ::= <Common Header>\r
443      *                      <Client Handle>\r
444      *                      <Report Type>\r
445      *                      *(<Named ClientSI>)\r
446      *                      [<Integrity>]\r
447      *\r
448      * Not support [<Integrity>]\r
449      *\r
450      * @param    conn                a  Socket\r
451      * @param    msg                 a  COPSMsg\r
452      *\r
453      */\r
454     private void handleReportMsg(Socket conn, COPSMsg msg) throws COPSPdpException {\r
455         COPSReportMsg repMsg = (COPSReportMsg) msg;\r
456         // COPSHandle handle = repMsg.getClientHandle();\r
457         // COPSHeader header = repMsg.getHeader();\r
458 \r
459         // Support\r
460         if (repMsg.getIntegrity() != null) {\r
461             logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
462         }\r
463 \r
464         COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(repMsg.getClientHandle().getId().str());\r
465         if (man == null) {\r
466             logger.warn("State manager not found for ID - " + repMsg.getClientHandle().getId().str());\r
467         } else {\r
468             man.processReport(repMsg);\r
469         }\r
470     }\r
471 \r
472     /**\r
473      * Method handleSyncComplete\r
474      *\r
475      * @param    conn                a  Socket\r
476      * @param    msg                 a  COPSMsg\r
477      *\r
478      */\r
479     private void handleSyncComplete(Socket conn, COPSMsg msg)\r
480     throws COPSPdpException {\r
481         COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg;\r
482         // COPSHandle handle = cMsg.getClientHandle();\r
483         // COPSHeader header = cMsg.getHeader();\r
484 \r
485         // Support\r
486         if (cMsg.getIntegrity() != null) {\r
487             logger.error("Unsupported objects (Integrity) to connection " + conn.getInetAddress());\r
488         }\r
489 \r
490         COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(cMsg.getClientHandle().getId().str());\r
491         if (man == null) {\r
492             logger.warn("State manager not found for ID - " + cMsg.getClientHandle().getId().str());\r
493         } else {\r
494             man.processSyncComplete(cMsg);\r
495         }\r
496     }\r
497 \r
498     /**\r
499      * Requests a COPS sync from the PEP\r
500      * @throws COPSException\r
501      * @throws COPSPdpException\r
502      */\r
503     protected void syncAllRequestState()\r
504     throws COPSException, COPSPdpException {\r
505         if (_managerMap.size() > 0) {\r
506             for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {\r
507                 String handle = (String) e.nextElement();\r
508                 COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle);\r
509 \r
510                 man.syncRequestState();\r
511             }\r
512         }\r
513     }\r
514 \r
515     private void notifyCloseAllReqStateMan()\r
516     throws COPSPdpException {\r
517         if (_managerMap.size() > 0) {\r
518             for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {\r
519                 String handle = (String) e.nextElement();\r
520                 COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle);\r
521 \r
522                 man.processClosedConnection(_error);\r
523             }\r
524         }\r
525     }\r
526 \r
527     private void notifyNoKAAllReqStateMan()\r
528     throws COPSPdpException {\r
529         if (_managerMap.size() > 0) {\r
530             for (Enumeration e = _managerMap.keys() ; e.hasMoreElements() ;) {\r
531                 String handle = (String) e.nextElement();\r
532                 COPSPdpOSReqStateMan man = (COPSPdpOSReqStateMan) _managerMap.get(handle);\r
533 \r
534                 man.processNoKAConnection();\r
535             }\r
536         }\r
537     }\r
538 \r
539 }\r