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