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