3f3a803d98724dd8f0f47a20b314eaf021f3c76a
[packetcable.git] / protocol_plugins.packetcable / src / main / java / org / umu / cops / stack / COPSReqMsg.java
1 /*\r
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
5  */\r
6 \r
7 package org.umu.cops.stack;\r
8 \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
15 \r
16 /**\r
17  * COPS Request Message (RFC 2748 pag. 22)\r
18  *\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
23  *\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
29  *\r
30  *   The format of the Request message is as follows:\r
31  *\r
32  *               <Request Message> ::=  <Common Header>\r
33  *                                      <Client Handle>\r
34  *                                      <Context>\r
35  *                                      [<IN-Int>]\r
36  *                                      [<OUT-Int>]\r
37  *                                      [<ClientSI(s)>]\r
38  *                                      [<LPDPDecision(s)>]\r
39  *                                      [<Integrity>]\r
40  *\r
41  *               <ClientSI(s)> ::= <ClientSI> | <ClientSI(s)> <ClientSI>\r
42  *\r
43  *               <LPDPDecision(s)> ::= <LPDPDecision> |\r
44  *                                     <LPDPDecision(s)> <LPDPDecision>\r
45  *\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
52  *\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
58  *\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
64  *\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
70  *\r
71  *   Finally, LPDPDecision object holds information regarding the local\r
72  *   decision made by the LPDP.\r
73  *\r
74  *   Malformed Request messages MUST result in the PDP specifying a\r
75  *   Decision message with the appropriate error code.\r
76  *\r
77  * @version COPSReqMsg.java, v 1.00 2003\r
78  *\r
79  */\r
80 public class COPSReqMsg extends COPSMsg {\r
81 \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
91 \r
92     public COPSReqMsg() {\r
93         _clientHandle = null;\r
94         _context = null;\r
95         _inInterface = null;\r
96         _outInterface = null;\r
97         _clientSIs = new Vector(20);\r
98         _decisions = new Hashtable();\r
99         _integrity = null;\r
100         _lpdpContext = null;\r
101     }\r
102 \r
103     /**\r
104           Parse data and create COPSReqMsg object\r
105      */\r
106     protected COPSReqMsg(byte[] data) throws COPSException {\r
107         parse(data);\r
108     }\r
109 \r
110     /**\r
111      * Checks the sanity of COPS message and throw an\r
112      * COPSBadDataException when data is bad.\r
113      */\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
117         }\r
118     }\r
119 \r
120     /**\r
121      * Add an IN or OUT interface object\r
122      *\r
123      * @param    inter               a  COPSInterface\r
124      *\r
125      * @throws   COPSException\r
126      *\r
127      */\r
128     public void add (COPSInterface inter) throws COPSException {\r
129         if (!(inter.isInInterface() || inter.isOutInterface()))\r
130             throw new COPSException ("No Interface");\r
131 \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
136 \r
137         if (inter.isInInterface()) {\r
138             if (_inInterface != null)\r
139                 throw new COPSException ("Object inInterface exits");\r
140 \r
141             if (inter.isIpv4Address()) {\r
142                 COPSIpv4InInterface inInter = (COPSIpv4InInterface) inter;\r
143                 _inInterface = inInter;\r
144             } else {\r
145                 COPSIpv6InInterface inInter = (COPSIpv6InInterface) inter;\r
146                 _inInterface = inInter;\r
147             }\r
148         } else {\r
149             if (_outInterface != null)\r
150                 throw new COPSException ("Object outInterface exits");\r
151 \r
152             if (inter.isIpv4Address()) {\r
153                 COPSIpv4OutInterface outInter = (COPSIpv4OutInterface) inter;\r
154                 _outInterface = outInter;\r
155             } else {\r
156                 COPSIpv6OutInterface outInter = (COPSIpv6OutInterface) inter;\r
157                 _outInterface = outInter;\r
158             }\r
159         }\r
160         setMsgLength();\r
161     }\r
162 \r
163     /**\r
164      * Add header to the message\r
165      *\r
166      * @param    hdr                 a  COPSHeader\r
167      *\r
168      * @throws   COPSException\r
169      *\r
170      */\r
171     public void add (COPSHeader hdr) throws COPSException {\r
172         if (hdr == null)\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
176         _hdr = hdr;\r
177         setMsgLength();\r
178     }\r
179 \r
180     /**\r
181      * Add Context object to the message\r
182      *\r
183      * @param    context             a  COPSContext\r
184      *\r
185      * @throws   COPSException\r
186      *\r
187      */\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
192         setMsgLength();\r
193     }\r
194 \r
195     /**\r
196      * Add client handle to the message\r
197      *\r
198      * @param    handle              a  COPSHandle\r
199      *\r
200      * @throws   COPSException\r
201      *\r
202      */\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
207         setMsgLength();\r
208     }\r
209 \r
210     /**\r
211      * Add one or more clientSI objects\r
212      *\r
213      * @param    clientSI            a  COPSClientSI\r
214      *\r
215      * @throws   COPSException\r
216      *\r
217      */\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
222         setMsgLength();\r
223     }\r
224 \r
225     /**\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
228      * message context\r
229      *\r
230      * @param    decision            a  COPSLPDPDecision\r
231      * @param    context             a  COPSContext\r
232      *\r
233      * @throws   COPSException\r
234      *\r
235      */\r
236     public void addLocalDecision(COPSLPDPDecision decision, COPSContext context) throws COPSException {\r
237         if (!decision.isLocalDecision())\r
238             throw new COPSException ("Local Decision");\r
239 \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
244                 //for each context\r
245                 throw new COPSException ("Bad Message format, only one set of decision flags is allowed.");\r
246             }\r
247         } else {\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
253             }\r
254         }\r
255         v.add(decision);\r
256         _decisions.put(context,v);\r
257 \r
258         setMsgLength();\r
259     }\r
260 \r
261     /**\r
262      * Add integrity object\r
263      *\r
264      * @param    integrity           a  COPSIntegrity\r
265      *\r
266      * @throws   COPSException\r
267      *\r
268      */\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
275         setMsgLength();\r
276     }\r
277 \r
278     /**\r
279      * Writes data to given socket\r
280      *\r
281      * @param    id                  a  Socket\r
282      *\r
283      * @throws   IOException\r
284      *\r
285      */\r
286     public void writeData(Socket id) throws IOException {\r
287         // checkSanity();\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
291 \r
292         for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {\r
293             COPSClientSI clientSI = (COPSClientSI) e.nextElement();\r
294             clientSI.writeData(id);\r
295         }\r
296 \r
297         //Display any local decisions\r
298         for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {\r
299 \r
300             COPSContext context = (COPSContext) e.nextElement();\r
301             Vector v = (Vector) _decisions.get(context);\r
302             context.writeData(id);\r
303 \r
304             for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {\r
305                 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();\r
306                 decision.writeData(id);\r
307             }\r
308         }\r
309 \r
310         if (_integrity != null) _integrity.writeData(id);\r
311 \r
312     }\r
313 \r
314     /**\r
315      * Return Header\r
316      *\r
317      * @return   a COPSHeader\r
318      *\r
319      */\r
320     public COPSHeader getHeader() {\r
321         return _hdr;\r
322     }\r
323 \r
324     /**\r
325      * Return client Handle\r
326      *\r
327      * @return   a COPSHandle\r
328      *\r
329      */\r
330     public COPSHandle getClientHandle() {\r
331         return _clientHandle;\r
332     }\r
333 \r
334     /**\r
335      * Return Context\r
336      *\r
337      * @return   a COPSContext\r
338      *\r
339      */\r
340     public COPSContext getContext() {\r
341         return _context;\r
342     }\r
343 \r
344     /**\r
345      * Returns true if it has In Interface\r
346      *\r
347      * @return   a boolean\r
348      *\r
349      */\r
350     public boolean hasInInterface() {\r
351         return (_inInterface == null);\r
352     }\r
353 \r
354     /**\r
355      * Should check hasInInterface() before calling\r
356      *\r
357      * @return   a COPSInterface\r
358      *\r
359      */\r
360     public COPSInterface getInInterface() {\r
361         return _inInterface;\r
362     }\r
363 \r
364     /**\r
365      * Returns true if it has Out interface\r
366      *\r
367      * @return   a boolean\r
368      *\r
369      */\r
370     public boolean hasOutInterface() {\r
371         return (_outInterface == null);\r
372     }\r
373 \r
374     /**\r
375      * Should check hasOutInterface() before calling\r
376      *\r
377      * @return   a COPSInterface\r
378      *\r
379      */\r
380     public COPSInterface getOutInterface() {\r
381         return _outInterface;\r
382     }\r
383 \r
384     /**\r
385      * Returns a vector if ClientSI objects\r
386      *\r
387      * @return   a Vector\r
388      *\r
389      */\r
390     public Vector getClientSI() {\r
391         return _clientSIs;\r
392     }\r
393 \r
394     /**\r
395      * Returns a HashTable of any local decisions\r
396      *\r
397      * @return   a Hashtable\r
398      *\r
399      */\r
400     public Hashtable getLpdpDecisions() {\r
401         return _decisions;\r
402     }\r
403 \r
404     /**\r
405      * Returns true if it has Integrity object\r
406      *\r
407      * @return   a boolean\r
408      *\r
409      */\r
410     public boolean hasIntegrity() {\r
411         return (_integrity == null);\r
412     }\r
413 \r
414     /**\r
415      * Get Integrity. Should check hasIntegrity() becfore calling\r
416      *\r
417      * @return   a COPSIntegrity\r
418      *\r
419      */\r
420     public COPSIntegrity getIntegrity() {\r
421         return _integrity;\r
422     }\r
423 \r
424     /**\r
425      * Parses the data and fills COPSReqMsg with its constituents\r
426      *\r
427      * @param    data                a  byte[]\r
428      *\r
429      * @throws   COPSException\r
430      *\r
431      */\r
432     protected void parse(byte[] data) throws COPSException {\r
433         super.parseHeader(data);\r
434 \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
438 \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
444             }\r
445             break;\r
446             case COPSObjHeader.COPS_CONTEXT: {\r
447                 if (_context == null) {\r
448                     //Message context\r
449                     _context = new COPSContext(buf);\r
450                     _dataStart += _context.getDataLength();\r
451                 } else {\r
452                     //lpdp context\r
453                     _lpdpContext = new COPSContext(buf);\r
454                     _dataStart += _lpdpContext.getDataLength();\r
455                 }\r
456             }\r
457             break;\r
458             case COPSObjHeader.COPS_ININTF: {\r
459                 if (objHdr.getCType() == 1) {\r
460                     _inInterface = new COPSIpv4InInterface(buf);\r
461                 } else {\r
462                     _inInterface = new COPSIpv6InInterface(buf);\r
463                 }\r
464                 _dataStart += _inInterface.getDataLength();\r
465             }\r
466             break;\r
467             case COPSObjHeader.COPS_OUTINTF: {\r
468                 if (objHdr.getCType() == 1) {\r
469                     _outInterface = new COPSIpv4OutInterface(buf);\r
470                 } else {\r
471                     _outInterface = new COPSIpv6OutInterface(buf);\r
472                 }\r
473                 _dataStart += _outInterface.getDataLength();\r
474             }\r
475             break;\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
480             }\r
481             break;\r
482             case COPSObjHeader.COPS_CSI: {\r
483                 COPSClientSI csi = new COPSClientSI (buf);\r
484                 _dataStart += csi.getDataLength();\r
485                 _clientSIs.add(csi);\r
486             }\r
487             break;\r
488             case COPSObjHeader.COPS_MSG_INTEGRITY: {\r
489                 _integrity = new COPSIntegrity(buf);\r
490                 _dataStart += _integrity.getDataLength();\r
491             }\r
492             break;\r
493             default: {\r
494                 throw new COPSException("Bad Message format, unknown object type");\r
495             }\r
496             }\r
497         }\r
498         checkSanity();\r
499 \r
500     }\r
501 \r
502     /**\r
503      * Parses the data and fills that follows the header hdr and fills COPSReqMsg\r
504      *\r
505      * @param    hdr                 a  COPSHeader\r
506      * @param    data                a  byte[]\r
507      *\r
508      * @throws   COPSException\r
509      *\r
510      */\r
511     protected void parse(COPSHeader hdr, byte[] data) throws COPSException {\r
512         _hdr = hdr;\r
513         parse(data);\r
514         setMsgLength();\r
515     }\r
516 \r
517     /**\r
518      * Set the message length, base on the set of objects it contains\r
519      *\r
520      * @throws   COPSException\r
521      *\r
522      */\r
523     protected void setMsgLength() throws COPSException {\r
524         short len = 0;\r
525 \r
526         if (_clientHandle != null)\r
527             len += _clientHandle.getDataLength();\r
528 \r
529         if (_context != null)\r
530             len += _context.getDataLength();\r
531 \r
532         for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {\r
533             COPSClientSI clientSI = (COPSClientSI) e.nextElement();\r
534             len += clientSI.getDataLength();\r
535         }\r
536 \r
537         //Display any local decisions\r
538         for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {\r
539 \r
540             COPSContext context = (COPSContext) e.nextElement();\r
541             Vector v = (Vector) _decisions.get(context);\r
542             len += context.getDataLength();\r
543 \r
544             for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {\r
545                 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();\r
546                 len += decision.getDataLength();\r
547             }\r
548         }\r
549 \r
550         if (_integrity != null) {\r
551             len += _integrity.getDataLength();\r
552         }\r
553 \r
554         _hdr.setMsgLength((int) len);\r
555 \r
556     }\r
557 \r
558     /**\r
559      * Write an object textual description in the output stream\r
560      *\r
561      * @param    os                  an OutputStream\r
562      *\r
563      * @throws   IOException\r
564      *\r
565      */\r
566     public void dump(OutputStream os) throws IOException {\r
567         _hdr.dump(os);\r
568 \r
569         if (_clientHandle != null)\r
570             _clientHandle.dump(os);\r
571 \r
572         if (_context != null)\r
573             _context.dump(os);\r
574 \r
575         for (Enumeration e = _clientSIs.elements() ; e.hasMoreElements() ;) {\r
576             COPSClientSI clientSI = (COPSClientSI) e.nextElement();\r
577             clientSI.dump(os);\r
578         }\r
579 \r
580         //Display any local decisions\r
581         for (Enumeration e = _decisions.keys() ; e.hasMoreElements() ;) {\r
582 \r
583             COPSContext context = (COPSContext) e.nextElement();\r
584             Vector v = (Vector) _decisions.get(context);\r
585             context.dump(os);\r
586 \r
587             for (Enumeration ee = v.elements() ; e.hasMoreElements() ;) {\r
588                 COPSLPDPDecision decision = (COPSLPDPDecision) ee.nextElement();\r
589                 decision.dump(os);\r
590             }\r
591         }\r
592 \r
593         if (_integrity != null) {\r
594             _integrity.dump(os);\r
595         }\r
596     }\r
597 }\r
598 \r