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