c4debd266ba5b31c06a5477877c5a62b928e354e
[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   * @param engine Codec engine used
377   */
378   Avp(Engine *engine = NULL);
379
380   /**
381   * Identified constructor
382   * @param id Avp identifier as pair (code,vendor-id).
383   * @param engine Codec engine used
384   */
385   Avp(AvpId id, Engine *engine = NULL);
386
387
388   /**
389   * Sets the codec engine
390   *
391   * Once assigned (here or at constructor), this method SHALL NOT be used anymore.
392   * Also, the associated dictionary SHOULD NOT BE CHANGED through the engine,
393   * unless you know what are you doing. If you want to reconfigure the engine,
394   * first #clear the avp and then you could reuse the same object with
395   * different configurations (execution contexts).
396   *
397   * Setting a new different engine with different stack, even same engine where the
398   * stack has been dynamically changed, could cause a bad behaviour depending on the
399   * changes: in general, if the dictionary grows, nothing bad will happen, but if
400   * you remove or modified some elements which were processed with a certain format,
401   * will be interpreted as 'unknown' with the new dictionary, and then some problems
402   * may occur. If you add elements (vendors, avps, messages) is not a problem.
403   */
404   void setEngine(Engine *engine) throw();
405
406
407   // Length references
408   static const int HeaderLengthVactive;
409   static const int HeaderLengthVinactive;
410
411   //    AVP Flags
412   //    +-+-+-+-+-+-+-+-+
413   //    |V M P r r r r r|
414   //    +-+-+-+-+-+-+-+-+
415   //
416   //      V(endor-specific)
417   //      M(andatory)
418   //      (encry)P(tion) (end to end encryption)
419   //      r(eserved)  - these flag bits are reserved for future use, and
420   //                    MUST be set to zero, and ignored by the receiver.
421   static const U8 VBitMask;
422   static const U8 MBitMask;
423   static const U8 PBitMask;
424
425   /**
426   * Destructor
427   */
428   virtual ~Avp();
429
430
431   // setters
432
433   /**
434   * Clears and initializes Avp class information.
435   * Application should clear auxiliary avp objects before setting data in a new context.
436   */
437   void clear() throw(anna::RuntimeException);
438
439
440   /**
441      Sets the avp identifier and clear the former content.
442      Internally reserves memory for data part depending on avp format for the identifier provided.
443      This must be called at first place because Avp class content is cleared when identifier is configured.
444      Generic AVP assignment have no sense and will be ignored.
445
446      @param id Avp identifier as pair (code,vendor-id).
447   */
448   void setId(AvpId id) throw(anna::RuntimeException);
449
450   /**
451      Same as #setId but providing dictionary logical name for Avp searched
452   */
453   void setId(const char *name) throw(anna::RuntimeException);
454
455   /**
456      Sets/unsets M bit activation.
457      Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored.
458      Anyway, could be useful when build unknown-type avps.
459
460      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
461      a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
462      Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
463
464      @param activate Activates/deactivates the bit. True by default.
465   */
466   void setMandatoryBit(bool activate = true) throw() { if(activate) a_flags |= MBitMask; else a_flags &= (~MBitMask); }
467
468   /**
469      Sets/unsets P bit activation.
470      Application should not have to use this because dictionary information is used in order to configure flags when Avp identifier is stored.
471      Anyway, could be useful when build unknown-type avps.
472
473      @param activate Activates/deactivates the bit. True by default.
474   */
475   void setEncryptionBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
476
477
478   /**
479      Adds an avp child providing its identifier and reserve internal memory it.
480      An exception is launched is the Avp over which we add the new avp, is not a grouped avp.
481
482      @param id Avp identifier as pair (code,vendor-id).
483
484      @return Pointer to the new created avp.
485   */
486   Avp * addAvp(AvpId id) throw(anna::RuntimeException) { assertFormat("Grouped"); return addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
487
488
489   /**
490      Same as #addAvp but providing dictionary logical name for Avp searched
491   */
492   Avp * addAvp(const char *name) throw(anna::RuntimeException);
493
494   /**
495      Adds an avp child providing a persistent pointer (must be maintained by application).
496      An exception is launched is the Avp over which we add the new avp, is not a grouped avp.
497      It is not allowed to add an avp with no codec engine configured, neither if the engine
498      is not the same.
499
500      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
501      Also NULL returned for bad engine configuration.
502
503      @return Pointer to the added avp (again).
504   */
505   Avp * addAvp(Avp * avp) throw(anna::RuntimeException);
506
507
508   // Data part access
509   /** Access content for OctetString Avp in order to set data part */
510   OctetString *        getOctetString() throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; }
511   /** Access content for Integer32 Avp in order to set data part */
512   Integer32 *          getInteger32() throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; }
513   /** Access content for Integer64 Avp in order to set data part */
514   Integer64 *          getInteger64() throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; }
515   /** Access content for Unsigned32 Avp in order to set data part */
516   Unsigned32 *         getUnsigned32() throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; }
517   /** Access content for Unsigned64 Avp in order to set data part */
518   Unsigned64 *         getUnsigned64() throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; }
519   /** Access content for Float32 Avp in order to set data part */
520   Float32 *            getFloat32() throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; }
521   /** Access content for Float64 Avp in order to set data part */
522   Float64 *            getFloat64() throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; }
523   /** Access content for Address Avp in order to set data part */
524   Address *            getAddress() throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; }
525   /** Access content for Time Avp in order to set data part */
526   Time *               getTime() throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; }
527   /** Access content for UTF8String Avp in order to set data part */
528   UTF8String *         getUTF8String() throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; }
529   /** Access content for DiameterIdentity Avp in order to set data part */
530   DiameterIdentity *   getDiameterIdentity() throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; }
531   /** Access content for DiameterURI Avp in order to set data part */
532   DiameterURI *        getDiameterURI() throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; }
533   /** Access content for Enumerated Avp in order to set data part */
534   Enumerated *         getEnumerated() throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; }
535   /** Access content for IPFilterRule Avp in order to set data part */
536   IPFilterRule *       getIPFilterRule() throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; }
537   /** Access content for QoSFilterRule Avp in order to set data part */
538   QoSFilterRule *      getQoSFilterRule() throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; }
539   /** Access content for Unknown Avp in order to set data part */
540   Unknown *            getUnknown() throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; }
541
542
543   /**
544      Removes an Avp within grouped type (first level) and free resources.
545
546      @param id Avp identifier (pair code + vendor-id).
547      @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).
548      Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
549
550      @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).
551   */
552   bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { assertFormat("Grouped"); return removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
553
554
555   /**
556      Same as #removeAvp but providing dictionary logical name for Avp searched
557   */
558   bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
559
560   // getters
561
562   /**
563      Gets Avp identifier as pair (code, vendor-id).
564   */
565   const AvpId & getId() const throw() { return a_id; }
566
567   /**
568      Gets Avp vendor-id.
569   */
570   int getVendorId() const throw() { return a_id.second; }
571
572   /**
573      Gets stack avp (dictionary avp reference).
574   */
575   const anna::diameter::stack::Avp *getStackAvp() const throw(anna::RuntimeException) { return getStackAvp(a_id, getEngine()); }
576
577   /** Returns V bit activation state */
578   bool vendorBit() const throw() { return ((a_flags & VBitMask) != 0x00); }
579
580   /** Returns M bit activation state */
581   bool mandatoryBit() const throw() { return ((a_flags & MBitMask) != 0x00); }
582
583   /** Returns P bit activation state */
584   bool encryptionBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
585
586   // Data part access
587   /** Access content for OctetString Avp */
588   const OctetString *        getOctetString() const throw(anna::RuntimeException) { assertFormat("OctetString"); return a_OctetString; }
589   /** Access content for Integer32 Avp */
590   const Integer32 *          getInteger32() const throw(anna::RuntimeException) { assertFormat("Integer32"); return a_Integer32; }
591   /** Access content for Integer64 Avp */
592   const Integer64 *          getInteger64() const throw(anna::RuntimeException) { assertFormat("Integer64"); return a_Integer64; }
593   /** Access content for Unsigned32 Avp */
594   const Unsigned32 *         getUnsigned32() const throw(anna::RuntimeException) { assertFormat("Unsigned32"); return a_Unsigned32; }
595   /** Access content for Unsigned64 Avp */
596   const Unsigned64 *         getUnsigned64() const throw(anna::RuntimeException) { assertFormat("Unsigned64"); return a_Unsigned64; }
597   /** Access content for Float32 Avp */
598   const Float32 *            getFloat32() const throw(anna::RuntimeException) { assertFormat("Float32"); return a_Float32; }
599   /** Access content for Float64 Avp */
600   const Float64 *            getFloat64() const throw(anna::RuntimeException) { assertFormat("Float64"); return a_Float64; }
601
602   /**
603      Access content for Grouped Avp. Exception mode allows different combinations like cascade access:
604      <pre>
605
606         try {
607            message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
608                   ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
609         }
610         catch(anna::RuntimeException) {;}
611      </pre>
612
613      Or step access:
614
615      <pre>
616         const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
617         const Avp *rg;
618         if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
619      </pre>
620
621      Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters.
622      Deleting procedures must use #removeAvp.
623      Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods.
624
625      @param id Avp identifier (pair code + vendor-id).
626      @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse
627      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
628      @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).
629      If avp format is not grouped, always exception will be launched and no matter what mode is provided. It would be a development
630      error and must be solved.
631   */
632   const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
633     return _getAvp(id, ocurrence, emode);
634   }
635
636   Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
637     return const_cast<Avp*>(_getAvp(id, ocurrence, emode));
638   }
639
640   /**
641      Same as #getAvp but providing dictionary logical name for Avp searched
642   */
643   const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
644     return _getAvp(name, ocurrence, emode);
645   }
646
647   Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
648     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
649   }
650
651
652
653   /** Access content for Address Avp */
654   const Address *            getAddress() const throw(anna::RuntimeException) { assertFormat("Address"); return a_Address; }
655   /** Access content for Time Avp */
656   const Time *               getTime() const throw(anna::RuntimeException) { assertFormat("Time"); return a_Time; }
657   /** Access content for UTF8String Avp */
658   const UTF8String *         getUTF8String() const throw(anna::RuntimeException) { assertFormat("UTF8String"); return a_UTF8String; }
659   /** Access content for DiameterIdentity Avp */
660   const DiameterIdentity *   getDiameterIdentity() const throw(anna::RuntimeException) { assertFormat("DiameterIdentity"); return a_DiameterIdentity; }
661   /** Access content for DiameterURI Avp */
662   const DiameterURI *        getDiameterURI() const throw(anna::RuntimeException) { assertFormat("DiameterURI"); return a_DiameterURI; }
663   /** Access content for Enumerated Avp */
664   const Enumerated *         getEnumerated() const throw(anna::RuntimeException) { assertFormat("Enumerated"); return a_Enumerated; }
665   /** Access content for IPFilterRule Avp */
666   const IPFilterRule *       getIPFilterRule() const throw(anna::RuntimeException) { assertFormat("IPFilterRule"); return a_IPFilterRule; }
667   /** Access content for QoSFilterRule Avp */
668   const QoSFilterRule *      getQoSFilterRule() const throw(anna::RuntimeException) { assertFormat("QoSFilterRule"); return a_QoSFilterRule; }
669   /** Access content for Unknown Avp */
670   const Unknown *            getUnknown() const throw(anna::RuntimeException) { assertFormat("Unknown"); return a_Unknown; }
671
672
673   /**
674      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
675      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
676      depending on validation depth (codec::Engine::ValidationDepth).
677
678      Useful as serialization procedure with #code
679
680      @param db Buffer data block processed
681   */
682   void decode(const anna::DataBlock &db) throw(anna::RuntimeException);
683
684
685   /**
686      Interpret xml data in order to dump over the class content.
687
688      \param avpNode Avp root node
689   */
690   void fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException);
691
692
693   /**
694     Encodes buffer with the class content. This method is internally used to encode diameter messages, but is declared as public, to allow
695     its use as serialization procedure. Then, it's assumed that this Avp is valid (validation shall be applied as part of a whole diameter
696     message but nothing will be verified now).
697
698   * @param buffer Raw data to be encoded (shall be externally allocated)
699   * @param size Size of raw data to be encoded
700   */
701   void code(char* buffer, int &size) const throw(anna::RuntimeException);
702
703
704   // Helpers
705
706   /**
707      Class xml representation
708      \param parent Parent XML node on which hold this instance information.
709      \return XML document with relevant information for this instance.
710   */
711   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
712
713   /**
714      Class xml string representation
715      \return XML string representation with relevant information for this instance.
716   */
717   std::string asXMLString() const throw();
718
719   /**
720      Comparison operator by mean serialization
721
722      @param a1 Instance 1 for Avp class
723      @param a2 Instance 2 for Avp class
724
725      @return Comparison result
726   */
727   friend bool operator == (const Avp & a1, const Avp & a2) throw() { return (a1.asXMLString() == a2.asXMLString()); }
728
729   /**
730      Match a regular expression (string pattern) regarding xml string serialization for this avp.
731      This works same as #Message::isLike
732
733      @param pattern Pattern to match
734
735      \return Returns the match result
736   */
737   bool isLike(const std::string &pattern) const throw();
738
739   /**
740      Counts the number of ocurrences of Avps (first level) with the identifier provided
741
742      @param id Avp identifier (pair code + vendor-id).
743   */
744   int countAvp(AvpId id) const throw(anna::RuntimeException) { assertFormat("Grouped"); return countAvp(a_avps, id); }
745
746   /**
747      Same as #countAvp but providing dictionary logical name for Avp searched
748   */
749   int countAvp(const char *name) const throw(anna::RuntimeException);
750
751   /**
752      Counts the number of children within a grouped avp
753
754      @param id Avp identifier (pair code + vendor-id).
755   */
756   int countChilds() const throw(anna::RuntimeException) { assertFormat("Grouped"); return countChilds(a_avps); }
757
758   /**
759      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
760      a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
761      Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
762
763      Default implementation launch alarm and counter indicating the anomaly but don't launch exception (traces at warning level).
764      Relay and Redirect agents could reimplement this method to avoid oam management (another way is avoid alarm/counter registration on
765      these applications). Result-Code DIAMETER_AVP_UNSUPPORTED will be stored for possible answer message.
766   */
767   virtual void unknownAvpWithMandatoryBit() const throw(anna::RuntimeException);
768
769
770   friend class Message;
771   friend class Engine;
772 };
773
774 }
775 }
776 }
777
778
779 #endif