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