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