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