The second patch of an estimated 4 to complete the COPS message refactoring as descri...
[packetcable.git] / packetcable-driver / src / main / java / org / pcmm / PCMMPdpAgent.java
1 /**
2  @header@
3  */
4
5 package org.pcmm;
6
7 import org.pcmm.objects.MMVersionInfo;
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10 import org.umu.cops.prpdp.COPSPdpAgent;
11 import org.umu.cops.prpdp.COPSPdpException;
12 import org.umu.cops.stack.*;
13 import org.umu.cops.stack.COPSError.ErrorTypes;
14
15 import java.io.IOException;
16 import java.net.InetAddress;
17 import java.net.Socket;
18
19 /**
20  * Core PDP agent for provisioning
21  */
22 public class PCMMPdpAgent extends COPSPdpAgent {
23
24     public final static Logger logger = LoggerFactory.getLogger(PCMMPdpAgent.class);
25
26     /** Well-known port for PCMM */
27     public static final int WELL_KNOWN_PDP_PORT = 3918;
28
29     private COPSPepId _pepId;
30     private String _pepIdString;
31     /**
32      * PEP host name
33      */
34     private String psHost;
35
36     /**
37      * PEP port
38      */
39     private int psPort;
40
41     private Socket socket;
42
43     /**
44      * Policy data processing object
45      */
46     private PCMMPdpDataProcess _process;
47     private COPSHandle _handle;
48 //    private short _transactionID;
49
50     /**
51      * Creates a PDP Agent
52      *
53      * @param clientType
54      *            COPS Client-type
55      * @param process
56      *            Object to perform policy data processing
57      */
58     public PCMMPdpAgent(short clientType, PCMMPdpDataProcess process) {
59         this(clientType, null, WELL_KNOWN_PDP_PORT, process);
60     }
61
62     /**
63      * Creates a PDP Agent
64      *
65      * @param clientType
66      *            COPS Client-type
67      * @param psHost
68      *            Host to connect to
69      * @param psPort
70      *            Port to connect to
71      * @param process
72      *            Object to perform policy data processing
73      */
74     public PCMMPdpAgent(short clientType, String psHost, int psPort, PCMMPdpDataProcess process) {
75         super(psPort, clientType, null);
76         this._process = process;
77         this.psHost = psHost;
78     }
79
80     /**
81      * XXX -tek- This is the retooled connect. Not sure if the while forever
82      * loop is needed. Socket accept --> handleClientOpenMsg --> pdpConn.run()
83      *
84      * Below is new Thread(pdpConn).start(); Does that do it?
85      *
86      */
87     /**
88      * Connects to a PDP
89      *
90      * @param psHost
91      *            CMTS host name
92      * @param psPort
93      *            CMTS port
94      * @return <tt>true</tt> if PDP accepts the connection; <tt>false</tt>
95      *         otherwise
96      * @throws java.net.UnknownHostException
97      * @throws java.io.IOException
98      * @throws COPSException
99      * @throws COPSPdpException
100      */
101     public boolean connect(String psHost, int psPort) throws IOException, COPSException, COPSPdpException {
102
103         this.psHost = psHost;
104         this.psPort = psPort;
105         // Create Socket and send OPN
106         InetAddress addr = InetAddress.getByName(psHost);
107         try {
108             socket = new Socket(addr, psPort);
109         } catch (IOException e) {
110             logger.error("Error creating socket connection", e);
111             return (false);
112         }
113         logger.info("PDP Socket Opened");
114         // Loop through for Incoming messages
115
116         // server infinite loop
117         // while(true)
118         {
119
120             // We're waiting for an message
121             try {
122                 logger.info("PDP  COPSTransceiver.receiveMsg");
123                 COPSMsg msg = COPSTransceiver.receiveMsg(socket);
124                 if (msg.getHeader().isAClientOpen()) {
125                     logger.info("PDP msg.getHeader().isAClientOpen");
126                     handleClientOpenMsg(socket, msg);
127                 } else {
128                     try {
129                         socket.close();
130                     } catch (Exception ex) {
131                         logger.error("Unexpected exception closing socket", ex);
132                     }
133                 }
134             } catch (Exception e) { // COPSException, IOException
135                 try {
136                     socket.close();
137                 } catch (Exception ex) {
138                     logger.error("Unexpected exception closing socket", ex);
139                 }
140                 return true;
141             }
142         }
143         return false;
144     }
145
146     /**
147      * Handles a COPS client-open message
148      *
149      * @param conn
150      *            Socket to the PEP
151      * @param msg
152      *            <tt>COPSMsg</tt> holding the client-open message
153      * @throws COPSException
154      * @throws IOException
155      */
156     private void handleClientOpenMsg(Socket conn, COPSMsg msg)
157     throws COPSException, IOException {
158         COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
159         COPSPepId pepId = cMsg.getPepId();
160
161         // Validate Client Type
162         if (msg.getHeader().getClientType() != getClientType()) {
163             // Unsupported client type
164             COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg
165                                              .getHeader().getClientType());
166             COPSError err = new COPSError(ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA);
167             COPSClientCloseMsg closeMsg = new COPSClientCloseMsg();
168             closeMsg.add(cHdr);
169             closeMsg.add(err);
170             try {
171                 closeMsg.writeData(conn);
172             } catch (IOException unae) {
173                 logger.error("Unexpected error writing COPS data", unae);
174             }
175
176             throw new COPSException("Unsupported client type");
177         }
178
179         // PEPId is mandatory
180         if (pepId == null) {
181             // Mandatory COPS object missing
182             COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg
183                                              .getHeader().getClientType());
184             COPSError err = new COPSError(
185                     ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA);
186             COPSClientCloseMsg closeMsg = new COPSClientCloseMsg();
187             closeMsg.add(cHdr);
188             closeMsg.add(err);
189             try {
190                 closeMsg.writeData(conn);
191             } catch (IOException unae) {
192                 logger.error("Unexpected error writing COPS data", unae);
193             }
194
195             throw new COPSException("Mandatory COPS object missing (PEPId)");
196         }
197         setPepId(pepId);
198         // Support
199         if ((cMsg.getClientSI() != null) ) {
200             final MMVersionInfo _mminfo = new MMVersionInfo(cMsg.getClientSI().getData().getData());
201             logger.info("CMTS sent MMVersion info : major:" + _mminfo.getMajorVersionNB() + "  minor:" +
202                     _mminfo.getMinorVersionNB());
203
204         } else {
205             // Unsupported objects
206             COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg
207                                              .getHeader().getClientType());
208             COPSError err = new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA);
209             COPSClientCloseMsg closeMsg = new COPSClientCloseMsg();
210             closeMsg.add(cHdr);
211             closeMsg.add(err);
212             try {
213                 closeMsg.writeData(conn);
214             } catch (IOException unae) {
215                 logger.error("Unexpected error writing COPS data", unae);
216             }
217
218             throw new COPSException("Unsupported objects (PdpAddress, Integrity)");
219         }
220         /*
221         */
222
223         // Connection accepted
224         COPSHeader ahdr = new COPSHeader(COPSHeader.COPS_OP_CAT, msg
225                                          .getHeader().getClientType());
226         COPSKATimer katimer = new COPSKATimer(getKaTimer());
227         COPSAcctTimer acctTimer = new COPSAcctTimer(getAcctTimer());
228         COPSClientAcceptMsg acceptMsg = new COPSClientAcceptMsg();
229         acceptMsg.add(ahdr);
230         acceptMsg.add(katimer);
231         if (getAcctTimer() != 0)
232             acceptMsg.add(acctTimer);
233         acceptMsg.writeData(conn);
234         // XXX - handleRequestMsg
235         try {
236             logger.info("PDP COPSTransceiver.receiveMsg");
237             COPSMsg rmsg = COPSTransceiver.receiveMsg(socket);
238             // Client-Close
239             if (rmsg.getHeader().isAClientClose()) {
240                 logger.info("Client close description - " + ((COPSClientCloseMsg) rmsg).getError().getDescription());
241                 // close the socket
242                 COPSHeader cHdr = new COPSHeader(COPSHeader.COPS_OP_CC, msg
243                                                  .getHeader().getClientType());
244                 COPSError err = new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA);
245                 COPSClientCloseMsg closeMsg = new COPSClientCloseMsg();
246                 closeMsg.add(cHdr);
247                 closeMsg.add(err);
248                 try {
249                     closeMsg.writeData(conn);
250                 } catch (IOException unae) {
251                     logger.error("Unexpected exception writing COPS data", unae);
252                 }
253                 throw new COPSException("CMTS requetsed Client-Close");
254             } else {
255                 // Request
256                 if (rmsg.getHeader().isARequest()) {
257                     COPSReqMsg rMsg = (COPSReqMsg) rmsg;
258                     _handle = rMsg.getClientHandle();
259                 } else
260                     throw new COPSException("Can't understand request");
261
262             }
263         } catch (Exception e) { // COPSException, IOException
264             throw new COPSException("Error COPSTransceiver.receiveMsg");
265         }
266
267         logger.info("PDPCOPSConnection");
268         PCMMPdpConnection pdpConn = new PCMMPdpConnection(pepId, conn, _process);
269         pdpConn.setKaTimer(getKaTimer());
270         if (getAcctTimer() != 0)
271             pdpConn.setAccTimer(getAcctTimer());
272
273         // XXX - handleRequestMsg
274         // XXX - check handle is valid
275         PCMMPdpReqStateMan man = new PCMMPdpReqStateMan(getClientType(), _handle.getId().str());
276         pdpConn.getReqStateMans().put(_handle.getId().str(),man);
277         man.setDataProcess(_process);
278         try {
279             man.initRequestState(conn);
280         } catch (COPSPdpException unae) {
281             logger.error("Error initializing the state manager's request state");
282         }
283         // XXX - End handleRequestMsg
284
285         logger.info("PDP Thread(pdpConn).start");
286         new Thread(pdpConn).start();
287         getConnectionMap().put(pepId.getData().str(), pdpConn);
288     }
289
290     /**
291      * @return the _psHost
292      */
293     public String getPsHost() {
294         return psHost;
295     }
296
297     /**
298      * TODO - make the host immutable
299      * @param _psHost
300      *            the _psHost to set
301      */
302     @Deprecated
303     public void setPsHost(String _psHost) {
304         this.psHost = _psHost;
305     }
306
307     /**
308      * @return the _psPort
309      */
310     public int getPsPort() {
311         return psPort;
312     }
313
314     /**
315      * TODO - make the port immutable
316      * @param _psPort
317      *            the _psPort to set
318      */
319     @Deprecated
320     public void setPsPort(int _psPort) {
321         this.psPort = _psPort;
322     }
323
324     /**
325      * @return the socket
326      */
327     public Socket getSocket() {
328         return socket;
329     }
330
331     /**
332      * TODO - Ensure socket is not overly transient
333      * @param socket
334      *            the socket to set
335      */
336     @Deprecated
337     public void setSocket(Socket socket) {
338         this.socket = socket;
339     }
340
341     /**
342      * @return the _process
343      */
344     public PCMMPdpDataProcess getProcess() {
345         return _process;
346     }
347
348     /**
349      * @param _process
350      *            the _process to set
351      */
352     public void setProcess(PCMMPdpDataProcess _process) {
353         this._process = _process;
354     }
355
356     /**
357       * Gets the client handle
358       * @return   Client's <tt>COPSHandle</tt>
359       */
360     public COPSHandle getClientHandle() {
361         return _handle;
362     }
363
364     /**
365       * Gets the PepId
366       * @return   <tt>COPSPepId</tt>
367       */
368     public COPSPepId getPepId() {
369         return _pepId;
370     }
371
372     public String getPepIdString() {
373         return _pepIdString;
374     }
375
376     /**
377      * Sets the PepId
378      * TODO - make PEP ID and the associate string immutable or remove altogether
379      * @param   pepId - COPSPepId
380      */
381     @Deprecated
382     public void setPepId(COPSPepId pepId) {
383         _pepId = pepId;
384         _pepIdString = pepId.getData().str();
385      }
386     /*
387      * (non-Javadoc)
388      *
389      * @see org.pcmm.rcd.IPCMMClient#isConnected()
390      */
391     public boolean isConnected() {
392         return socket != null && socket.isConnected();
393     }
394
395
396 }