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