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