bb550f710774e2c3dea9561043b62110c64ba367
[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.COPSConnection;
12 import org.umu.cops.stack.*;
13
14 import javax.annotation.concurrent.ThreadSafe;
15 import java.io.IOException;
16 import java.net.Socket;
17 import java.util.Date;
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20
21 /**
22  * Class for managing an provisioning connection at the PDP side.
23  */
24 @ThreadSafe
25 public class COPSPdpConnection extends COPSConnection {
26
27     public final static Logger logger = LoggerFactory.getLogger(COPSPdpConnection.class);
28
29     /**
30      * PEP identifier
31      * TODO FIXME - Why is this member never being used?
32      */
33     private final COPSPepId _pepId;
34
35     /**
36      *  Time of the latest keep-alive sent
37      * TODO FIXME - Why is this member never being used?
38      */
39     private volatile Date _lastKa;
40
41     /**
42      * Maps a Client Handle to a Handler
43      */
44     protected final Map<COPSHandle, COPSPdpReqStateMan> _managerMap;
45
46     /**
47      *  PDP policy data processor class
48      */
49     protected final COPSPdpDataProcess _process;
50
51     /**
52      * Creates a new PDP connection
53      *
54      * @param pepId PEP-ID of the connected PEP
55      * @param sock  Socket connected to PEP
56      * @param process   Object for processing policy data
57      */
58     public COPSPdpConnection(final COPSPepId pepId, Socket sock, final COPSPdpDataProcess process) {
59         this(pepId, sock, process, (short)0, (short)0);
60     }
61
62     /**
63      * Constructor for this or extended classes
64      * @param pepId - PEP-ID of the connected PEP
65      * @param sock - Socket connected to PEP
66      * @param process - Object for processing policy data
67      * @param kaTimer - the Keep-alive timer value
68      * @param acctTimer - the accounting timer value
69      */
70     protected COPSPdpConnection(final COPSPepId pepId, Socket sock, final COPSPdpDataProcess process,
71                                 final short kaTimer, final short acctTimer) {
72         super(sock, kaTimer, acctTimer);
73         _pepId = pepId;
74         _process = process;
75         _lastKa = new Date();
76         _managerMap = new ConcurrentHashMap<>();
77     }
78
79     /**
80      * Main loop
81      */
82     public void run () {
83         Date lastSendKa = new Date();
84         Date lastRecKa = new Date();
85         try {
86             while (!_sock.isClosed()) {
87                 if (_sock.getInputStream().available() != 0) {
88                     processMessage(_sock);
89                     lastRecKa = new Date();
90                 }
91
92                 // Keep Alive
93                 if (_kaTimer > 0) {
94                     // Timeout at PDP
95                     int _startTime = (int) (lastRecKa.getTime());
96                     int cTime = (int) (new Date().getTime());
97
98                     if ((cTime - _startTime) > _kaTimer*1000) {
99                         _sock.close();
100                         // Notify all Request State Managers
101                         notifyNoKAAllReqStateMan();
102                     }
103
104                     // Send to PEP
105                     _startTime = (int) (lastSendKa.getTime());
106                     cTime = (int) (new Date().getTime());
107
108                     if ((cTime - _startTime) > ((_kaTimer*3/4)*1000)) {
109                         // TODO - what should the real clientType be here???
110                         final COPSKAMsg msg = new COPSKAMsg(null);
111                         COPSTransceiver.sendMsg(msg, _sock);
112                         lastSendKa = new Date();
113                     }
114                 }
115
116                 try {
117                     Thread.sleep(500);
118                 } catch (Exception e) {
119                     logger.error("Exception thrown while sleeping", e);
120                 }
121
122             }
123         } catch (Exception e) {
124             logger.error("Error while processing socket messages", e);
125         }
126
127         // connection closed by server
128         try {
129             _sock.close();
130         } catch (IOException e) {
131             logger.error("Error closing socket", e);
132         }
133
134         // Notify all Request State Managers
135         try {
136             notifyCloseAllReqStateMan();
137         } catch (COPSException e) {
138             logger.error("Error closing state managers");
139         }
140     }
141
142     /**
143      * Gets a COPS message from the socket and processes it
144      * @param    conn Socket connected to the PEP
145      */
146     private void processMessage(final Socket conn) throws COPSException, IOException {
147         final COPSMsg msg = COPSTransceiver.receiveMsg(conn);
148         switch (msg.getHeader().getOpCode()) {
149             case CC:
150                 handleClientCloseMsg(conn, (COPSClientCloseMsg)msg);
151                 break;
152             case KA:
153                 handleKeepAliveMsg(conn, (COPSKAMsg)msg);
154                 break;
155             case REQ:
156                 handleRequestMsg(conn, (COPSReqMsg)msg);
157                 break;
158             case RPT:
159                 handleReportMsg(conn, (COPSReportMsg)msg);
160                 break;
161             case DRQ:
162                 handleDeleteRequestMsg(conn, (COPSDeleteMsg)msg);
163                 break;
164             case SSC:
165                 handleSyncComplete(conn, (COPSSyncStateMsg)msg);
166                 break;
167             default:
168                 throw new COPSPdpException("Message not expected (" + msg.getHeader().getOpCode() + ").");
169         }
170     }
171
172     /**
173      * Handle Keep Alive Message
174      * @param    conn                a  Socket
175      * @param    kaMsg               a  COPSKAMsg
176      */
177     private void handleKeepAliveMsg(final Socket conn, final COPSKAMsg kaMsg) {
178         try {
179             // Support
180             if (kaMsg.getIntegrity() != null) {
181                 logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
182             }
183             kaMsg.writeData(conn);
184             _lastKa = new Date();
185         } catch (Exception unae) {
186             logger.error("Unexpected exception while writing COPS data", unae);
187         }
188     }
189
190     /**
191      * Handle Delete Request Message
192      * @param    conn                a  Socket
193      * @param    cMsg                a  COPSDeleteMsg
194      */
195     private void handleDeleteRequestMsg(final Socket conn, final COPSDeleteMsg cMsg) throws COPSException {
196         // Support
197         if (cMsg.getIntegrity() != null) {
198             logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
199         }
200
201         final COPSPdpReqStateMan man = _managerMap.remove(cMsg.getClientHandle());
202         if (man == null) {
203             logger.warn("No state manager found with ID - " + cMsg.getClientHandle().getId().str());
204         } else {
205             man.processDeleteRequestState(cMsg);
206         }
207     }
208
209     /**
210      * Handle Request Message
211      * @param    conn                a  Socket
212      * @param    reqMsg              a  COPSReqMsg
213      */
214     protected void handleRequestMsg(final Socket conn, final COPSReqMsg reqMsg) throws COPSException {
215         final COPSHeader header = reqMsg.getHeader();
216
217         // Support
218         if (reqMsg.getIntegrity() != null) {
219             logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
220         }
221
222         final COPSPdpReqStateMan man;
223         if (_managerMap.get(reqMsg.getClientHandle()) == null) {
224
225             man = createStateManager(reqMsg);
226             _managerMap.put(reqMsg.getClientHandle(), man);
227             man.initRequestState(_sock);
228
229             logger.info("createHandler called, clientType=" + header.getClientType() + " msgType=" + ", connId=" +
230                     conn.toString());
231         } else {
232             man = _managerMap.get(reqMsg.getClientHandle());
233         }
234         man.processRequest(reqMsg);
235     }
236
237     /**
238      * Returns an instance of a COPSPdpReqStateMan
239      * @param reqMsg - the request on which to create the state manager
240      * @return - the state manager
241      */
242     protected COPSPdpReqStateMan createStateManager(final COPSReqMsg reqMsg) {
243         return new COPSPdpReqStateMan(reqMsg.getHeader().getClientType(), reqMsg.getClientHandle(), _process);
244     }
245
246     /**
247      * Handle Report Message
248      * @param    conn                a  Socket
249      * @param    repMsg              a  COPSReportMsg
250      */
251     private void handleReportMsg(final Socket conn, final COPSReportMsg repMsg) throws COPSException {
252         // Support
253         if (repMsg.getIntegrity() != null) {
254             logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
255         }
256
257         final COPSPdpReqStateMan man = _managerMap.get(repMsg.getClientHandle());
258         if (man == null) {
259             logger.warn("No state manager found with ID - " + repMsg.getClientHandle().getId().str());
260         } else {
261             man.processReport(repMsg);
262         }
263     }
264
265     /**
266      * Method handleSyncComplete
267      * @param    conn                a  Socket
268      * @param    cMsg                a  COPSSyncStateMsg
269      */
270     private void handleSyncComplete(final Socket conn, final COPSSyncStateMsg cMsg) throws COPSException {
271         // Support
272         if (cMsg.getIntegrity() != null) {
273             logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
274         }
275
276         final COPSPdpReqStateMan man = _managerMap.get(cMsg.getClientHandle());
277         if (man == null) {
278             logger.warn("No state manager found with ID - " + cMsg.getClientHandle().getId().str());
279         } else {
280             man.processSyncComplete(cMsg);
281         }
282     }
283
284     /**
285      * Requests a COPS sync from the PEP
286      * @throws COPSException
287      * @throws COPSPdpException
288      */
289     public void syncAllRequestState() throws COPSException {
290         for (final COPSPdpReqStateMan man : _managerMap.values()) {
291             man.syncRequestState();
292         }
293     }
294
295     private void notifyCloseAllReqStateMan() throws COPSException {
296         for (final COPSPdpReqStateMan man : _managerMap.values()) {
297             man.processClosedConnection(_error);
298         }
299     }
300
301     private void notifyNoKAAllReqStateMan() throws COPSException {
302         for (final COPSPdpReqStateMan man : _managerMap.values()) {
303             man.processNoKAConnection();
304         }
305     }
306
307 }
308