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