First commit
[anna.git] / include / anna / diameter / codec / Avp.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_diameter_codec_Avp_hpp
38 #define anna_diameter_codec_Avp_hpp
39
40
41 // Local
42 #include <anna/config/defines.hpp>
43 #include <anna/diameter/defines.hpp>
44 #include <anna/diameter/codec/basetypes/basetypes.hpp>
45 #include <anna/diameter/stack/Avp.hpp>
46 #include <anna/diameter/helpers/tme/codectypes/codectypes.hpp>
47
48 #include <anna/core/RuntimeException.hpp>
49
50 // STL
51 #include <string>
52 #include <map>
53
54 //------------------------------------------------------------------------------
55 //---------------------------------------------------------------------- #define
56 //------------------------------------------------------------------------------
57
58 namespace anna {
59
60 class DataBlock;
61
62 namespace xml {
63 class Node;
64 class Attribute;
65 }
66 }
67
68 namespace anna {
69
70 namespace diameter {
71
72
73 namespace helpers {
74 namespace tme {
75 namespace codectypes {
76 class Unsigned16;
77 class ISDNNumber;
78 class ISDNAddress;
79 }
80 }
81 }
82
83
84 namespace stack {
85 class Dictionary;
86 class Format;
87 class Avp;
88 }
89
90 namespace codec {
91
92 namespace basetypes {
93 class OctetString;
94 class Integer32;
95 class Integer64;
96 class Unsigned32;
97 class Unsigned64;
98 class Float32;
99 class Float64;
100 class Address;
101 class Time;
102 class UTF8String;
103 class DiameterIdentity;
104 class DiameterURI;
105 class Enumerated;
106 class IPFilterRule;
107 class QoSFilterRule;
108 class Unknown;
109 }
110
111 class Avp;
112 class Message;
113 class Engine;
114
115
116 typedef std::map < int /* key: insertion pos */, Avp* > avp_container;
117 typedef avp_container::iterator avp_iterator;
118 typedef avp_container::const_iterator const_avp_iterator;
119
120 // Cache avp-find system
121 typedef std::pair < AvpId, unsigned int /* position */ > find_key;
122 typedef std::map<find_key, Avp*> find_container;
123 typedef std::map<find_key, Avp*>::iterator find_iterator;
124
125
126 using namespace basetypes;
127 using namespace helpers::tme::codectypes;
128
129 /**
130 * Diameter avp generic container
131 * <pre>
132 *    RFC 3588                Diameter Based Protocol           September 2003
133 *    4.1.  AVP Header
134 *
135 *       The fields in the AVP header MUST be sent in network byte order.  The
136 *       format of the header is:
137 *
138 *        0                   1                   2                   3
139 *        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
140 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141 *       |                           AVP Code                            |
142 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143 *       |   AVP Flags   |                  AVP Length                   |
144 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
145 *       |                        Vendor-ID (opt)                        |
146 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147 *       |    Data ...
148 *       +-+-+-+-+-+-+-+-+
149 *
150 *
151 *        AVP Flags: V (vendor-specific), M (mandatory), P (end to end encryption)
152 *        +-+-+-+-+-+-+-+-+
153 *        |V M P r r r r r|
154 *        +-+-+-+-+-+-+-+-+
155 *
156 *        AVP Length
157 *        The AVP Length field is three octets, and indicates the number of
158 *        octets in this AVP including the AVP Code, AVP Length, AVP Flags,
159 *        Vendor-ID field (if present) and the AVP data.
160 *
161 *        Vendor-ID: IANA "SMI Network Management Private Enterprise Codes" [ASSIGNNO]
162 *                   http://www.iana.org/assignments/enterprise-numbers
163 * </pre>
164 */
165 class Avp {
166
167   AvpId a_id;          // code and vendor-code
168   U8 a_flags;
169
170   // auxiliary
171   int a_insertionPositionForChilds; // used at grouped type
172
173
174   // --- Developer notes ---
175   // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length'
176   // is the difference between 'AVP Length' and sum of code, length, flags and
177   // optionally the vendor-ID (all of them are 32-bit boundary), that is to say:
178   // 8 or 12 (vendor-specific avps).
179   //
180   // Grouped avps 'AVP Length' includes own headers plus the total length of all
181   //  underlying AVPs, including their headers and padding, then 'AVP Length' is
182   //  always multiple of 4 (library will check this), and smae for 'Data Length'
183   //  which is an 'whole avp Length with padding' itself.
184
185   // Data containers
186   OctetString *a_OctetString;
187   Integer32 *a_Integer32;
188   Integer64 *a_Integer64;
189   Unsigned32 *a_Unsigned32;
190   Unsigned64 *a_Unsigned64;
191   Float32 *a_Float32;
192   Float64 *a_Float64;
193   avp_container a_avps; // Grouped
194   Address *a_Address;
195   Time *a_Time;
196   UTF8String *a_UTF8String;
197   DiameterIdentity *a_DiameterIdentity;
198   DiameterURI *a_DiameterURI;
199   Enumerated *a_Enumerated;
200   IPFilterRule *a_IPFilterRule;
201   QoSFilterRule *a_QoSFilterRule;
202   Unknown *a_Unknown;
203
204   // Derived formats ////////////////////////////////////////////
205   /* TME */
206   ISDNNumber *a_ISDNNumber;
207   ISDNAddress *a_ISDNAddress;
208   Unsigned16 *a_Unsigned16;
209
210
211
212   // Grouped helpers
213   find_container a_finds; // fast access for grouped and message first-level avps
214
215
216   // Static functions are used when you want a function that is the same for every instance of a class. Such functions do not have access
217   //  to "this" pointer and thus cannot access any non static fields. They are used often when you want a function that can be used without
218   //  instantiating the class. Friend functions are functions which are not in the class and you want to give them access to private members
219   //  of your class.
220
221   // Common (also for Message class)
222   static avp_iterator avp_find(avp_container &avps, AvpId id, unsigned int position) throw();
223   static const_avp_iterator avp_find(const avp_container &avps, AvpId id, unsigned int position) throw() {
224     return (const_avp_iterator)avp_find((avp_container &)avps, id, position);
225   }
226   static Avp * addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw();
227   static bool removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw();
228   static void fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw();
229   static bool validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const std::string & parentDescription, Message *answer) throw(anna::RuntimeException); // validates mandatory/fixed and cardinality
230   static const Avp* getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException);
231   static int countAvp(const avp_container &avps, AvpId id) throw();
232   static const Avp* firstAvp(const avp_container &avps, AvpId id) throw();
233   static int countChilds(const avp_container &avps) throw();
234   static int addChild(avp_container &avps, int &insertionPositionForChilds, Avp *avp) throw() {
235     if(!avp) return -1;
236
237     avps[insertionPositionForChilds++] = avp;
238     return insertionPositionForChilds;
239   }
240   static const anna::diameter::stack::Avp *getStackAvp(AvpId id, Engine *engine) throw();
241   const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException);
242   const Avp* _getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException);
243
244   // Own
245   avp_iterator avp_begin() throw() { return a_avps.begin(); }
246   avp_iterator avp_end() throw() { return a_avps.end(); }
247   static Avp* avp(avp_iterator ii) throw() { return ii->second; }
248   const_avp_iterator avp_begin() const throw() { return a_avps.begin(); }
249   const_avp_iterator avp_end() const throw() { return a_avps.end(); }
250   static const Avp* avp(const_avp_iterator ii) throw() { return ii->second; }
251
252   // Internal
253   void assertFormat(const std::string &name) const throw(anna::RuntimeException);
254   bool flagsOK() const throw(); // flags coherence regarding dictionary. Only must be called when AVP is identified at the dictionary.
255   int addChild(Avp *avp) throw(anna::RuntimeException) { assertFormat("Grouped"); return addChild(a_avps, a_insertionPositionForChilds, avp); }
256   bool hasChildren() throw() { return a_avps.size() != 0; }
257
258   static bool contain(const_avp_iterator begin, const_avp_iterator end, const Avp *parent) throw() { return true; }
259
260
261   /**
262      Fix grouped content regarding dictionary avp positions.
263      Avp could remain invalid because of possible fixed/mandatory avps.
264      This is useful to give flexibility to the application during message construction before encoding or representing the data.
265      Is not recommended to fix a recently decoded message because possible validation problems will be hidden.
266   */
267   void fix() throw();
268
269   /**
270      Validates an Avp regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
271
272      @param parentDescription Parent description. Internally used for alarms and tracing
273      @param answer Answer could be modified with any validation problem during requests validation
274
275      @return Boolean indicating validation result
276   */
277   bool valid(const std::string & parentDescription, Message *answer) const throw(anna::RuntimeException);
278
279   /**
280      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
281      message is valid against all odds then validation will go on). In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
282      depending on validation depth (codec::Engine::ValidationDepth).
283
284      @param db Buffer data block processed
285      @param answer Answer built for request decoding/validation
286   */
287   void decode(const anna::DataBlock &db, Message *answer) throw(anna::RuntimeException);
288
289
290   /////////////////////////////////////////////
291   // Inherit format-specific virtual methods //
292   /////////////////////////////////////////////
293
294   /**
295   * Initializes Avp class information.
296   * Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
297   * Diameter basic formats are managed at #initialize, which will invoke this method at the end.
298   */
299   virtual void initializeByFormat() throw();
300
301   /**
302   * Gets avp data-part length.
303   * Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
304   * Diameter basic formats are managed at #initialize, which will invoke this method at the end.
305   *
306   * @param stackFormat Stack avp format in which data extraction is based.
307   *
308   * @return Avp data-part size.
309   */
310   virtual U24 getLengthByFormat(const anna::diameter::stack::Format *stackFormat) const throw();
311
312   /**
313      Gets data or hexadecimal data depending on avp format, for xml creating
314      Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
315      Diameter basic formats are managed at #initialize, which will invoke this method at the end.
316
317      \param isHex Hexadecimal/Natural data when apply.
318      \param stackFormat Stack avp format in which data extraction is based.
319      \return xml data representation
320   */
321   virtual std::string getXMLdataByFormat(bool & isHex, const anna::diameter::stack::Format *stackFormat) const throw();
322
323   /**
324      Interpret xml data in order to dump over the class content.
325      Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
326      Diameter basic formats are managed at #initialize, which will invoke this method at the end.
327
328      \param data Avp data attribute
329      \param hexData Avp hex-data attribute
330      \param stackFormat Stack avp format in which data extraction is based.
331   */
332   virtual void fromXMLByFormat(const anna::xml::Attribute* data, const anna::xml::Attribute* hexData, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException);
333
334
335   /**
336      Encodes buffer with the class content.
337      Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
338      Diameter basic formats are managed at #initialize, which will invoke this method at the end.
339
340      @param dataPart Data-part begin pointer
341      @param stackFormat Stack avp format in which data extraction is based.
342   */
343   virtual void codeByFormat(char* dataPart, const anna::diameter::stack::Format *stackFormat) const throw(anna::RuntimeException);
344
345
346   /**
347      Decodes Avp data part.
348      Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
349      Diameter basic formats are managed at #initialize, which will invoke this method at the end.
350
351      @param buffer Avp data part start pointer
352      @param size Avp data part size
353      @param stackFormat Stack avp format in which data extraction is based.
354   */
355   virtual void decodeDataPartByFormat(const char * buffer, int size, const anna::diameter::stack::Format *stackFormat) throw(anna::RuntimeException);
356
357   /**
358      Reserves memory for data part depending on avp format for the identifier provided.
359      Default implementation supports all anna::diameter formats (including i.e. tme.db ones).
360      Diameter basic formats are managed at #initialize, which will invoke this method at the end.
361
362      @param stackFormat Stack avp format in which data extraction is based.
363   */
364   virtual void allocationByFormat(const anna::diameter::stack::Format *stackFormat) throw();
365
366   /**
367   * Clears Avp data-part format containers.
368   */
369   virtual void clearByFormat() throw();
370
371
372
373 protected:
374
375   /** Codec Engine */
376   mutable Engine *a_engine;
377
378   /** Codec Engine getter: avoids have to create base engine when using its child */
379   virtual Engine * getEngine() const throw(anna::RuntimeException);
380
381   /**
382   * Initializes Avp class information.
383   */
384   void initialize() throw();
385
386
387   /**
388   * Gets avp total length based on internal data part and header configuration.
389   * Padding octets are not included, only header and data part length.
390   * The only format which always have total length equal to sum of all its parts is Grouped,
391   * because of the 4-multiple nature of its data part length.
392   */
393   U24 getLength() const throw();
394
395   /**
396      Gets data or hexadecimal data depending on avp format, for xml creating
397
398      \param isHex Hexadecimal/Natural data when apply.
399      \param stackFormat Stack avp format in which data extraction is based.
400      \return xml data representation
401   */
402   std::string getXMLdata(bool & isHex, const anna::diameter::stack::Format *stackFormat) const throw();
403
404   /**
405      Interpret xml data in order to dump over the class content.
406
407      \param avpNode Avp root node
408   */
409   void fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException);
410
411
412   /**
413      Encodes buffer with the class content.
414
415   * @param buffer Raw data to be encoded
416   * @param size Size of raw data to be encoded
417   */
418   void code(char* buffer, int &size) const throw(anna::RuntimeException);
419
420
421   /**
422      Decodes Avp data part.
423
424      @param buffer Avp data part start pointer
425      @param size Avp data part size
426      @param answer Answer built for request decoding/validation
427   */
428   void decodeDataPart(const char * buffer, int size, Message *answer) throw(anna::RuntimeException);
429
430
431 public:
432
433   /**
434   * Default constructor
435   */
436   Avp();
437
438   /**
439   * Identified constructor
440   * @param id Avp identifier as pair (code,vendor-id).
441   */
442   Avp(AvpId id);
443
444
445   // Length references
446   static const int HeaderLengthVactive;
447   static const int HeaderLengthVinactive;
448
449   //    AVP Flags
450   //    +-+-+-+-+-+-+-+-+
451   //    |V M P r r r r r|
452   //    +-+-+-+-+-+-+-+-+
453   //
454   //      V(endor-specific)
455   //      M(andatory)
456   //      (encry)P(tion) (end to end encryption)
457   //      r(eserved)  - these flag bits are reserved for future use, and
458   //                    MUST be set to zero, and ignored by the receiver.
459   static const U8 VBitMask;
460   static const U8 MBitMask;
461   static const U8 PBitMask;
462
463   /**
464   * Destructor
465   */
466   ~Avp();
467
468
469   // setters
470
471   /**
472   * Clears and initializes Avp class information.
473   * Application should clear auxiliary avp objects before setting data in a new context.
474   */
475   void clear() throw(anna::RuntimeException);
476
477
478   /**
479      Sets the avp identifier and clear the former content.
480      Internally reserves memory for data part depending on avp format for the identifier provided.
481      This must be called at first place because Avp class content is cleared when identifier is configured.
482      Generic AVP assignment have no sense and will be ignored.
483
484      @param id Avp identifier as pair (code,vendor-id).
485   */
486   void setId(AvpId id) throw(anna::RuntimeException);
487
488   /**
489      Same as #setId but providing dictionary logical name for Avp searched
490   */
491   void setId(const char *name) throw(anna::RuntimeException);
492
493   /**
494      Sets/unsets M bit activation.
495      Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored.
496      Anyway, could be useful when build unknown-type avps.
497
498      The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by
499      a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
500      Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
501
502      @param activate Activates/deactivates the bit. True by default.
503   */
504   void setMandatoryBit(bool activate = true) throw() { if(activate) a_flags |= MBitMask; else a_flags &= (~MBitMask); }
505
506   /**
507      Sets/unsets P bit activation.
508      Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored.
509      Anyway, could be useful when build unknown-type avps.
510
511      @param activate Activates/deactivates the bit. True by default.
512   */
513   void setEncryptionBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
514
515
516   /**
517      Adds an avp child providing its identifier and reserve internal memory it.
518      An exception is launched is the Avp is not a grouped avp.
519
520      @param id Avp identifier as pair (code,vendor-id).
521
522      @return Pointer to the new created avp.
523   */
524   Avp * addAvp(AvpId id) throw(anna::RuntimeException) { assertFormat("Grouped"); return addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
525
526
527   /**
528      Same as #addAvp but providing dictionary logical name for Avp searched
529   */
530   Avp * addAvp(const char *name) throw(anna::RuntimeException);
531
532
533   /**
534      Adds an avp child providing a persistent pointer (must be maintained by application).
535      An exception is launched is the Avp is not a grouped avp.
536
537      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
538
539      @return Pointer to the added avp (again).
540   */
541   Avp * addAvp(Avp * avp) throw(anna::RuntimeException) { if(!avp) return NULL; addChild(avp); return avp; }
542
543   // Data part access
544   /** Access content for OctetString Avp in order to set data part */
545   OctetString *        getOctetString() throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; }
546   /** Access content for Integer32 Avp in order to set data part */
547   Integer32 *          getInteger32() throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; }
548   /** Access content for Integer64 Avp in order to set data part */
549   Integer64 *          getInteger64() throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; }
550   /** Access content for Unsigned32 Avp in order to set data part */
551   Unsigned32 *         getUnsigned32() throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; }
552   /** Access content for Unsigned64 Avp in order to set data part */
553   Unsigned64 *         getUnsigned64() throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; }
554   /** Access content for Float32 Avp in order to set data part */
555   Float32 *            getFloat32() throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; }
556   /** Access content for Float64 Avp in order to set data part */
557   Float64 *            getFloat64() throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; }
558   /** Access content for Address Avp in order to set data part */
559   Address *            getAddress() throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; }
560   /** Access content for Time Avp in order to set data part */
561   Time *               getTime() throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; }
562   /** Access content for UTF8String Avp in order to set data part */
563   UTF8String *         getUTF8String() throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; }
564   /** Access content for DiameterIdentity Avp in order to set data part */
565   DiameterIdentity *   getDiameterIdentity() throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; }
566   /** Access content for DiameterURI Avp in order to set data part */
567   DiameterURI *        getDiameterURI() throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; }
568   /** Access content for Enumerated Avp in order to set data part */
569   Enumerated *         getEnumerated() throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; }
570   /** Access content for IPFilterRule Avp in order to set data part */
571   IPFilterRule *       getIPFilterRule() throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; }
572   /** Access content for QoSFilterRule Avp in order to set data part */
573   QoSFilterRule *      getQoSFilterRule() throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; }
574   /** Access content for Unknown Avp in order to set data part */
575   Unknown *            getUnknown() throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; }
576
577   // Derived formats ////////////////////////////////////////////
578   /* TME */
579   /** Access content for ISDNNumber Avp in order to set data part */
580   ISDNNumber *        getISDNNumber() throw(anna::RuntimeException) { assertFormat("ISDNNumber"); return a_ISDNNumber; }
581   /** Access content for ISDNAddress Avp in order to set data part */
582   ISDNAddress *        getISDNAddress() throw(anna::RuntimeException) { assertFormat("ISDNAddress"); return a_ISDNAddress; }
583   /** Access content for Unsigned16 Avp in order to set data part */
584   Unsigned16 *        getUnsigned16() throw(anna::RuntimeException) { assertFormat("Unsigned16"); return a_Unsigned16; }
585
586
587   /**
588      Removes an Avp within grouped type (first level) and free resources.
589
590      @param id Avp identifier (pair code + vendor-id).
591      @param ocurrence Order of appearance for the searched avp. Zero value means remove all avps with provided identifier at first level (no recursiveness would be allowed in the API in order to avoid unexpected behaviour).
592      Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
593
594      @return Returns true if something was removed. False in other cases (including i.e. when this Avp is empty or is not a grouped avp).
595   */
596   bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { assertFormat("Grouped"); return removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
597
598
599   /**
600      Same as #removeAvp but providing dictionary logical name for Avp searched
601   */
602   bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
603
604   // getters
605
606   /**
607      Gets Avp identifier as pair (code, vendor-id).
608   */
609   const AvpId & getId() const throw() { return a_id; }
610
611   /**
612      Gets Avp vendor-id.
613   */
614   int getVendorId() const throw() { return a_id.second; }
615
616   /**
617      Gets stack avp (dictionary avp reference).
618   */
619   const anna::diameter::stack::Avp *getStackAvp() const throw(anna::RuntimeException) { return getStackAvp(a_id, getEngine()); }
620
621   /** Returns V bit activation state */
622   bool vendorBit() const throw() { return ((a_flags & VBitMask) != 0x00); }
623
624   /** Returns M bit activation state */
625   bool mandatoryBit() const throw() { return ((a_flags & MBitMask) != 0x00); }
626
627   /** Returns P bit activation state */
628   bool encryptionBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
629
630   // Data part access
631   /** Access content for OctetString Avp */
632   const OctetString *        getOctetString() const throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; }
633   /** Access content for Integer32 Avp */
634   const Integer32 *          getInteger32() const throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; }
635   /** Access content for Integer64 Avp */
636   const Integer64 *          getInteger64() const throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; }
637   /** Access content for Unsigned32 Avp */
638   const Unsigned32 *         getUnsigned32() const throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; }
639   /** Access content for Unsigned64 Avp */
640   const Unsigned64 *         getUnsigned64() const throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; }
641   /** Access content for Float32 Avp */
642   const Float32 *            getFloat32() const throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; }
643   /** Access content for Float64 Avp */
644   const Float64 *            getFloat64() const throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; }
645
646   /**
647      Access content for Grouped Avp. Exception mode allows different combinations like cascade access:
648      <pre>
649
650         try {
651            message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
652                   ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
653         }
654         catch(anna::RuntimeException) {;}
655      </pre>
656
657      Or step access:
658
659      <pre>
660         const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
661         const Avp *rg;
662         if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
663      </pre>
664
665      Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters.
666      Deleting procedures must use #removeAvp.
667      Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods.
668
669      @param id Avp identifier (pair code + vendor-id).
670      @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse
671      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
672      @param emode Excepcion mode handling when avp is not found: Ignore (no action is taken but debug trace), Throw (excepcion launched, by default), Trace (trace warning).
673      If avp format is not grouped, always exception will be launched and no matter what mode is provided. It would be a development
674      error and must be solved.
675   */
676   const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
677     return _getAvp(id, ocurrence, emode);
678   }
679
680   Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
681     return const_cast<Avp*>(_getAvp(id, ocurrence, emode));
682   }
683
684   /**
685      Same as #getAvp but providing dictionary logical name for Avp searched
686   */
687   const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
688     return _getAvp(name, ocurrence, emode);
689   }
690
691   Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
692     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
693   }
694
695
696
697   /** Access content for Address Avp */
698   const Address *            getAddress() const throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; }
699   /** Access content for Time Avp */
700   const Time *               getTime() const throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; }
701   /** Access content for UTF8String Avp */
702   const UTF8String *         getUTF8String() const throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; }
703   /** Access content for DiameterIdentity Avp */
704   const DiameterIdentity *   getDiameterIdentity() const throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; }
705   /** Access content for DiameterURI Avp */
706   const DiameterURI *        getDiameterURI() const throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; }
707   /** Access content for Enumerated Avp */
708   const Enumerated *         getEnumerated() const throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; }
709   /** Access content for IPFilterRule Avp */
710   const IPFilterRule *       getIPFilterRule() const throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; }
711   /** Access content for QoSFilterRule Avp */
712   const QoSFilterRule *      getQoSFilterRule() const throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; }
713   /** Access content for Unknown Avp */
714   const Unknown *            getUnknown() const throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; }
715
716
717   // Derived formats ////////////////////////////////////////////
718   /* TME */
719   /** Access content for ISDNNumber Avp */
720   const ISDNNumber *         getISDNNumber() const throw(anna::RuntimeException) { assertFormat("ISDNNumber"); return a_ISDNNumber; }
721   /** Access content for ISDNAddress Avp */
722   const ISDNAddress *        getISDNAddress() const throw(anna::RuntimeException) { assertFormat("ISDNAddress"); return a_ISDNAddress; }
723   /** Access content for Unsigned16 Avp */
724   const Unsigned16 *        getUnsigned16() const throw(anna::RuntimeException) { assertFormat("Unsigned16"); return a_Unsigned16; }
725
726
727   // Helpers
728
729   /**
730      Class xml representation
731      \param parent Parent XML node on which hold this instance information.
732      \return XML document with relevant information for this instance.
733   */
734   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
735
736   /**
737      Class xml string representation
738      \return XML string representation with relevant information for this instance.
739   */
740   std::string asXMLString() const throw();
741
742   /**
743      Counts the number of ocurrences of Avps (first level) with the identifier provided
744
745      @param id Avp identifier (pair code + vendor-id).
746   */
747   int countAvp(AvpId id) const throw(anna::RuntimeException) { assertFormat("Grouped"); return countAvp(a_avps, id); }
748
749   /**
750      Same as #countAvp but providing dictionary logical name for Avp searched
751   */
752   int countAvp(const char *name) const throw(anna::RuntimeException);
753
754   /**
755      Counts the number of children within a grouped avp
756
757      @param id Avp identifier (pair code + vendor-id).
758   */
759   int countChilds() const throw(anna::RuntimeException) { assertFormat("Grouped"); return countChilds(a_avps); }
760
761   /**
762      The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by
763      a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
764      Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
765
766      Default implementation launch alarm and counter indicating the anomaly but don't launch exception (traces at warning level).
767      Realy and Redirect agents could reimplement this method to avoid oam management (another way is avoid alarm/counter registration on
768      these applications). Result-Code DIAMETER_AVP_UNSUPPORTED will be stored for possible answer message.
769
770      @param answer Answer built for request decoding/validation
771   */
772   virtual void unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException);
773
774
775   friend class Message;
776   friend class Engine;
777 };
778
779 }
780 }
781 }
782
783
784 #endif