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