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