1 package org.umu.cops.ospep;
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5 import org.umu.cops.stack.*;
6 import org.umu.cops.stack.COPSHeader.OPCode;
8 import java.io.IOException;
9 import java.net.Socket;
10 import java.util.Date;
11 import java.util.Hashtable;
12 import java.util.List;
14 import java.util.concurrent.ConcurrentHashMap;
17 * COPSPepConnection represents a PEP-PDP Connection Manager.
18 * Responsible for processing messages received from PDP.
20 public class COPSPepOSConnection implements Runnable {
22 public final static Logger logger = LoggerFactory.getLogger(COPSPepOSConnection.class);
24 /** Socket connected to PDP */
25 protected Socket _sock;
27 /** Time to wait responses (milliseconds), default is 10 seconds */
28 protected final int _responseTime;
30 /** COPS Client-type */
31 protected short _clientType;
34 Accounting timer value (secs)
36 protected transient short _acctTimer;
39 Keep-alive timer value (secs)
41 protected transient short _kaTimer;
44 * Time of the latest keep-alive received
46 protected Date _lastRecKa;
49 Maps a COPS Client Handle to a Request State Manager
51 protected final Map<String, COPSPepOSReqStateMan> _managerMap;
54 COPS error returned by PDP
56 protected COPSError _error;
59 * Creates a new PEP connection
60 * @param clientType PEP's client-type
61 * @param sock Socket connected to PDP
63 public COPSPepOSConnection(final short clientType, final Socket sock) {
64 _clientType = clientType;
70 _responseTime = 10000;
71 _managerMap = new ConcurrentHashMap<>();
75 * Gets the response time
76 * @return Response time value (msecs)
78 public int getResponseTime() {
83 * Gets the socket connected to the PDP
84 * @return Socket connected to PDP
86 public Socket getSocket() {
91 * Gets keep-alive timer
92 * @return Keep-alive timer value (secs)
94 public short getKaTimer () {
99 * Gets accounting timer
100 * @return Accounting timer value (secs)
102 public short getAcctTimer () {
107 * Gets all request state managers
108 * @return A <tt>Hashatable</tt> holding all request state managers
109 * TODO - change the return to Map
111 protected Hashtable getReqStateMans() {
112 return new Hashtable(_managerMap);
116 * Checks whether the socket to the PDP is closed or not
117 * @return <tt>true</tt> if the socket is closed, <tt>false</tt> otherwise
119 public boolean isClosed() {
120 return _sock.isClosed();
126 * @throws java.io.IOException
128 protected void close() throws IOException {
133 * Sets keep-alive timer
134 * @param kaTimer Keep-alive timer value (secs)
136 public void setKaTimer(short kaTimer) {
141 * Sets accounting timer
142 * @param acctTimer Accounting timer value (secs)
144 public void setAcctTimer(short acctTimer) {
145 _acctTimer = acctTimer;
149 * Message-processing loop
152 Date _lastSendKa = new Date();
153 Date _lastSendAcc = new Date();
154 _lastRecKa = new Date();
157 while (!_sock.isClosed()) {
158 if (_sock.getInputStream().available() != 0) {
159 processMessage(_sock);
160 _lastRecKa = new Date();
166 int _startTime = (int) (_lastRecKa.getTime());
167 int cTime = (int) (new Date().getTime());
169 if ((cTime - _startTime) > _kaTimer*1000) {
171 // Notify all Request State Managers
172 notifyNoKAAllReqStateMan();
176 _startTime = (int) (_lastSendKa.getTime());
177 cTime = (int) (new Date().getTime());
179 if ((cTime - _startTime) > ((_kaTimer*3/4) * 1000)) {
180 final COPSKAMsg msg = new COPSKAMsg(null);
181 COPSTransceiver.sendMsg(msg, _sock);
182 _lastSendKa = new Date();
187 if (_acctTimer > 0) {
188 int _startTime = (int) (_lastSendAcc.getTime());
189 int cTime = (int) (new Date().getTime());
191 if ((cTime - _startTime) > ((_acctTimer*3/4)*1000)) {
192 // Notify all Request State Managers
193 notifyAcctAllReqStateMan();
194 _lastSendAcc = new Date();
200 } catch (Exception e) {
201 logger.error("Exception thrown while sleeping", e);
204 } catch (Exception e) {
205 logger.error("Error while processing socket messages", e);
208 // connection closed by server
209 // COPSDebug.out(getClass().getName(),"Connection closed by server");
212 } catch (IOException e) {
213 logger.error("Unexpected exception closing the socket", e);
216 // Notify all Request State Managers
218 notifyCloseAllReqStateMan();
219 } catch (COPSPepException e) {
220 logger.error("Error closing state managers", e);
225 * Gets a COPS message from the socket and processes it
226 * @param conn Socket connected to the PDP
227 * @throws COPSPepException
228 * @throws COPSException
229 * @throws IOException
231 protected void processMessage(Socket conn) throws COPSPepException, COPSException, IOException {
232 COPSMsg msg = COPSTransceiver.receiveMsg(conn);
234 if (msg.getHeader().getOpCode().equals(OPCode.CC)) {
235 handleClientCloseMsg(conn, msg);
236 } else if (msg.getHeader().getOpCode().equals(OPCode.DEC)) {
237 handleDecisionMsg(/*OJO conn, */msg);
238 } else if (msg.getHeader().getOpCode().equals(OPCode.SSQ)) {
239 handleSyncStateReqMsg(conn, msg);
240 } else if (msg.getHeader().getOpCode().equals(OPCode.KA)) {
241 handleKeepAliveMsg(conn, msg);
243 throw new COPSPepException("Message not expected (" + msg.getHeader().getOpCode() + ").");
248 * Handle Client Close Message, close the passed connection
250 * @param conn a Socket
251 * @param msg a COPSMsg
254 * <Client-Close> ::= <Common Header>
258 * Not support [<Integrity>]
261 private void handleClientCloseMsg(Socket conn, COPSMsg msg) {
262 COPSClientCloseMsg cMsg = (COPSClientCloseMsg) msg;
263 _error = cMsg.getError();
265 // COPSDebug.out(getClass().getName(),"Got close request, closing connection " +
266 // conn.getInetAddress() + ":" + conn.getPort() + ":[Error " + _error.getDescription() + "]");
270 if (cMsg.getIntegrity() != null)
271 logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
274 } catch (Exception unae) {
275 logger.error("Unexpected exception closing connection", unae);
280 * Gets the COPS error
281 * @return <tt>COPSError</tt> returned by PDP
283 protected COPSError getError() {
288 * Handle Keep Alive Message
290 * <Keep-Alive> ::= <Common Header>
293 * Not support [<Integrity>]
295 * @param conn a Socket
296 * @param msg a COPSMsg
299 private void handleKeepAliveMsg(Socket conn, COPSMsg msg) {
300 COPSKAMsg cMsg = (COPSKAMsg) msg;
302 // COPSDebug.out(getClass().getName(),"Get KAlive Msg");
305 if (cMsg.getIntegrity() != null)
306 logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
308 // must we do anything else?
312 * Method handleDecisionMsg
314 * <Decision Message> ::= <Common Header: Flag SOLICITED>
316 * *(<Decision>) | <Error>
318 * <Decision> ::= <Context>
320 * [<ClientSI Decision Data: Outsourcing>]
321 * <Decision: Flags> ::= <Command-Code> NULLFlag
322 * <Command-Code> ::= NULLDecision | Install | Remove
323 * <ClientSI Decision Data> ::= <<Install Decision> | <Remove Decision>>
324 * <Install Decision> ::= *(<PRID> <EPD>)
325 * <Remove Decision> ::= *(<PRID> | <PPRID>)
327 * @param msg a COPSMsg
330 private void handleDecisionMsg(/*OJO Socket conn, */COPSMsg msg) throws COPSPepException {
331 COPSDecisionMsg dMsg = (COPSDecisionMsg) msg;
332 COPSHandle handle = dMsg.getClientHandle();
333 COPSPepOSReqStateMan manager = _managerMap.get(handle.getId().str());
334 manager.processDecision(dMsg);
338 * Method handleSyncStateReqMsg
340 * <Synchronize State> ::= <Common Header>
344 * @param conn a Socket
345 * @param msg a COPSMsg
348 private void handleSyncStateReqMsg(Socket conn, COPSMsg msg) throws COPSPepException {
349 COPSSyncStateMsg cMsg = (COPSSyncStateMsg) msg;
350 // COPSHandle handle = cMsg.getClientHandle();
351 // COPSHeader header = cMsg.getHeader();
354 if (cMsg.getIntegrity() != null)
355 logger.warn("Unsupported objects (Integrity) to connection " + conn.getInetAddress());
357 COPSPepOSReqStateMan manager = _managerMap.get(cMsg.getClientHandle().getId().str());
360 logger.warn("Unable to find state manager with ID - " + cMsg.getClientHandle().getId().str());
362 manager.processSyncStateRequest(cMsg);
366 * Adds a new request state
367 * @param clientHandle Client's handle
368 * @param process Policy data processing object
369 * @param clientSIs Client data from the outsourcing event
370 * @return The newly created request state manager
371 * @throws COPSException
372 * @throws COPSPepException
374 protected COPSPepOSReqStateMan addRequestState(final String clientHandle, final COPSPepOSDataProcess process,
375 final List<COPSClientSI> clientSIs)
376 throws COPSException, COPSPepException {
377 COPSPepOSReqStateMan manager = new COPSPepOSReqStateMan(_clientType, clientHandle);
378 if (_managerMap.get(clientHandle) != null)
379 throw new COPSPepException("Duplicate Handle, rejecting " + clientHandle);
381 manager.setDataProcess(process);
382 manager.setClientSI(clientSIs);
383 _managerMap.put(clientHandle, manager);
384 manager.initRequestState(_sock);
389 * Deletes a request state
390 * @param manager Request state manager
391 * @throws COPSException
392 * @throws COPSPepException
394 protected void deleteRequestState(COPSPepOSReqStateMan manager) throws COPSException, COPSPepException {
395 manager.finalizeRequestState();
398 private void notifyCloseAllReqStateMan() throws COPSPepException {
399 for (final COPSPepOSReqStateMan man : _managerMap.values()) {
400 man.processClosedConnection(_error);
404 private void notifyNoKAAllReqStateMan() throws COPSPepException {
405 for (final COPSPepOSReqStateMan man : _managerMap.values()) {
406 man.processNoKAConnection();
410 private void notifyAcctAllReqStateMan() throws COPSPepException {
411 for (final COPSPepOSReqStateMan man : _managerMap.values()) {
412 man.processAcctReport();