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