f66a2318e574702630de7a207015263371650d6a
[packetcable.git] / packetcable-driver / src / main / java / org / umu / cops / ospdp / COPSPdpOSAgent.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.COPSError.ErrorTypes;
7 import org.umu.cops.stack.COPSHeader.OPCode;
8
9 import java.io.IOException;
10 import java.net.ServerSocket;
11 import java.net.Socket;
12 import java.util.Map;
13 import java.util.concurrent.ConcurrentHashMap;
14
15 /**
16  * Core PDP agent for outsourcing.
17  */
18 public class COPSPdpOSAgent extends Thread {
19
20     public final static Logger logger = LoggerFactory.getLogger(COPSPdpOSAgent.class);
21
22     /** Well-known port for COPS */
23     public static final int WELL_KNOWN_PDP_PORT = 3288;
24     /** Default keep-alive timer value (secs) */
25     public static final short KA_TIMER_VALUE = 30;
26     /** Default accounting timer value (secs) */
27     public static final short ACCT_TIMER_VALUE = 0;
28
29     /**
30         PDP host port
31      */
32     private int _serverPort;
33
34     /**
35         Client-type of connecting PEP
36      */
37     private short _clientType;
38
39     /**
40         Accounting timer (secs)
41      */
42     private short _acctTimer;
43
44     /**
45         Keep-alive timer (secs)
46      */
47     private short _kaTimer;
48
49     /**
50         Maps a PEP-ID to a connection
51      */
52     private final Map<String, COPSPdpOSConnection> _connectionMap;
53     // map < String(PEPID), COPSPdpOSConnection > ConnectionMap;
54
55     /**
56      *  Policy data processing object
57      */
58     private COPSPdpOSDataProcess _process;
59
60     /**
61      * Creates a PDP Agent
62      *
63      * @param clientType    COPS Client-type
64      * @param process       Object to perform policy data processing
65      */
66     public COPSPdpOSAgent(final short clientType, final COPSPdpOSDataProcess process) {
67         _serverPort = WELL_KNOWN_PDP_PORT;
68         _kaTimer = KA_TIMER_VALUE;
69         _acctTimer = ACCT_TIMER_VALUE;
70
71         _clientType = clientType;
72         _connectionMap = new ConcurrentHashMap<>();
73         _process = process;
74     }
75
76     /**
77      * Creates a PDP Agent
78      *
79      * @param port  Port to listen to
80      * @param clientType    COPS Client-type
81      * @param process   Object to perform policy data processing
82      */
83     public COPSPdpOSAgent(final int port, final short clientType, final COPSPdpOSDataProcess process) {
84         _serverPort = port;
85
86         _kaTimer = KA_TIMER_VALUE;
87         _acctTimer = ACCT_TIMER_VALUE;
88
89         _clientType = clientType;
90         _connectionMap = new ConcurrentHashMap<>();
91         _process = process;
92     }
93
94     /**
95      * Sets the keep-alive timer value
96      * @param    kaTimer    Keep alive timer value (secs)
97      */
98     public void setKaTimer (short kaTimer) {
99         _kaTimer = kaTimer;
100     }
101
102     /**
103      * Sets the accounting timer value
104      * @param    acctTimer  Accounting timer value (secs)
105      */
106     public void setAcctTimer (short acctTimer) {
107         _acctTimer = acctTimer;
108     }
109
110     /**
111      * Gets the value of the keep-alive timer
112      * @return   Keep-alive timer value (secs)
113      */
114     public short getKaTimer () {
115         return _kaTimer;
116     }
117
118     /**
119      * Gets the accounting timer value
120      * @return   Accounting timer value (secs)
121      */
122     public short getAcctTimer () {
123         return _acctTimer;
124     }
125
126     /**
127      * Gets the client-type
128      * @return   The client-type
129      */
130     public int getClientType() {
131         return _clientType;
132     }
133
134     /**
135      * Disconnects a PEP
136      * @param pepID PEP-ID of the PEP to be disconnected
137      * @param error COPS Error to be reported as a reason
138      * @throws COPSException
139      * @throws IOException
140      */
141     public void disconnect(final String pepID, final COPSError error) throws COPSException, IOException {
142         final COPSPdpOSConnection pdpConn = _connectionMap.get(pepID);
143         final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType, error, null, null);
144         closeMsg.writeData(pdpConn.getSocket());
145         pdpConn.close();
146     }
147
148     /**
149      * Requests a COPS sync for a PEP
150      * @param pepID PEP-ID of the PEP to be synced
151      * @throws COPSException
152      * @throws COPSPdpException
153      */
154     public void sync(String pepID) throws COPSException, COPSPdpException {
155         COPSPdpOSConnection pdpConn = _connectionMap.get(pepID);
156         pdpConn.syncAllRequestState();
157     }
158
159     /**
160      * Removes a PEP from the connection map
161      * @param pepID PEP-ID of the PEP to be removed
162      */
163     public void delete (String pepID) {
164         _connectionMap.remove(pepID);
165     }
166
167     /**
168      * Runs the PDP process
169      */
170     public void run() {
171         try {
172             final ServerSocket serverSocket = new ServerSocket (_serverPort);
173
174             //Loop through for Incoming messages
175
176             // server infinite loop
177             while (true) {
178                 // Wait for an incoming connection from a PEP
179                 Socket socket = serverSocket.accept();
180
181                 // COPSDebug.out(getClass().getName(),"New connection accepted " +
182                 //           socket.getInetAddress() +
183                 //           ":" + socket.getPort());
184
185                 // We're waiting for an OPN message
186                 try {
187                     COPSMsg msg = COPSTransceiver.receiveMsg(socket);
188                     if (msg.getHeader().getOpCode().equals(OPCode.OPN)) {
189                         handleClientOpenMsg(socket, msg);
190                     } else {
191                         // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_NOEXPECTEDMSG);
192                         try {
193                             socket.close();
194                         } catch (Exception ex) {
195                             logger.error("Error closing socket", ex);
196                         }
197                     }
198                 } catch (Exception e) { // COPSException, IOException
199                     // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION,
200                     //    "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e);
201                     try {
202                         socket.close();
203                     } catch (Exception ex) {
204                         logger.error("Error closing socket", ex);
205                     }
206                 }
207             }
208         } catch (IOException e) {
209             logger.error("Error processing socket messages", e);
210         }
211     }
212
213     /**
214       * Handles a COPS client-open message
215       * @param    conn Socket to the PEP
216       * @param    msg <tt>COPSMsg</tt> holding the client-open message
217       * @throws COPSException
218       * @throws IOException
219       */
220     private void handleClientOpenMsg(Socket conn, COPSMsg msg) throws COPSException, IOException {
221         COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
222         COPSPepId pepId = cMsg.getPepId();
223
224         // Validate Client Type
225         if (msg.getHeader().getClientType() != _clientType) {
226             // Unsupported client type
227             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType,
228                     new COPSError(ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA), null, null);
229             try {
230                 closeMsg.writeData(conn);
231             } catch (IOException unae) {
232                 logger.error("Error writing data", unae);
233             }
234
235             throw new COPSException("Unsupported client type");
236         }
237
238         // PEPId is mandatory
239         if (pepId == null) {
240             // Mandatory COPS object missing
241             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType,
242                     new COPSError(ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA), null, null);
243             try {
244                 closeMsg.writeData(conn);
245             } catch (IOException unae) {
246                 logger.error("Error writing data", unae);
247             }
248
249             throw new COPSException("Mandatory COPS object missing (PEPId)");
250         }
251
252         // Support
253         if ( (cMsg.getClientSI() != null) || (cMsg.getPdpAddress() != null) || (cMsg.getIntegrity() != null)) {
254
255             // Unsupported objects
256             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(_clientType,
257                     new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null);
258             try {
259                 closeMsg.writeData(conn);
260             } catch (IOException unae) {
261                 logger.error("Error writing data", unae);
262             }
263
264             throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)");
265         }
266
267         // Connection accepted
268         final COPSKATimer katimer = new COPSKATimer(_kaTimer);
269         final COPSClientAcceptMsg acceptMsg;
270         if (_acctTimer != 0)
271             acceptMsg = new COPSClientAcceptMsg(msg.getHeader().getClientType(), katimer, new COPSAcctTimer(_acctTimer),
272                     null);
273         else
274             acceptMsg = new COPSClientAcceptMsg(msg.getHeader().getClientType(), katimer, null, null);
275
276         acceptMsg.writeData(conn);
277
278         final COPSPdpOSConnection pdpConn = new COPSPdpOSConnection(pepId, conn, _process);
279         pdpConn.setKaTimer(_kaTimer);
280         if (_acctTimer != 0) pdpConn.setAcctTimer(_acctTimer);
281         new Thread(pdpConn).start();
282         _connectionMap.put(pepId.getData().str(),pdpConn);
283     }
284 }