2 * Copyright (c) 2004 University of Murcia. All rights reserved.
3 * --------------------------------------------------------------
4 * For more information, please see <http://www.umu.euro6ix.org/>.
7 package org.umu.cops.prpdp;
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;
15 import java.io.IOException;
16 import java.net.ServerSocket;
17 import java.net.Socket;
19 import java.util.concurrent.ConcurrentHashMap;
22 * Core PDP agent for provisioning
24 public class COPSPdpAgent extends Thread {
26 private static final Logger logger = LoggerFactory.getLogger(COPSPdpAgent.class);
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;
38 private int _serverPort;
41 * Client-type of connecting PEP
43 private short _clientType;
46 * Accounting timer (secs)
48 private short _acctTimer;
51 * Keep-alive timer (secs)
53 private short _kaTimer;
58 protected transient COPSPepId _pepId;
61 * Maps a PEP-ID to a connection
62 * TODO - Refactor COPSPdpConnection to extend PCMMPdpConnection. Until then, the value must remain an Object
64 protected Map<String, Object> _connectionMap;
65 // map < String(PEPID), COPSPdpConnection > ConnectionMap;
68 * Policy data processing object
70 private COPSPdpDataProcess _process;
73 * Holds all of the threads to manage by PEP ID
75 protected final Map<String, Thread> threadMap;
80 * @param port Port to listen to
81 * @param clientType COPS Client-type
82 * @param process Object to perform policy data processing
84 public COPSPdpAgent(final int port, final short clientType, final COPSPdpDataProcess process) {
87 _kaTimer = KA_TIMER_VALUE;
88 _acctTimer = ACCT_TIMER_VALUE;
90 _clientType = clientType;
91 _connectionMap = new ConcurrentHashMap<>();
93 this.threadMap = new ConcurrentHashMap<>();
97 * Gets the value of the keep-alive timer
98 * @return Keep-alive timer value (secs)
100 public short getKaTimer () {
105 * Gets the accounting timer value
106 * @return Accounting timer value (secs)
108 public short getAcctTimer () {
113 * Gets the client-type
114 * @return The client-type
116 public short getClientType() {
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
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());
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
140 public void sync(final String pepID) throws COPSException {
141 COPSPdpConnection pdpConn = (COPSPdpConnection) _connectionMap.get(pepID);
142 pdpConn.syncAllRequestState();
146 * Removes a PEP from the connection map
147 * @param pepID PEP-ID of the PEP to be removed
149 public void delete(final String pepID) {
150 _connectionMap.remove(pepID);
155 * Runs the PDP process
159 final ServerSocket serverSocket = new ServerSocket (_serverPort);
161 //Loop through for Incoming messages
162 // server infinite loop
164 // Wait for an incoming connection from a PEP
165 final Socket socket = serverSocket.accept();
167 // COPSDebug.out(getClass().getName(),"New connection accepted " +
168 // socket.getInetAddress() +
169 // ":" + socket.getPort());
171 // We're waiting for an OPN message
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);
178 logger.error("Not an open message, closing socket");
181 } catch (Exception ex) {
182 logger.error("Unexpected exception closing socket", ex);
185 } catch (Exception e) { // COPSException, IOException
186 // COPSDebug.err(getClass().getName(), COPSDebug.ERROR_EXCEPTION,
187 // "(" + socket.getInetAddress() + ":" + socket.getPort() + ")", e);
190 } catch (Exception ex) {
191 logger.error("Unexpected exception closing socket", ex);
195 } catch (IOException e) {
196 logger.error("Error caught while processing socket messages", e);
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
208 protected void handleClientOpenMsg(final Socket conn, final COPSMsg msg) throws COPSException, IOException {
209 final COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
210 _pepId = cMsg.getPepId();
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);
218 closeMsg.writeData(conn);
219 } catch (IOException unae) {
220 logger.error("Unexpected exception writing data", unae);
223 throw new COPSException("Unsupported client type");
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);
232 closeMsg.writeData(conn);
233 } catch (IOException unae) {
234 logger.error("Unexpected exception writing data", unae);
237 throw new COPSException("Mandatory COPS object missing (PEPId)");
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);
246 closeMsg.writeData(conn);
247 } catch (IOException unae) {
248 logger.error("Exception writing data", unae);
251 throw new COPSException("Unsupported objects (ClientSI, PdpAddress, Integrity)");
254 // Connection accepted
255 final COPSClientAcceptMsg acceptMsg;
257 acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer),
258 new COPSAcctTimer(_acctTimer), null);
260 acceptMsg = new COPSClientAcceptMsg(_clientType, new COPSKATimer(_kaTimer),null, null);
261 acceptMsg.writeData(conn);
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);