Miscellaneous driver fixes found while migrating and testing the new Arris API submis...
[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 import org.umu.cops.stack.COPSHeader.OPCode;
15
16 import java.io.IOException;
17 import java.net.InetAddress;
18 import java.net.Socket;
19
20 /**
21  * Core PDP agent for provisioning
22  */
23 public class PCMMPdpAgent extends COPSPdpAgent {
24
25     private static final Logger logger = LoggerFactory.getLogger(PCMMPdpAgent.class);
26
27     /** Well-known port for PCMM */
28     public static final int WELL_KNOWN_PDP_PORT = 3918;
29
30     /**
31      * PEP host name
32      */
33     private final String psHost;
34
35     /**
36      * PEP port
37      */
38     private final int psPort;
39
40     /**
41      * Policy data processing object
42      */
43     private final PCMMPdpDataProcess _process;
44
45     // Next two attributes are initialized when connected
46     /**
47      * The Socket connection to the PEP
48      */
49     private transient Socket socket;
50     private transient COPSHandle _handle;
51
52     /**
53      * Creates a PDP Agent
54      *
55      * @param clientType - COPS Client-type
56      * @param psHost - Host to connect to
57      * @param psPort - Port to connect to
58      * @param process - Object to perform policy data processing
59      */
60     public PCMMPdpAgent(final short clientType, final String psHost, final int psPort,
61                         final PCMMPdpDataProcess process) {
62         super(psPort, clientType, null);
63         this._process = process;
64         this.psHost = psHost;
65         this.psPort = psPort;
66     }
67
68     /**
69      * XXX -tek- This is the retooled connect. Not sure if the while forever
70      * loop is needed. Socket accept --> handleClientOpenMsg --> pdpConn.run()
71      *
72      * Below is new Thread(pdpConn).start(); Does that do it?
73      *
74      */
75     /**
76      * Connects to a PDP
77      *
78      * @return <tt>true</tt> if PDP accepts the connection; <tt>false</tt>
79      *         otherwise
80      * @throws java.net.UnknownHostException
81      * @throws java.io.IOException
82      * @throws COPSException
83      */
84     public boolean connect() throws IOException, COPSException, COPSPdpException {
85         // Create Socket and send OPN
86         final InetAddress addr = InetAddress.getByName(psHost);
87         // caller will catch IOExceptions
88         socket = new Socket(addr, psPort);
89         logger.debug("{} {}", getClass().getName(), "PDP Socket Opened");
90         //        COPSDebug.err(getClass().getName(), "PDP Socket Opened");
91         // Loop through for Incoming messages
92
93         // server infinite loop
94         // while(true)
95         {
96
97             // We're waiting for an message
98             try {
99                 logger.debug("Waiting to receiveMsg");
100                 final COPSMsg msg = COPSTransceiver.receiveMsg(socket);
101                 logger.debug("Message received of type - " + msg.getHeader().getOpCode());
102                 if (msg.getHeader().getOpCode().equals(OPCode.OPN)) {
103                     handleClientOpenMsg(socket, msg);
104                 } else {
105                     try {
106                         socket.close();
107                     } catch (Exception ex) {
108                         logger.error("Unexpected error closing socket", ex);
109                     }
110                 }
111             } catch (Exception e) {
112                 logger.error("Unexpected error handing client open message", e);
113                 try {
114                     socket.close();
115                 } catch (Exception ex) {
116                     logger.error("Unexpected error closing socket", ex);
117                 }
118                 return true;
119             }
120         }
121         return false;
122     }
123
124     // TODO - remove and let super handle after DataProcess & PdpConnection classes are properly refactored
125     @Override
126     public void disconnect (final String pepID, final COPSError error) throws COPSException, IOException {
127         final PCMMPdpConnection pdpConn = (PCMMPdpConnection) _connectionMap.get(pepID);
128         if (pdpConn != null) {
129             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(), error, null, null);
130             closeMsg.writeData(pdpConn.getSocket());
131             pdpConn.close();
132         }
133
134         final Thread thread = threadMap.remove(pepID);
135         if (thread != null) thread.interrupt();
136     }
137
138     @Override
139     protected void handleClientOpenMsg(final Socket conn, final COPSMsg msg) throws COPSException, IOException {
140         logger.info("Processing client open message");
141         final COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
142         _pepId = cMsg.getPepId();
143
144         // Validate Client Type
145         // TODO - Need to fix this logic. Currently the client type being set is the CCAP AMID.type mapped to the
146         // enumeration's ordinal value
147 /*
148         if (msg.getHeader().getClientType() != getClientType()) {
149             // Unsupported client type
150             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
151                     new COPSError(ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA), null, null);
152             try {
153                 closeMsg.writeData(conn);
154             } catch (IOException unae) {
155                 logger.error("Unexpected error writing data", unae);
156             }
157
158             throw new COPSException("Unsupported client type");
159         }
160 */
161
162         // PEPId is mandatory
163         if (_pepId == null) {
164             // Mandatory COPS object missing
165             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
166                     new COPSError(ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA), null, null);
167             try {
168                 closeMsg.writeData(conn);
169             } catch (IOException unae) {
170                 logger.error("Unexpected error closing socket", unae);
171             }
172
173             throw new COPSException("Mandatory COPS object missing (PEPId)");
174         }
175
176         // Support
177         if ((cMsg.getClientSI() != null) ) {
178             final MMVersionInfo _mminfo = new MMVersionInfo(cMsg.getClientSI().getData().getData());
179             logger.debug("CMTS sent MMVersion info : major:" + _mminfo.getMajorVersionNB() + "  minor:" +
180                     _mminfo.getMinorVersionNB());
181
182         } else {
183             // Unsupported objects
184             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
185                     new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null);
186             try {
187                 closeMsg.writeData(conn);
188             } catch (IOException unae) {
189                 logger.error("Unexpected error writing data", unae);
190             }
191
192             throw new COPSException("Unsupported objects (PdpAddress, Integrity)");
193         }
194         /*
195         */
196
197         // Connection accepted
198         final COPSClientAcceptMsg acceptMsg;
199         if (getAcctTimer() != 0)
200             acceptMsg = new COPSClientAcceptMsg(getClientType(), new COPSKATimer(getKaTimer()),
201                     new COPSAcctTimer(getAcctTimer()), null);
202         else
203             acceptMsg = new COPSClientAcceptMsg(getClientType(), new COPSKATimer(getKaTimer()), null, null);
204         acceptMsg.writeData(conn);
205         // XXX - handleRequestMsg
206         try {
207             logger.debug("handleClientOpenMsg() - Waiting to receive message");
208             final COPSMsg rmsg = COPSTransceiver.receiveMsg(socket);
209             logger.debug("Received message of type - " + rmsg.getHeader().getOpCode());
210             // Client-Close
211             if (rmsg.getHeader().getOpCode().equals(OPCode.CC)) {
212                 System.out.println(((COPSClientCloseMsg) rmsg)
213                         .getError().getDescription());
214                 // close the socket
215                 final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
216                         new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null);
217                 try {
218                     closeMsg.writeData(conn);
219                 } catch (IOException unae) {
220                     logger.error("Unexpected error writing data", unae);
221                 }
222                 throw new COPSException("CMTS requetsed Client-Close");
223             } else {
224                 // Request
225                 if (rmsg.getHeader().getOpCode().equals(OPCode.REQ)) {
226                     COPSReqMsg rMsg = (COPSReqMsg) rmsg;
227                     _handle = rMsg.getClientHandle();
228                 } else
229                     throw new COPSException("Can't understand request");
230             }
231         } catch (Exception e) { // COPSException, IOException
232             throw new COPSException("Error COPSTransceiver.receiveMsg", e);
233         }
234
235         logger.debug("PDPCOPSConnection");
236         final PCMMPdpConnection pdpConn = new PCMMPdpConnection(_pepId, conn, _process);
237         pdpConn.setKaTimer(getKaTimer());
238         if (getAcctTimer() != 0)
239             pdpConn.setAccTimer(getAcctTimer());
240
241         // XXX - handleRequestMsg
242         // XXX - check handle is valid
243         final PCMMPdpReqStateMan man = new PCMMPdpReqStateMan(getClientType(), _handle.getId().str());
244         pdpConn.addStateMan(_handle.getId().str(), man);
245         man.setDataProcess(_process);
246         try {
247             man.initRequestState(conn);
248         } catch (COPSPdpException unae) {
249             logger.error("Unexpected error initializing state", unae);
250         }
251         // XXX - End handleRequestMsg
252
253         logger.info("Starting PDP connection thread to - " + psHost);
254
255         // TODO - store the thread reference so it is possible to manage.
256         final Thread thread = new Thread(pdpConn, "Agent for - " + psHost);
257         thread.start();
258         threadMap.put(_pepId.getData().str(), thread);
259         _connectionMap.put(_pepId.getData().str(), pdpConn);
260     }
261
262     public Socket getSocket() {
263         return socket;
264     }
265     public PCMMPdpDataProcess getProcess() {
266         return _process;
267     }
268     public COPSHandle getClientHandle() {
269         return _handle;
270     }
271     public String getPepIdString() {
272         return _pepId.getData().str();
273     }
274
275     /*
276      * (non-Javadoc)
277      *
278      * @see org.pcmm.rcd.IPCMMClient#isConnected()
279      */
280     public boolean isConnected() {
281         return socket != null && socket.isConnected();
282     }
283
284
285 }
286