2 * Copyright (c) 2003 University of Murcia. All rights reserved.
\r
3 * --------------------------------------------------------------
\r
4 * For more information, please see <http://www.umu.euro6ix.org/>.
\r
7 package org.umu.cops.stack;
\r
9 import java.io.IOException;
\r
10 import java.io.OutputStream;
\r
11 import java.net.Socket;
\r
12 import java.util.Enumeration;
\r
13 import java.util.Hashtable;
\r
14 import java.util.Vector;
\r
17 * COPS Request Message (RFC 2748 pag. 22)
\r
19 * The PEP establishes a request state client handle for which the
\r
20 * remote PDP may maintain state. The remote PDP then uses this handle
\r
21 * to refer to the exchanged information and decisions communicated over
\r
22 * the TCP connection to a particular PEP for a given client-type.
\r
24 * Once a stateful handle is established for a new request, any
\r
25 * subsequent modifications of the request can be made using the REQ
\r
26 * message specifying the previously installed handle. The PEP is
\r
27 * responsible for notifying the PDP whenever its local state changes so
\r
28 * the PDP's state will be able to accurately mirror the PEP's state.
\r
30 * The format of the Request message is as follows:
\r
32 * <Request Message> ::= <Common Header>
\r
38 * [<LPDPDecision(s)>]
\r
41 * <ClientSI(s)> ::= <ClientSI> | <ClientSI(s)> <ClientSI>
\r
43 * <LPDPDecision(s)> ::= <LPDPDecision> |
\r
44 * <LPDPDecision(s)> <LPDPDecision>
\r
46 * <LPDPDecision> ::= [<Context>]
\r
47 * <LPDPDecision: Flags>
\r
48 * [<LPDPDecision: Stateless Data>]
\r
49 * [<LPDPDecision: Replacement Data>]
\r
50 * [<LPDPDecision: ClientSI Data>]
\r
51 * [<LPDPDecision: Named Data>]
\r
53 * The context object is used to determine the context within which all
\r
54 * the other objects are to be interpreted. It also is used to determine
\r
55 * the kind of decision to be returned from the policy server. This
\r
56 * decision might be related to admission control, resource allocation,
\r
57 * object forwarding and substitution, or configuration.
\r
59 * The interface objects are used to determine the corresponding
\r
60 * interface on which a signaling protocol message was received or is
\r
61 * about to be sent. They are typically used if the client is
\r
62 * participating along the path of a signaling protocol or if the client
\r
63 * is requesting configuration data for a particular interface.
\r
65 * ClientSI, the client specific information object, holds the client-
\r
66 * type specific data for which a policy decision needs to be made. In
\r
67 * the case of configuration, the Named ClientSI may include named
\r
68 * information about the module, interface, or functionality to be
\r
69 * configured. The ordering of multiple ClientSIs is not important.
\r
71 * Finally, LPDPDecision object holds information regarding the local
\r
72 * decision made by the LPDP.
\r
74 * Malformed Request messages MUST result in the PDP specifying a
\r
75 * Decision message with the appropriate error code.
\r
77 * @version COPSReqMsg.java, v 1.00 2003
\r
80 public class COPSReqMsg extends COPSMsg {
\r
82 /* COPSHeader coming from base class */
\r
83 private COPSHandle _clientHandle;
\r
84 private COPSContext _context;
\r
85 private COPSInterface _inInterface;
\r
86 private COPSInterface _outInterface;
\r
87 private Vector _clientSIs;
\r
88 private Hashtable _decisions;
\r
89 private COPSIntegrity _integrity;
\r
90 private COPSContext _lpdpContext;
\r
92 public COPSReqMsg() {
\r
93 _clientHandle = null;
\r
95 _inInterface = null;
\r
96 _outInterface = null;
\r
97 _clientSIs = new Vector(20);
\r
98 _decisions = new Hashtable();
\r
100 _lpdpContext = null;
\r
104 Parse data and create COPSReqMsg object
\r
106 protected COPSReqMsg(byte[] data) throws COPSException {
\r
111 * Checks the sanity of COPS message and throw an
\r
112 * COPSBadDataException when data is bad.
\r
114 public void checkSanity() throws COPSException {
\r
115 if ((_hdr == null) || (_clientHandle == null) || (_context == null)) {
\r
116 throw new COPSException("Bad message format");
\r
121 * Add an IN or OUT interface object
\r
123 * @param inter a COPSInterface
\r
125 * @throws COPSException
\r
128 public void add (COPSInterface inter) throws COPSException {
\r
129 if (!(inter.isInInterface() || inter.isOutInterface()))
\r
130 throw new COPSException ("No Interface");
\r
132 //Message integrity object should be the very last one
\r
133 //If it is already added
\r
134 if (_integrity != null)
\r
135 throw new COPSException ("Integrity should be the last one");
\r
137 if (inter.isInInterface()) {
\r
138 if (_inInterface != null)
\r
139 throw new COPSException ("Object inInterface exits");
\r
141 if (inter.isIpv4Address()) {
\r
142 COPSIpv4InInterface inInter = (COPSIpv4InInterface) inter;
\r
143 _inInterface = inInter;
\r
145 COPSIpv6InInterface inInter = (COPSIpv6InInterface) inter;
\r
146 _inInterface = inInter;
\r
149 if (_outInterface != null)
\r
150 throw new COPSException ("Object outInterface exits");
\r
152 if (inter.isIpv4Address()) {
\r
153 COPSIpv4OutInterface outInter = (COPSIpv4OutInterface) inter;
\r
154 _outInterface = outInter;
\r
156 COPSIpv6OutInterface outInter = (COPSIpv6OutInterface) inter;
\r
157 _outInterface = outInter;
\r
164 * Add header to the message
\r
166 * @param hdr a COPSHeader
\r
168 * @throws COPSException
\r
171 public void add (COPSHeader hdr) throws COPSException {
\r
173 throw new COPSException ("Null Header");
\r
174 if (hdr.getOpCode() != COPSHeader.COPS_OP_REQ)
\r
175 throw new COPSException ("Error Header (no COPS_OP_REQ)");
\r
181 * Add Context object to the message
\r
183 * @param context a COPSContext
\r
185 * @throws COPSException
\r
188 public void add (COPSContext context) throws COPSException {
\r
189 if (context == null)
\r
190 throw new COPSException ("Null Context");
\r
191 _context = context;
\r
196 * Add client handle to the message
\r
198 * @param handle a COPSHandle
\r
200 * @throws COPSException
\r
203 public void add (COPSHandle handle) throws COPSException {
\r
204 if (handle == null)
\r
205 throw new COPSException ("Null Handle");
\r
206 _clientHandle = handle;
\r
211 * Add one or more clientSI objects
\r
213 * @param clientSI a COPSClientSI
\r
215 * @throws COPSException
\r
218 public void add (COPSClientSI clientSI) throws COPSException {
\r
219 if (clientSI == null)
\r
220 throw new COPSException ("Null ClientSI");
\r
221 _clientSIs.add(clientSI);
\r
226 * Add one or more local decision object for a given decision context
\r
227 * the context is optional, if null all decision object are tided to
\r
230 * @param decision a COPSLPDPDecision
\r
231 * @param context a COPSContext
\r
233 * @throws COPSException
\r
236 public void addLocalDecision(COPSLPDPDecision decision, COPSContext context) throws COPSException {
\r
237 if (!decision.isLocalDecision())
\r
238 throw new COPSException ("Local Decision");
\r
240 Vector v = (Vector) _decisions.get(context);
\r
241 if (decision.isFlagSet()) {
\r
242 if (v.size() != 0) {
\r
243 //Only one set of decision flags is allowed
\r
245 throw new COPSException ("Bad Message format, only one set of decision flags is allowed.");
\r
248 if (v.size() == 0) {
\r
249 //The flags decision must precede any other
\r
250 //decision message, since the decision is not
\r
251 //flags throw exception
\r
252 throw new COPSException ("Bad Message format, flags decision must precede any other decision object.");
\r
256 _decisions.put(context,v);
\r
262 * Add integrity object
\r
264 * @param integrity a COPSIntegrity
\r
266 * @throws COPSException
\r
269 public void add (COPSIntegrity integrity) throws COPSException {
\r
270 if (integrity == null)
\r
271 throw new COPSException ("Null Integrity");
\r
272 if (!integrity.isMessageIntegrity())
\r
273 throw new COPSException ("Error Integrity");
\r
274 _integrity = integrity;
\r
279 * Writes data to given socket
\r
281 * @param id a Socket
\r
283 * @throws IOException
\r
286 public void writeData(Socket id) throws IOException {
\r
288 if (_hdr != null) _hdr.writeData(id);
\r
289 if (_clientHandle != null) _clientHandle.writeData(id);
\r
290 if (_context != null) _context.writeData(id);
\r
292 for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {
\r
293 COPSClientSI clientSI = (COPSClientSI) e.nextElement();
\r
294 clientSI.writeData(id);
\r
297 //Display any local decisions
\r
298 for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {
\r
300 COPSContext context = (COPSContext) e.nextElement();
\r
301 Vector v = (Vector) _decisions.get(context);
\r
302 context.writeData(id);
\r
304 for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {
\r
305 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();
\r
306 decision.writeData(id);
\r
310 if (_integrity != null) _integrity.writeData(id);
\r
317 * @return a COPSHeader
\r
320 public COPSHeader getHeader() {
\r
325 * Return client Handle
\r
327 * @return a COPSHandle
\r
330 public COPSHandle getClientHandle() {
\r
331 return _clientHandle;
\r
337 * @return a COPSContext
\r
340 public COPSContext getContext() {
\r
345 * Returns true if it has In Interface
\r
347 * @return a boolean
\r
350 public boolean hasInInterface() {
\r
351 return (_inInterface == null);
\r
355 * Should check hasInInterface() before calling
\r
357 * @return a COPSInterface
\r
360 public COPSInterface getInInterface() {
\r
361 return _inInterface;
\r
365 * Returns true if it has Out interface
\r
367 * @return a boolean
\r
370 public boolean hasOutInterface() {
\r
371 return (_outInterface == null);
\r
375 * Should check hasOutInterface() before calling
\r
377 * @return a COPSInterface
\r
380 public COPSInterface getOutInterface() {
\r
381 return _outInterface;
\r
385 * Returns a vector if ClientSI objects
\r
390 public Vector getClientSI() {
\r
395 * Returns a HashTable of any local decisions
\r
397 * @return a Hashtable
\r
400 public Hashtable getLpdpDecisions() {
\r
405 * Returns true if it has Integrity object
\r
407 * @return a boolean
\r
410 public boolean hasIntegrity() {
\r
411 return (_integrity == null);
\r
415 * Get Integrity. Should check hasIntegrity() becfore calling
\r
417 * @return a COPSIntegrity
\r
420 public COPSIntegrity getIntegrity() {
\r
425 * Parses the data and fills COPSReqMsg with its constituents
\r
427 * @param data a byte[]
\r
429 * @throws COPSException
\r
432 protected void parse(byte[] data) throws COPSException {
\r
433 super.parseHeader(data);
\r
435 while (_dataStart < _dataLength) {
\r
436 byte[] buf = new byte[data.length - _dataStart];
\r
437 System.arraycopy(data,_dataStart,buf,0,data.length - _dataStart);
\r
439 COPSObjHeader objHdr = new COPSObjHeader (buf);
\r
440 switch (objHdr.getCNum()) {
\r
441 case COPSObjHeader.COPS_HANDLE: {
\r
442 _clientHandle = new COPSHandle(buf);
\r
443 _dataStart += _clientHandle.getDataLength();
\r
446 case COPSObjHeader.COPS_CONTEXT: {
\r
447 if (_context == null) {
\r
449 _context = new COPSContext(buf);
\r
450 _dataStart += _context.getDataLength();
\r
453 _lpdpContext = new COPSContext(buf);
\r
454 _dataStart += _lpdpContext.getDataLength();
\r
458 case COPSObjHeader.COPS_ININTF: {
\r
459 if (objHdr.getCType() == 1) {
\r
460 _inInterface = new COPSIpv4InInterface(buf);
\r
462 _inInterface = new COPSIpv6InInterface(buf);
\r
464 _dataStart += _inInterface.getDataLength();
\r
467 case COPSObjHeader.COPS_OUTINTF: {
\r
468 if (objHdr.getCType() == 1) {
\r
469 _outInterface = new COPSIpv4OutInterface(buf);
\r
471 _outInterface = new COPSIpv6OutInterface(buf);
\r
473 _dataStart += _outInterface.getDataLength();
\r
476 case COPSObjHeader.COPS_LPDP_DEC: {
\r
477 COPSLPDPDecision lpdp = new COPSLPDPDecision(buf);
\r
478 _dataStart += lpdp.getDataLength();
\r
479 addLocalDecision(lpdp, _lpdpContext);
\r
482 case COPSObjHeader.COPS_CSI: {
\r
483 COPSClientSI csi = new COPSClientSI (buf);
\r
484 _dataStart += csi.getDataLength();
\r
485 _clientSIs.add(csi);
\r
488 case COPSObjHeader.COPS_MSG_INTEGRITY: {
\r
489 _integrity = new COPSIntegrity(buf);
\r
490 _dataStart += _integrity.getDataLength();
\r
494 throw new COPSException("Bad Message format, unknown object type");
\r
503 * Parses the data and fills that follows the header hdr and fills COPSReqMsg
\r
505 * @param hdr a COPSHeader
\r
506 * @param data a byte[]
\r
508 * @throws COPSException
\r
511 protected void parse(COPSHeader hdr, byte[] data) throws COPSException {
\r
518 * Set the message length, base on the set of objects it contains
\r
520 * @throws COPSException
\r
523 protected void setMsgLength() throws COPSException {
\r
526 if (_clientHandle != null)
\r
527 len += _clientHandle.getDataLength();
\r
529 if (_context != null)
\r
530 len += _context.getDataLength();
\r
532 for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {
\r
533 COPSClientSI clientSI = (COPSClientSI) e.nextElement();
\r
534 len += clientSI.getDataLength();
\r
537 //Display any local decisions
\r
538 for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {
\r
540 COPSContext context = (COPSContext) e.nextElement();
\r
541 Vector v = (Vector) _decisions.get(context);
\r
542 len += context.getDataLength();
\r
544 for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {
\r
545 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();
\r
546 len += decision.getDataLength();
\r
550 if (_integrity != null) {
\r
551 len += _integrity.getDataLength();
\r
554 _hdr.setMsgLength((int) len);
\r
559 * Write an object textual description in the output stream
\r
561 * @param os an OutputStream
\r
563 * @throws IOException
\r
566 public void dump(OutputStream os) throws IOException {
\r
569 if (_clientHandle != null)
\r
570 _clientHandle.dump(os);
\r
572 if (_context != null)
\r
575 for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {
\r
576 COPSClientSI clientSI = (COPSClientSI) e.nextElement();
\r
580 //Display any local decisions
\r
581 for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {
\r
583 COPSContext context = (COPSContext) e.nextElement();
\r
584 Vector v = (Vector) _decisions.get(context);
\r
587 for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {
\r
588 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();
\r
593 if (_integrity != null) {
\r
594 _integrity.dump(os);
\r