8d840266c6dfdce4a16c131a448b8ccc6eb76aa9
[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 {
85         // Create Socket and send OPN
86         final InetAddress addr = InetAddress.getByName(psHost);
87         socket = new Socket(addr, psPort);
88         logger.debug("{} {}", getClass().getName(), "PDP Socket Opened");
89
90         // We're waiting for an message
91         try {
92             logger.debug("Waiting to receiveMsg");
93             final COPSMsg msg = COPSTransceiver.receiveMsg(socket);
94             logger.debug("Message received of type - " + msg.getHeader().getOpCode());
95             if (msg.getHeader().getOpCode().equals(OPCode.OPN)) {
96                 handleClientOpenMsg(socket, msg);
97             } else {
98                 try {
99                     socket.close();
100                 } catch (Exception ex) {
101                     logger.error("Unexpected error closing socket", ex);
102                 }
103             }
104         } catch (Exception e) {
105             logger.error("Unexpected error handing client open message", e);
106             try {
107                 socket.close();
108             } catch (Exception ex) {
109                 logger.error("Unexpected error closing socket", ex);
110             }
111             return true;
112         }
113
114         return false;
115     }
116
117     // TODO - remove and let super handle after DataProcess & PdpConnection classes are properly refactored
118     @Override
119     public void disconnect (final String pepID, final COPSError error) throws COPSException, IOException {
120         final PCMMPdpConnection pdpConn = (PCMMPdpConnection) _connectionMap.get(pepID);
121         if (pdpConn != null) {
122             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(), error, null, null);
123             closeMsg.writeData(pdpConn.getSocket());
124             pdpConn.close();
125         }
126
127         final Thread thread = threadMap.remove(pepID);
128         if (thread != null) thread.interrupt();
129     }
130
131     // TODO - this method should be broken apart into smaller pieces.
132     @Override
133     protected void handleClientOpenMsg(final Socket conn, final COPSMsg msg) throws COPSException, IOException {
134         logger.info("Processing client open message");
135         final COPSClientOpenMsg cMsg = (COPSClientOpenMsg) msg;
136         _pepId = cMsg.getPepId();
137
138         // Validate Client Type
139         if (msg.getHeader().getClientType() != getClientType()) {
140             // Unsupported client type
141             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
142                     new COPSError(ErrorTypes.UNSUPPORTED_CLIENT_TYPE, ErrorTypes.NA), null, null);
143             try {
144                 closeMsg.writeData(conn);
145             } catch (IOException unae) {
146                 logger.error("Unexpected error writing data", unae);
147             }
148
149             throw new COPSException("Unsupported client type");
150         }
151
152         // PEPId is mandatory
153         if (_pepId == null) {
154             // Mandatory COPS object missing
155             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
156                     new COPSError(ErrorTypes.MANDATORY_OBJECT_MISSING, ErrorTypes.NA), null, null);
157             try {
158                 closeMsg.writeData(conn);
159             } catch (IOException unae) {
160                 logger.error("Unexpected error closing socket", unae);
161             }
162
163             throw new COPSException("Mandatory COPS object missing (PEPId)");
164         }
165
166         // Support
167         if ((cMsg.getClientSI() != null) ) {
168             final MMVersionInfo _mminfo = new MMVersionInfo(cMsg.getClientSI().getData().getData());
169             logger.debug("CMTS sent MMVersion info : major:" + _mminfo.getMajorVersionNB() + "  minor:" +
170                     _mminfo.getMinorVersionNB());
171
172         } else {
173             // Unsupported objects
174             final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
175                     new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null);
176             try {
177                 closeMsg.writeData(conn);
178             } catch (IOException unae) {
179                 logger.error("Unexpected error writing data", unae);
180             }
181
182             throw new COPSException("Unsupported objects (PdpAddress, Integrity)");
183         }
184         /*
185         */
186
187         // Connection accepted
188         final COPSClientAcceptMsg acceptMsg;
189         if (getAcctTimer() != 0)
190             acceptMsg = new COPSClientAcceptMsg(getClientType(), new COPSKATimer(getKaTimer()),
191                     new COPSAcctTimer(getAcctTimer()), null);
192         else
193             acceptMsg = new COPSClientAcceptMsg(getClientType(), new COPSKATimer(getKaTimer()), null, null);
194         acceptMsg.writeData(conn);
195         // XXX - handleRequestMsg
196         try {
197             logger.debug("handleClientOpenMsg() - Waiting to receive message");
198             final COPSMsg rmsg = COPSTransceiver.receiveMsg(socket);
199             logger.debug("Received message of type - " + rmsg.getHeader().getOpCode());
200             // Client-Close
201             if (rmsg.getHeader().getOpCode().equals(OPCode.CC)) {
202                 System.out.println(((COPSClientCloseMsg) rmsg)
203                         .getError().getDescription());
204                 // close the socket
205                 final COPSClientCloseMsg closeMsg = new COPSClientCloseMsg(getClientType(),
206                         new COPSError(ErrorTypes.UNKNOWN_OBJECT, ErrorTypes.NA), null, null);
207                 try {
208                     closeMsg.writeData(conn);
209                 } catch (IOException unae) {
210                     logger.error("Unexpected error writing data", unae);
211                 }
212                 throw new COPSException("CMTS requetsed Client-Close");
213             } else {
214                 // Request
215                 if (rmsg.getHeader().getOpCode().equals(OPCode.REQ)) {
216                     COPSReqMsg rMsg = (COPSReqMsg) rmsg;
217                     _handle = rMsg.getClientHandle();
218                 } else
219                     throw new COPSException("Can't understand request");
220             }
221         } catch (Exception e) { // COPSException, IOException
222             throw new COPSException("Error COPSTransceiver.receiveMsg", e);
223         }
224
225         logger.debug("PDPCOPSConnection");
226         final PCMMPdpConnection pdpConn = new PCMMPdpConnection(_pepId, conn, _process, getKaTimer(), getAcctTimer());
227
228         // XXX - handleRequestMsg
229         // XXX - check handle is valid
230         final PCMMPdpReqStateMan man = new PCMMPdpReqStateMan(getClientType(), _handle, _process);
231         pdpConn.addStateMan(_handle, man);
232         try {
233             man.initRequestState(conn);
234         } catch (COPSPdpException unae) {
235             logger.error("Unexpected error initializing state", unae);
236         }
237         // XXX - End handleRequestMsg
238
239         logger.info("Starting PDP connection thread to - " + psHost);
240
241         // TODO - store the thread reference so it is possible to manage.
242         final Thread thread = new Thread(pdpConn, "Agent for - " + psHost);
243         thread.start();
244         threadMap.put(_pepId.getData().str(), thread);
245         _connectionMap.put(_pepId.getData().str(), pdpConn);
246     }
247
248     public Socket getSocket() {
249         return socket;
250     }
251
252     public COPSHandle getClientHandle() {
253         return _handle;
254     }
255
256     public String getPepIdString() {
257         return _pepId.getData().str();
258     }
259
260 }
261