Created abstract super class for all COPS state managers called COPSStateMan as each...
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / prpep / COPSPepConnection.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.prpep;
8
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 import org.umu.cops.stack.*;
12 import org.umu.cops.stack.COPSDecision.Command;
13 import org.umu.cops.stack.COPSDecision.DecisionFlag;
14 import org.umu.cops.stack.COPSHeader.OPCode;
15
16 import java.io.IOException;
17 import java.net.Socket;
18 import java.util.Date;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.concurrent.ConcurrentHashMap;
22
23 /**
24  * COPSPepConnection represents a PEP-PDP Connection Manager.
25  * Responsible for processing messages received from PDP.
26  */
27 public class COPSPepConnection implements Runnable {
28
29     private final static Logger logger = LoggerFactory.getLogger(COPSPepConnection.class);
30
31     /** Socket connected to PDP */
32     protected Socket _sock;
33
34     /** Time to wait responses (milliseconds), default is 10 seconds */
35     protected int _responseTime;
36
37     /** COPS Client-type */
38     protected short _clientType;
39
40     /**
41         Accounting timer value (secs)
42      */
43     protected short _acctTimer;
44
45     /**
46         Keep-alive timer value (secs)
47      */
48     protected short _kaTimer;
49
50     /**
51      *  Time of the latest keep-alive received
52      */
53     protected Date _lastRecKa;
54
55     /**
56         Maps a COPS Client Handle to a Request State Manager
57      */
58     protected final Map<COPSHandle, COPSPepReqStateMan> _managerMap;
59
60     /**
61         COPS error returned by PDP
62      */
63     protected COPSError _error;
64
65     /**
66      * Creates a new PEP connection
67      * @param clientType    PEP's client-type
68      * @param sock          Socket connected to PDP
69      */
70     public COPSPepConnection(final short clientType, final Socket sock) {
71         _clientType = clientType;
72         _sock = sock;
73
74         // Timers
75         _acctTimer = 0;
76         _kaTimer = 0;
77         _responseTime = 10000;
78         _managerMap = new ConcurrentHashMap<>();
79     }
80
81     /**
82      * Gets the response time
83      * @return  Response time value (msecs)
84      */
85     public int getResponseTime() {
86         return _responseTime;
87     }
88
89     /**
90      * Gets the socket connected to the PDP
91      * @return  Socket connected to PDP
92      */
93     public Socket getSocket() {
94         return _sock;
95     }
96
97     /**
98      * Gets keep-alive timer
99      * @return  Keep-alive timer value (secs)
100      */
101     public short getKaTimer () {
102         return _kaTimer;
103     }
104
105     /**
106      * Gets accounting timer
107      * @return  Accounting timer value (secs)
108      */
109     public short getAcctTimer () {
110         return _acctTimer;
111     }
112
113     /**
114      * Checks whether the socket to the PDP is closed or not
115      * @return  <tt>true</tt> if the socket is closed, <tt>false</tt> otherwise
116      */
117     public boolean isClosed() {
118         return _sock.isClosed();
119     }
120
121     /**
122      * Closes the socket
123      *
124      * @throws java.io.IOException
125      */
126     protected void close()
127     throws IOException {
128         _sock.close();
129     }
130
131     /**
132      * Sets response time
133      * @param respTime  Response time value (msecs)
134      */
135     public void setResponseTime(int respTime) {
136         _responseTime = respTime;
137     }
138
139     /**
140      * Sets keep-alive timer
141      * @param kaTimer   Keep-alive timer value (secs)
142      */
143     public void setKaTimer (short kaTimer) {
144         _kaTimer = kaTimer;
145     }
146
147     /**
148      * Sets accounting timer
149      * @param acctTimer Accounting timer value (secs)
150      */
151     public void setAcctTimer (short acctTimer) {
152         _acctTimer = acctTimer;
153     }
154
155     /**
156      * Message-processing loop
157      */
158     public void run () {
159         Date _lastSendKa = new Date();
160         Date _lastSendAcc = new Date();
161         _lastRecKa = new Date();
162         try {
163             while (!_sock.isClosed()) {
164                 if (_sock.getInputStream().available() != 0) {
165                     processMessage(_sock);
166                     _lastRecKa = new Date();
167                 }
168
169                 // Keep Alive
170                 if (_kaTimer > 0) {
171                     // Timeout at PDP
172                     int _startTime = (int) (_lastRecKa.getTime());
173                     int cTime = (int) (new Date().getTime());
174
175                     if ((cTime - _startTime) > _kaTimer*1000) {
176                         _sock.close();
177                         // Notify all Request State Managers
178                         notifyNoKAAllReqStateMan();
179                     }
180
181                     // Send to PEP
182                     _startTime = (int) (_lastSendKa.getTime());
183                     cTime = (int) (new Date().getTime());
184
185                     if ((cTime - _startTime) > ((_kaTimer*3/4) * 1000)) {
186                         final COPSKAMsg msg = new COPSKAMsg(null);
187                         COPSTransceiver.sendMsg(msg, _sock);
188                         _lastSendKa = new Date();
189                     }
190                 }
191
192                 // Accounting
193                 if (_acctTimer > 0) {
194                     int _startTime = (int) (_lastSendAcc.getTime());
195                     int cTime = (int) (new Date().getTime());
196
197                     if ((cTime - _startTime) > ((_acctTimer*3/4)*1000)) {
198                         // Notify all Request State Managers
199                         notifyAcctAllReqStateMan();
200                         _lastSendAcc = new Date();
201                     }
202                 }
203
204                 try {
205                     Thread.sleep(500);
206                 } catch (Exception e) {
207                     logger.error("Exception thrown while sleeping", e);
208                 }
209             }
210         } catch (Exception e) {
211             logger.error("Error while processing socket messages", e);
212         }
213
214         // connection closed by server
215         // COPSDebug.out(getClass().getName(),"Connection closed by server");
216         try {
217             _sock.close();
218         } catch (IOException e) {
219             logger.error("Error closing socket", e);
220         }
221
222         // Notify all Request State Managers
223         try {
224             notifyCloseAllReqStateMan();
225         } catch (COPSPepException e) {
226             logger.error("Error closing state managers");
227         }
228     }
229
230     /**
231      * Gets a COPS message from the socket and processes it
232      * @param conn  Socket connected to the PDP
233      * @return COPS message type
234      * @throws COPSPepException
235      * @throws COPSException
236      * @throws IOException
237      */
238     protected byte processMessage(final Socket conn) throws COPSException, IOException {
239         final COPSMsg msg = COPSTransceiver.receiveMsg(conn);
240
241         switch (msg.getHeader().getOpCode()) {
242             case CC:
243                 handleClientCloseMsg(conn, (COPSClientCloseMsg)msg);
244                 return (byte)OPCode.CC.ordinal();
245             case DEC:
246                 handleDecisionMsg((COPSDecisionMsg)msg);
247                 return (byte)OPCode.DEC.ordinal();
248             case SSQ:
249                 handleSyncStateReqMsg((COPSSyncStateMsg)msg);
250                 return (byte)OPCode.SSQ.ordinal();
251             case KA:
252                 handleKeepAliveMsg((COPSKAMsg)msg);
253                 return (byte)OPCode.KA.ordinal();
254             default:
255                 throw new COPSPepException("Message not expected (" + msg.getHeader().getOpCode() + ").");
256         }
257     }
258
259     /**
260      * Handle Client Close Message, close the passed connection
261      * @param    conn                a  Socket
262      * @param    cMsg                a  COPSClientCloseMsg
263      */
264     private void handleClientCloseMsg(final Socket conn, final COPSClientCloseMsg cMsg) {
265         _error = cMsg.getError();
266         logger.info("Got close request, closing connection "
267                 + conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]");
268         try {
269             // Support
270             if (cMsg.getIntegrity() != null) {
271                 logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
272             }
273             conn.close();
274         } catch (Exception unae) {
275             logger.error("Unexpected exception closing connection", unae);
276         }
277     }
278
279     /**
280      * Method getError
281      * @return   a COPSError
282      */
283     protected COPSError getError()  {
284         return _error;
285     }
286
287     /**
288      * Handle Keep Alive Message
289      * @param    cMsg                a  COPSKAMsg
290      */
291     private void handleKeepAliveMsg(final COPSKAMsg cMsg) {
292         logger.info("Get KAlive Msg");
293         try {
294             // Support
295             if (cMsg.getIntegrity() != null) {
296                 logger.warn("Unsupported objects (Integrity)");
297             }
298
299             // should we do anything else?? ....
300
301         } catch (Exception unae) {
302             logger.error("Unexpected exception while writing COPS data", unae);
303         }
304     }
305
306     /**
307      * Method handleDecisionMsg
308      * @param    dMsg                 a  COPSDecisionMsg
309      */
310     private void handleDecisionMsg(final COPSDecisionMsg dMsg) throws COPSPepException {
311         final COPSHandle handle = dMsg.getClientHandle();
312         final Map<COPSContext, Set<COPSDecision>> decisions = dMsg.getDecisions();
313
314         for (final Set<COPSDecision> copsDecisions: decisions.values()) {
315             for (final COPSDecision decision : copsDecisions) {
316                 // Get the associated manager
317                 final COPSPepReqStateMan manager = _managerMap.get(handle);
318                 if (manager == null) {
319                     logger.warn("Unable to find state manager with key - " + handle);
320                     return;
321                 }
322
323                 // Check message type
324                 // TODO FIXME - Use of manager object could result in a NPE
325                 if (decision.getFlag().equals(DecisionFlag.REQSTATE)) {
326                     if (decision.getCommand().equals(Command.REMOVE))
327                         // Delete Request State
328                         manager.processDeleteRequestState(dMsg);
329                     else
330                         // Open new Request State
331                         handleOpenNewRequestStateMsg(handle);
332                 } else
333                     // Decision
334                     manager.processDecision(dMsg, _sock);
335             }
336         }
337     }
338
339
340     /**
341      * Method handleOpenNewRequestStateMsg
342      * @param    handle              a  COPSHandle
343      */
344     private void handleOpenNewRequestStateMsg(final COPSHandle handle) throws COPSPepException {
345         final COPSPepReqStateMan manager = _managerMap.get(handle);
346         if (manager == null)
347             logger.warn("Unable to find state manager with key - " + handle.getId().str());
348         else
349             manager.processOpenNewRequestState();
350     }
351
352     /**
353      * Method handleSyncStateReqMsg
354      * @param    cMsg                a  COPSSyncStateMsg
355      */
356     private void handleSyncStateReqMsg(final COPSSyncStateMsg cMsg) throws COPSPepException {
357         if (cMsg.getIntegrity() != null) {
358             logger.warn("Unsupported objects (Integrity)");
359         }
360
361         final COPSPepReqStateMan manager = _managerMap.get(cMsg.getClientHandle());
362         if (manager == null)
363             logger.warn("Unable to find state manager with key - " + cMsg.getClientHandle().getId().str());
364         else
365             manager.processSyncStateRequest(cMsg);
366     }
367
368     /**
369      * Method createRequestState
370      * @param    clientHandle             a  String
371      * @param    process                  a  COPSPepDataProcess
372      * @return   a COPSPepmanager
373      * @throws   COPSException
374      * @throws   COPSPepException
375      */
376     protected COPSPepReqStateMan addRequestState(final COPSHandle clientHandle, final COPSPepDataProcess process)
377             throws COPSException {
378         final COPSPepReqStateMan manager = new COPSPepReqStateMan(_clientType, clientHandle, process);
379         if (_managerMap.get(clientHandle) != null)
380             throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle);
381
382         _managerMap.put(clientHandle, manager);
383         logger.info("Added state manager with key - " + clientHandle);
384         manager.initRequestState(_sock);
385         return manager;
386     }
387
388     /**
389      * Method deleteRequestState
390      * @param    manager             a  COPSPepReqStateMan
391      * @throws   COPSException
392      * @throws   COPSPepException
393      */
394     protected void deleteRequestState(COPSPepReqStateMan manager) throws COPSException {
395         manager.finalizeRequestState();
396     }
397
398     private void notifyCloseAllReqStateMan() throws COPSPepException {
399         for (final COPSPepReqStateMan man: _managerMap.values()) {
400             man.processClosedConnection(_error);
401         }
402     }
403
404     private void notifyNoKAAllReqStateMan() throws COPSPepException {
405         for (final COPSPepReqStateMan man: _managerMap.values()) {
406             man.processNoKAConnection();
407         }
408     }
409
410     private void notifyAcctAllReqStateMan() throws COPSPepException {
411         for (final COPSPepReqStateMan man: _managerMap.values()) {
412             man.processAcctReport();
413         }
414     }
415
416 }
417