pcapDecoder allows .hex files as input. Make public some Avp methods for serializatio...
[anna.git] / source / diameter / codec / Avp.cpp
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 // Local
38 #include <anna/diameter/codec/Avp.hpp>
39 #include <anna/diameter/codec/Format.hpp>
40
41 #include <anna/config/defines.hpp> // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc.
42 #include <anna/diameter/functions.hpp>
43 #include <anna/diameter/helpers/defines.hpp>
44 #include <anna/diameter/codec/basetypes/basetypes.hpp>
45 #include <anna/diameter/codec/functions.hpp> // REQUIRED_WORDS
46 #include <anna/diameter/codec/OamModule.hpp>
47 #include <anna/diameter/stack/Avp.hpp>
48 #include <anna/diameter/stack/Format.hpp>
49 #include <anna/diameter/stack/Dictionary.hpp>
50 #include <anna/diameter/stack/Engine.hpp>
51 #include <anna/diameter/codec/Engine.hpp>
52 #include <anna/core/functions.hpp>
53 #include <anna/core/util/RegularExpression.hpp>
54
55 #include <anna/core/tracing/Logger.hpp>
56 #include <anna/core/functions.hpp>
57 #include <anna/core/tracing/TraceMethod.hpp>
58 #include <anna/xml/xml.hpp>
59
60 // STL
61 #include <map>
62
63
64 using namespace anna;
65 using namespace anna::diameter::codec;
66
67
68 //static
69 namespace anna {
70
71 namespace diameter {
72
73 namespace codec {
74 const int Avp::HeaderLengthVactive(12);
75 const int Avp::HeaderLengthVinactive(8);
76 const U8 Avp::VBitMask(0x80);
77 const U8 Avp::MBitMask(0x40);
78 const U8 Avp::PBitMask(0x20);
79 }
80 }
81 }
82
83 //------------------------------------------------------------------------------
84 //------------------------------------------------------------------- Avp::Avp()
85 //------------------------------------------------------------------------------
86 Avp::Avp() {
87   initialize();
88 }
89
90
91 //------------------------------------------------------------------------------
92 //------------------------------------------------------------------- Avp::Avp()
93 //------------------------------------------------------------------------------
94 Avp::Avp(AvpId id) {
95   initialize();
96   setId(id);
97 }
98
99
100 //------------------------------------------------------------------------------
101 //------------------------------------------------------------------ Avp::~Avp()
102 //------------------------------------------------------------------------------
103 Avp::~Avp() {
104   clear();
105 }
106
107
108 //------------------------------------------------------------------------------
109 //------------------------------------------------------------- Avp::getEngine()
110 //------------------------------------------------------------------------------
111 Engine * Avp::getEngine() const throw(anna::RuntimeException) {
112   return a_engine ? a_engine : (a_engine = anna::functions::component <Engine> (ANNA_FILE_LOCATION));
113 }
114
115
116 //------------------------------------------------------------------------------
117 //------------------------------------------------------------ Avp::initialize()
118 //------------------------------------------------------------------------------
119 void Avp::initialize() throw() {
120   a_engine = NULL;
121   a_id = helpers::AVPID__AVP; // (0,0)
122   a_flags = 0x00;
123   a_insertionPositionForChilds = 0;
124   a_OctetString = NULL;
125   a_Integer32 = NULL;
126   a_Integer64 = NULL;
127   a_Unsigned32 = NULL;
128   a_Unsigned64 = NULL;
129   a_Float32 = NULL;
130   a_Float64 = NULL;
131   //a_avps.clear();
132   a_Address = NULL;
133   a_Time = NULL;
134   a_UTF8String = NULL;
135   a_DiameterIdentity = NULL;
136   a_DiameterURI = NULL;
137   a_Enumerated = NULL;
138   a_IPFilterRule = NULL;
139   a_QoSFilterRule = NULL;
140   a_Unknown = NULL;
141   //a_finds.clear();
142   /////////////////////
143   // Format specific //
144   /////////////////////
145   initializeByFormat();
146 }
147
148
149 //------------------------------------------------------------------------------
150 //----------------------------------------------------------------- Avp::clear()
151 //------------------------------------------------------------------------------
152 void Avp::clear() throw(anna::RuntimeException) {
153   delete a_OctetString;
154   delete a_Integer32;
155   delete a_Integer64;
156   delete a_Unsigned32;
157   delete a_Unsigned64;
158   delete a_Float32;
159   delete a_Float64;
160
161   for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(avp(it)); }
162
163   a_avps.clear();
164   delete a_Address;
165   delete a_Time;
166   delete a_UTF8String;
167   delete a_DiameterIdentity;
168   delete a_DiameterURI;
169   delete a_Enumerated;
170   delete a_IPFilterRule;
171   delete a_QoSFilterRule;
172   delete a_Unknown;
173   // Cache system:
174   a_finds.clear();
175   /////////////////////
176   // Format specific //
177   /////////////////////
178   clearByFormat();
179   // Initialize:
180   initialize();
181 }
182
183
184 //------------------------------------------------------------------------------
185 //-------------------------------------------------------------- Avp::avp_find()
186 //------------------------------------------------------------------------------
187 avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() {
188   int match = 0;
189   Avp *aux;
190
191   for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
192     aux = (*it).second;
193
194     if(aux && (aux->getId() == id)) {
195       match++;
196
197       if(match == position) return it;
198     }
199   }
200
201   return avps.end();
202 }
203
204
205 //------------------------------------------------------------------------------
206 //---------------------------------------------------------------- Avp::addAvp()
207 //------------------------------------------------------------------------------
208 Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() {
209   Avp * result = engine->allocateAvp();
210   result->setId(id);
211   addChild(avps, insertionPositionForChilds, result);
212   return result;
213 }
214
215
216 //------------------------------------------------------------------------------
217 //------------------------------------------------------------- Avp::removeAvp()
218 //------------------------------------------------------------------------------
219 bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() {
220   bool removed = false;
221   bool do_remove = true;
222   int position = ocurrence;
223
224   if(position < 0) {  /* reversed access */
225     position = countAvp(avps, id) + 1 + position;
226
227     // Special cases -> 0 and negative results:
228     // (1) User wants to remove the last, but no avp is found: position = 0 + 1 - 1 = 0 (would removes all but, no avp will be found: return now)
229     // (2) User wants to remove some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (would removes all !!!: return to avoid unexpected behaviour)
230     // (2) User wants to remove some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
231     if(position <= 0) do_remove = false;
232   }
233
234   if(do_remove) {
235     int n = position ? position : 1 /* will search always the first and remove, the first and remove, the first and remove ... */;
236     avp_iterator it;
237
238     while((it = avp_find(avps, id, n)) != avps.end()) {
239       engine->releaseAvp((*it).second);
240       avps.erase(it);
241       removed = true;
242
243       if(position) break;
244     }
245   }
246
247   if(removed) {
248     // Cache system reset (remove will invalidate cached findings):
249     finds.clear();
250     LOGDEBUG(
251       const stack::Avp *stackAvp = getStackAvp(id, engine);
252       std::string msg = "Removed Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
253       msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
254       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
255     );
256   } else {
257     LOGDEBUG(
258       const stack::Avp *stackAvp = getStackAvp(id, engine);
259       std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
260       msg += anna::functions::asString(" with provided ocurrence (%d), in order to be removed", ocurrence);
261       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
262     );
263   }
264
265   return removed;
266 }
267
268
269 //------------------------------------------------------------------------------
270 //-------------------------------------------------------------- Avp::countAvp()
271 //------------------------------------------------------------------------------
272 int Avp::countAvp(const avp_container &avps, AvpId id) throw() {
273   int result = 0;
274   const_avp_iterator it;
275
276   while((it = avp_find(avps, id, result + 1)) != avps.end()) result++;
277
278   return result;
279 }
280
281
282 //------------------------------------------------------------------------------
283 //-------------------------------------------------------------- Avp::firstAvp()
284 //------------------------------------------------------------------------------
285 const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() {
286   const_avp_iterator it = avp_find(avps, id, 1);
287
288   if(it != avps.end())
289     return (*it).second;
290
291   return NULL;
292 }
293
294
295 //------------------------------------------------------------------------------
296 //----------------------------------------------------------- Avp::countChilds()
297 //------------------------------------------------------------------------------
298 int Avp::countChilds(const avp_container &avps) throw() {
299   return avps.size();
300 }
301
302
303 //------------------------------------------------------------------------------
304 //---------------------------------------------------------------- Avp::getAvp()
305 //------------------------------------------------------------------------------
306 const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
307   if(ocurrence == 0) {
308     LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION));
309     return NULL;
310   }
311
312   bool do_search = true;
313   bool cached;
314   int position = ocurrence;
315
316   if(position < 0) {  /* reversed access */
317     position = countAvp(avps, id) + 1 + position;
318
319     // Special cases -> 0 and negative results:
320     // (1) User wants to get the last, but no avp is found: position = 0 + 1 - 1 = 0 (can't find 0-position ...)
321     // (2) User wants to get some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (can't find 0-position ...)
322     // (2) User wants to get some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
323     if(position <= 0) do_search = false;
324   }
325
326   const Avp * result = NULL;
327
328   if(do_search) {
329     // Search at cache finds:
330     find_key key(id, position);
331     find_iterator fit = finds.find(key);
332     cached = (fit != finds.end());
333
334     if(cached) {
335       result = (*fit).second;
336     } else {
337       const_avp_iterator it = avp_find(avps, id, position);
338
339       if(it != avps.end()) {
340         result = (*it).second;
341         finds[key] = const_cast<Avp*>(result); // store in cache
342       }
343     }
344   }
345
346   // Avp found:
347   if(result) {
348     LOGDEBUG(
349       const stack::Avp *stackAvp = getStackAvp(id, engine);
350       std::string msg = "Found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
351       msg += anna::functions::asString(" with provided ocurrence (%d) which was ", ocurrence);
352       msg += cached ? "already cached:\n" : "the first search, now cached:\n";
353       msg += result->asXMLString();
354       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
355     );
356     return result;
357   }
358
359   // Avp not found:
360   switch(emode) {
361   case anna::Exception::Mode::Throw: {
362     const stack::Avp *stackAvp = getStackAvp(id, engine);
363     std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
364     msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
365     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
366     break;
367   }
368   case anna::Exception::Mode::Trace: {
369     LOGWARNING(
370       const stack::Avp *stackAvp = getStackAvp(id, engine);
371       std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
372       msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
373       anna::Logger::warning(msg, ANNA_FILE_LOCATION);
374     );
375     break;
376   }
377   case anna::Exception::Mode::Ignore: {
378     LOGDEBUG(
379       const stack::Avp *stackAvp = getStackAvp(id, engine);
380       std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
381       msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
382       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
383     );
384     break;
385   }
386   }
387
388   return NULL;
389 }
390
391
392 //------------------------------------------------------------------------------
393 //--------------------------------------------------------------- Avp::_getAvp()
394 //------------------------------------------------------------------------------
395 const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
396   // Dictionary stack avp and format (this):
397   const stack::Avp *stackAvp = getStackAvp();
398   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
399
400   if(!stackFormat || !stackFormat->isGrouped())
401     throw anna::RuntimeException("This method only applies over grouped avps.", ANNA_FILE_LOCATION);
402
403   return getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
404 }
405
406
407 //------------------------------------------------------------------------------
408 //---------------------------------------------------------- Avp::assertFormat()
409 //------------------------------------------------------------------------------
410 void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) {
411   // Dictionary stack avp and format:
412   const stack::Avp *stackAvp = getStackAvp();
413   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
414   std::string format = stackFormat ? stackFormat->getName() : "Unknown";
415
416   if(format != name) {
417     std::string msg = "The Avp ";
418     msg += anna::diameter::functions::avpIdAsPairString(a_id);
419     msg += " with format '";
420     msg += format;
421     msg += "' is not compatible with the API method used (";
422     msg += name;
423     msg += ")";
424     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
425   }
426 }
427
428
429 //------------------------------------------------------------------------------
430 //--------------------------------------------------------------- Avp::flagsOK()
431 //------------------------------------------------------------------------------
432 bool Avp::flagsOK() const throw() {
433   // Dictionary stack avp:
434   const stack::Avp *stackAvp = getStackAvp();
435
436   if(!stackAvp) {
437     anna::Logger::error("Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok", ANNA_FILE_LOCATION);
438     return true;
439   };
440
441   // Assignments
442   bool Vnone = (stackAvp->getVbit() == stack::Avp::FlagRule::None);
443
444   bool Vmust = (stackAvp->getVbit() == stack::Avp::FlagRule::must);
445
446   bool Vmustnot = (stackAvp->getVbit() == stack::Avp::FlagRule::mustnot);
447
448   bool Mnone = (stackAvp->getMbit() == stack::Avp::FlagRule::None);
449
450   bool Mmust = (stackAvp->getMbit() == stack::Avp::FlagRule::must);
451
452   bool Mmustnot = (stackAvp->getMbit() == stack::Avp::FlagRule::mustnot);
453
454   bool Pnone = (stackAvp->getPbit() == stack::Avp::FlagRule::None);
455
456   bool Pmust = (stackAvp->getPbit() == stack::Avp::FlagRule::must);
457
458   bool Pmustnot = (stackAvp->getPbit() == stack::Avp::FlagRule::mustnot);
459
460   // V-bit
461   if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) {
462     anna::Logger::error("Vendor Bit (V) incoherence found", ANNA_FILE_LOCATION);
463     return false;
464   }
465
466   // Exit on permissive mode:
467   if(getEngine()->ignoreFlagsOnValidation()) return true;  // Ignore checking for AVP 'M' & 'P' bits
468
469   // M-bit
470   if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) {
471     anna::Logger::error("Mandatory Bit (M) incoherence found", ANNA_FILE_LOCATION);
472     return false;
473   }
474
475   // P-bit
476   if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) {
477     anna::Logger::error("Encryption Bit (P) incoherence found", ANNA_FILE_LOCATION);
478     return false;
479   }
480
481   // Reserved bits
482   if((a_flags & 0x1f) != 0x00) {
483     anna::Logger::error("Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION);
484     return false;
485   }
486
487   return true;
488 }
489
490
491 //------------------------------------------------------------------------------
492 //----------------------------------------------------------------- Avp::setId()
493 //------------------------------------------------------------------------------
494 void Avp::setId(AvpId id) throw(anna::RuntimeException) {
495   // Generic AVP assignment has no sense
496   if(id == helpers::AVPID__AVP) return;
497
498   // Clear class content:
499   clear();
500   // Id assignment:
501   a_id = id;
502   // Dictionary stack avp and format:
503   const stack::Avp *stackAvp = getStackAvp(); // based on dictionary and a_id
504   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
505
506   // Dictionary flags for known types:
507   if(stackAvp) {
508     if(stackAvp->getVbit() == stack::Avp::FlagRule::must) a_flags |= VBitMask;
509
510     if(stackAvp->getMbit() == stack::Avp::FlagRule::must) a_flags |= MBitMask;
511
512     if(stackAvp->getPbit() == stack::Avp::FlagRule::must) a_flags |= PBitMask;
513   } else {
514     if(a_id.second != 0) a_flags |= VBitMask; else a_flags &= (~VBitMask);
515   }
516
517   if(!stackFormat) {  // Unknown Avp
518     LOGDEBUG(
519       std::string msg = "Unknown format for AVP identifier ";
520       msg += anna::diameter::functions::avpIdAsPairString(id);
521       msg += ". Raw data without specific format will be managed";
522       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
523     );
524     a_Unknown = new Unknown();
525     return;
526   }
527
528   // Avp class formats (Avp child classes should implement this source code block for application-specific formats):
529   if(stackFormat->isOctetString()) a_OctetString = new OctetString();
530   else if(stackFormat->isInteger32()) a_Integer32 = new Integer32();
531   else if(stackFormat->isInteger64()) a_Integer64 = new Integer64();
532   else if(stackFormat->isUnsigned32()) a_Unsigned32 = new Unsigned32();
533   else if(stackFormat->isUnsigned64()) a_Unsigned64 = new Unsigned64();
534   else if(stackFormat->isFloat32()) a_Float32 = new Float32();
535   else if(stackFormat->isFloat64()) a_Float64 = new Float64();
536   //else if (stackFormat->isGrouped())
537   else if(stackFormat->isAddress()) a_Address = new Address();
538   else if(stackFormat->isTime()) a_Time = new Time();
539   else if(stackFormat->isUTF8String()) a_UTF8String = new UTF8String();
540   else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity = new DiameterIdentity();
541   else if(stackFormat->isDiameterURI()) a_DiameterURI = new DiameterURI();
542   else if(stackFormat->isEnumerated()) a_Enumerated = new Enumerated();
543   else if(stackFormat->isIPFilterRule()) a_IPFilterRule = new IPFilterRule();
544   else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule = new QoSFilterRule();
545
546   /////////////////////
547   // Format specific //
548   /////////////////////
549   allocationByFormat(stackFormat);
550 }
551
552
553 //------------------------------------------------------------------------------
554 //----------------------------------------------------------------- Avp::setId()
555 //------------------------------------------------------------------------------
556 void Avp::setId(const char *name) throw(anna::RuntimeException) {
557   setId(getEngine()->avpIdForName(name));
558 }
559
560
561 //------------------------------------------------------------------------------
562 //---------------------------------------------------------------- Avp::addAvp()
563 //------------------------------------------------------------------------------
564 Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) {
565   return addAvp(getEngine()->avpIdForName(name));
566 }
567
568
569 //------------------------------------------------------------------------------
570 //------------------------------------------------------------- Avp::removeAvp()
571 //------------------------------------------------------------------------------
572 bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) {
573   return removeAvp(getEngine()->avpIdForName(name), ocurrence);
574 }
575
576
577 //------------------------------------------------------------------------------
578 //--------------------------------------------------------------- Avp::_getAvp()
579 //------------------------------------------------------------------------------
580 const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
581   return getAvp(getEngine()->avpIdForName(name), ocurrence, emode);
582 }
583
584
585 //------------------------------------------------------------------------------
586 //-------------------------------------------------------------- Avp::countAvp()
587 //------------------------------------------------------------------------------
588 int Avp::countAvp(const char *name) const throw(anna::RuntimeException) {
589   return countAvp(getEngine()->avpIdForName(name));
590 }
591
592 //------------------------------------------------------------------------------
593 //------------------------------------------------------------- Avp::getLength()
594 //------------------------------------------------------------------------------
595 U24 Avp::getLength() const throw() {
596   U24 result;
597   // Avp format:
598   const stack::Avp *stackAvp = getStackAvp();
599   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
600   // Header length:
601   result = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
602
603   if(!stackFormat) {
604     result += a_Unknown->getSize();
605     return result;
606   }
607
608   if(stackFormat->isOctetString()) result += a_OctetString->getSize();
609   else if(stackFormat->isInteger32()) result += a_Integer32->getSize();
610   else if(stackFormat->isInteger64()) result += a_Integer64->getSize();
611   else if(stackFormat->isUnsigned32()) result += a_Unsigned32->getSize();
612   else if(stackFormat->isUnsigned64()) result += a_Unsigned64->getSize();
613   else if(stackFormat->isFloat32()) result += a_Float32->getSize();
614   else if(stackFormat->isFloat64()) result += a_Float64->getSize();
615   else if(stackFormat->isGrouped()) for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(avp(it)->getLength());
616   else if(stackFormat->isAddress()) result += a_Address->getSize();
617   else if(stackFormat->isTime()) result += a_Time->getSize();
618   else if(stackFormat->isUTF8String()) result += a_UTF8String->getSize();
619   else if(stackFormat->isDiameterIdentity()) result += a_DiameterIdentity->getSize();
620   else if(stackFormat->isDiameterURI()) result += a_DiameterURI->getSize();
621   else if(stackFormat->isEnumerated()) result += a_Enumerated->getSize();
622   else if(stackFormat->isIPFilterRule()) result += a_IPFilterRule->getSize();
623   else if(stackFormat->isQoSFilterRule()) result += a_QoSFilterRule->getSize();
624
625   /////////////////////
626   // Format specific //
627   /////////////////////
628   result += getLengthByFormat(stackFormat);
629   return result;
630 }
631
632
633 //------------------------------------------------------------------------------
634 //-------------------------------------------- Avp::unknownAvpWithMandatoryBit()
635 //------------------------------------------------------------------------------
636 void Avp::unknownAvpWithMandatoryBit() const throw(anna::RuntimeException) {
637   OamModule &oamModule = OamModule::instantiate();
638   const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id));
639   oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid);
640   oamModule.count(OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit);
641   LOGWARNING(
642     std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid);
643     anna::Logger::warning(msg, ANNA_FILE_LOCATION);
644   );
645 }
646
647 //------------------------------------------------------------------------------
648 //-------------------------------------------------------- Avp::decodeDataPart()
649 //------------------------------------------------------------------------------
650 void Avp::decodeDataPart(const char * buffer, int size, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
651   // OAM
652   OamModule &oamModule = OamModule::instantiate();
653   // Dictionary stack avp and format:
654   const stack::Avp *stackAvp = getStackAvp();
655   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
656
657   if(!stackFormat) {
658     a_Unknown->decode(buffer, size);
659     return;
660   }
661
662   if(stackFormat->isOctetString()) a_OctetString->decode(buffer, size);
663   else if(stackFormat->isInteger32()) a_Integer32->decode(buffer, size);
664   else if(stackFormat->isInteger64()) a_Integer64->decode(buffer, size);
665   else if(stackFormat->isUnsigned32()) a_Unsigned32->decode(buffer, size);
666   else if(stackFormat->isUnsigned64()) a_Unsigned64->decode(buffer, size);
667   else if(stackFormat->isFloat32()) a_Float32->decode(buffer, size);
668   else if(stackFormat->isFloat64()) a_Float64->decode(buffer, size);
669   else if(stackFormat->isGrouped()) {
670     if(size == 0) {
671       LOGDEBUG(anna::Logger::debug("Grouped Avp has empty data part", ANNA_FILE_LOCATION));
672       return;
673     }
674
675     if((size % 4) != 0) {
676       oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
677       oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
678
679       if(answer) {
680         answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
681         answer->setFailedAvp(parent, a_id);
682       }
683
684       throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION);
685     }
686
687     int avpPos = 0;
688     Avp* avp;
689     anna::DataBlock db;
690
691     // Me as parent:
692     parent_t me = parent;
693     me.addAvp(a_id);
694
695     while(avpPos < size) {
696       try {
697         avp = getEngine()->allocateAvp();
698         db.assign(buffer + avpPos, size - avpPos /* is valid to pass total size (indeed i don't know the real avp size) because it will be limited and this has deep copy disabled (no memory is reserved) */);
699         avp -> decode(db, me, answer);
700       } catch(anna::RuntimeException &ex) {
701         getEngine()->releaseAvp(avp);
702         throw;
703       }
704
705       addChild(avp);
706       avpPos += 4 * REQUIRED_WORDS(avp->getLength());
707     }
708   } else if(stackFormat->isAddress()) a_Address->decode(buffer, size);
709   else if(stackFormat->isTime()) a_Time->decode(buffer, size);
710   else if(stackFormat->isUTF8String()) a_UTF8String->decode(buffer, size);
711   else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->decode(buffer, size);
712   else if(stackFormat->isDiameterURI()) a_DiameterURI->decode(buffer, size);
713   else if(stackFormat->isEnumerated()) a_Enumerated->decode(buffer, size);
714   else if(stackFormat->isIPFilterRule()) a_IPFilterRule->decode(buffer, size);
715   else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->decode(buffer, size);
716
717   /////////////////////
718   // Format specific //
719   /////////////////////
720   decodeDataPartByFormat(buffer, size, stackFormat);
721 }
722
723 //------------------------------------------------------------------------------
724 //---------------------------------------------------------------- Avp::decode()
725 //------------------------------------------------------------------------------
726 void Avp::decode(const anna::DataBlock &db, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
727   // OAM
728   OamModule &oamModule = OamModule::instantiate();
729
730   if(db.getSize() < HeaderLengthVinactive) {
731     oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
732     oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
733     // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
734     throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION);
735   }
736
737   const char * buffer = db.getData();
738
739   //       0                   1                   2                   3
740   //       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
741   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742   //      |                           AVP Code                            |
743   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
744   //      |   AVP Flags   |                  AVP Length                   |
745   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
746   //      |                        Vendor-ID (opt)                        |
747   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748   //      |    Data ...
749   //      +-+-+-+-+-+-+-+-+
750   // Code flags and vendor-id
751   U32 code = DECODE4BYTES_INDX_VALUETYPE(buffer, 0, U32);
752
753   a_flags = (S8)buffer[4];
754
755   U32 vendorID = helpers::VENDORID__base;
756
757   if(vendorBit()) {
758     if(db.getSize() < HeaderLengthVactive) {
759       oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
760       oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
761       // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
762       throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION);
763     }
764
765     vendorID = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32);
766
767     if(vendorID == helpers::VENDORID__base) {
768       //      A vendor ID value of zero (0) corresponds to the IETF adopted AVP
769       //      values, as managed by the IANA. Since the absence of the vendor
770       //      ID field implies that the AVP in question is not vendor specific,
771       //      ...
772       //      implementations MUST NOT use the zero (0) vendor ID.
773       oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
774       oamModule.count(OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
775       throw anna::RuntimeException(anna::functions::asString("Incoherence between activated V bit and zeroed vendor-id value received (avp code = %u)", code), ANNA_FILE_LOCATION);
776     }
777   }
778
779   // Avp identifier
780   setId(AvpId(code, vendorID));
781   // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received:
782   a_flags = (S8)buffer[4];
783
784   // Here i know id and flags:
785   //   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
786   //   a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
787   //   Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
788   if(!getStackAvp() && mandatoryBit()) {
789
790         if(answer) {
791           answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED);
792           answer->setFailedAvp(parent, a_id);
793         }
794
795         unknownAvpWithMandatoryBit();
796   }
797
798   // Avp Length
799   U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24);
800   // Data start position:
801   int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
802   // Data part:
803   int dataBytes = length - startDataPos;
804
805   if(dataBytes < 0) {
806     oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
807     oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
808
809     if(answer) {
810       answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
811       answer->setFailedAvp(parent, a_id);
812     }
813
814     throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION);
815   }
816
817   try {
818     decodeDataPart(buffer + startDataPos, dataBytes, parent, answer);
819   } catch(anna::RuntimeException &ex) {
820     oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence);
821     oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence);
822
823     if(answer) {
824       answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
825       answer->setFailedAvp(parent, a_id);
826     }
827
828     throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION);
829   }
830 }
831
832
833 //------------------------------------------------------------------------------
834 //----------------------------------------------------------- Avp::getStackAvp()
835 //------------------------------------------------------------------------------
836 const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() {
837   const stack::Dictionary * dictionary = engine->getDictionary();
838   return (dictionary ? (dictionary->getAvp(id)) : NULL);
839 }
840
841
842 //------------------------------------------------------------------------------
843 //------------------------------------------------------------------- Avp::fix()
844 //------------------------------------------------------------------------------
845 void Avp::fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw() {
846   // Exit cases
847   if(avps.size() == 0) return;  // empty content, nothing to fix
848
849   if(ruleBegin == ruleEnd) return;  // no reference. Cannot fix
850
851   // Copy reference container and clear internal map in order to build a fixed version:
852   avp_container unfixedAvps;
853
854   for(const_avp_iterator it = avps.begin(); it != avps.end(); it++)
855     unfixedAvps[(*it).first] = (*it).second;
856
857   avps.clear();
858   // Cache system reset (fix probably will invalidate cached findings):
859   finds.clear();
860   insertionPositionForChilds = 0;
861   avp_iterator avp_it;
862   Avp * avp;
863
864   for(anna::diameter::stack::const_avprule_iterator rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
865     while((avp_it = Avp::avp_find(unfixedAvps, (*rule_it).second.getId(), 1)) != unfixedAvps.end()) {
866       avp = (*avp_it).second;
867       addChild(avps, insertionPositionForChilds, avp);
868       unfixedAvps.erase(avp_it); // processed
869     }
870   }
871
872   // Add remaining avps:
873   for(avp_it = unfixedAvps.begin(); avp_it != unfixedAvps.end(); avp_it++) {
874     avp = (*avp_it).second;
875
876     if(avp) addChild(avps, insertionPositionForChilds, avp);
877   }
878
879   // Fix grouped Avps:
880   for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
881     avp = (*it).second;
882
883     if(avp->hasChildren()) avp->fix();
884   }
885 }
886
887
888 //------------------------------------------------------------------------------
889 //------------------------------------------------------------------- Avp::fix()
890 //------------------------------------------------------------------------------
891 void Avp::fix() throw() {
892   // Dictionary stack avp:
893   const stack::Avp *stackAvp = getStackAvp();
894   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
895
896   if(!stackAvp) {
897     //LOGDEBUG(anna::Logger::debug("No dictionary avp reference found. Cannot fix.", ANNA_FILE_LOCATION));
898     return;
899   }
900
901   if(!stackFormat || !stackFormat->isGrouped()) {
902     //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing to fix.", ANNA_FILE_LOCATION));
903     return;
904   }
905
906   fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackAvp->avprule_begin(), stackAvp->avprule_end());
907 }
908
909
910 //------------------------------------------------------------------------------
911 //------------------------------------------------------------ Avp::validLevel()
912 //------------------------------------------------------------------------------
913 bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
914   bool result = true;
915   // OAM
916   OamModule &oamModule = OamModule::instantiate();
917   ///////////
918   // Fixed //
919   ///////////
920   // auxiliary
921   AvpId id;
922   const_avp_iterator avp_it = avps.begin();
923   anna::diameter::stack::const_avprule_iterator rule_it;
924   bool okFixed;
925
926   for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
927     okFixed = true;
928
929     if((*rule_it).second.isFixed()) {
930       if(avps.size() == 0) break;  // cardinality checking will show this anomaly
931
932       if(avp_it != avps.end()) {
933         id = Avp::avp(avp_it)->getId();
934
935         if(id != (*rule_it).second.getId()) {
936           okFixed = false;
937           // Missing fixed rule: %s
938         } else if(Avp::avp_find(avps, id, 2) != avps.end()) {
939           okFixed = false;
940           // More than one fixed ocurrency for rule %s (*)
941         }
942
943         avp_it++;
944         // (*) for (int k = 0; k < (*rule_it).second.getQualMax(); k++) avp_it++
945       } else
946         okFixed = false;
947
948       if(!okFixed) {
949         result = false;
950         // OAM & Depth management
951         oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
952         oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule);
953
954         if(answer) {
955           answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
956           answer->setFailedAvp(parent, (*rule_it).second.getId());
957         }
958
959         engine->validationAnomaly(anna::functions::asString("Missing fixed rule %s inside %s", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
960       }
961     } else break; // finish fixed
962   }
963
964   /////////////////
965   // Cardinality // Mandatory control is implicit here
966   /////////////////
967   anna::diameter::stack::const_avprule_iterator generic_rule_it = ruleEnd;
968   int min, max, amount;
969
970   for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
971     if((*rule_it).second.isAny()) { generic_rule_it = rule_it; continue; }  // generic Avp will be managed after
972
973     id = (*rule_it).second.getId();
974     min = (*rule_it).second.getQualMin();
975     max = (*rule_it).second.getQualMax(); // -1 means infinite
976     amount = Avp::countAvp(avps, id);
977
978     if((amount < min) || ((max != -1) && (amount > max))) {
979       // Failed rule %s for cardinality (found %d items)
980       result = false;
981       // OAM & Depth management
982       oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
983       oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality);
984
985       if(amount < min) {
986         oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded);
987
988         if(answer) {
989           answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
990           answer->setFailedAvp(parent, id);
991         }
992       } else {
993         oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded);
994
995         if(answer) {
996           answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES);
997           answer->setFailedAvp(parent, id);
998         }
999       }
1000
1001       engine->validationAnomaly(anna::functions::asString("Failed rule %s for cardinality (found %d items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1002     }
1003   }
1004
1005   bool haveGeneric = (generic_rule_it != ruleEnd);
1006   /////////////////
1007   // Generic AVP //
1008   /////////////////
1009   bool foundInRules;
1010   std::map < AvpId, int /* dummy */ > disregarded; // 'Disregardeds' are Avps not in rules list
1011   std::map < AvpId, int /* dummy */ >::const_iterator disregarded_it;
1012
1013   for(avp_it = avps.begin(); avp_it != avps.end(); avp_it++) {
1014     id = Avp::avp(avp_it)->getId();
1015     // Find rule for the child:
1016     foundInRules = false;
1017
1018     for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
1019       if((*rule_it).second.getId() == id) {
1020         foundInRules = true;
1021         break;
1022       }
1023     }
1024
1025     if(!foundInRules) {
1026       disregarded[id] = 0;
1027     }
1028   }
1029
1030   // Generic AVP cardinality checkings
1031   int disregardeds = disregarded.size();
1032
1033   if(haveGeneric) {
1034     min = (*generic_rule_it).second.getQualMin();
1035     max = (*generic_rule_it).second.getQualMax(); // -1 means infinite
1036     amount = disregardeds;
1037
1038     if((amount < min) || ((max != -1) && (amount > max))) {
1039       // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)
1040       result = false;
1041       // OAM & Depth management
1042       oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
1043       oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem);
1044
1045       if(answer) {
1046         answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1047         answer->setFailedAvp(parent, id); // NO SENSE... what to put ?
1048       }
1049
1050       engine->validationAnomaly(anna::functions::asString("Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1051     }
1052   } else if(disregardeds) {  // When Generic AVP missing, no disregarded Avps are allowed
1053     // Found %d disregarded items inside %s and Generic AVP was not specified
1054     result = false;
1055     // Build disregarded list as string (unknown as avp id pair):
1056     std::string s_disregardeds = "";
1057     const stack::Avp *stackAvp;
1058
1059     for(disregarded_it = disregarded.begin(); disregarded_it != disregarded.end(); disregarded_it++) {
1060       id = (*disregarded_it).first;
1061       stackAvp = getStackAvp(id, engine);
1062       s_disregardeds += (stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)));
1063       s_disregardeds += ", ";
1064
1065       // We wouldn't know where are these disregarded, but...
1066       if(answer) {
1067         answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1068         answer->setFailedAvp(parent, id);
1069       }
1070     }
1071
1072     s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', '
1073     // OAM & Depth management
1074     oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds));
1075     oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified);
1076     engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)));
1077   }
1078
1079   return result;
1080 }
1081
1082
1083 //------------------------------------------------------------------------------
1084 //----------------------------------------------------------------- Avp::valid()
1085 //------------------------------------------------------------------------------
1086 bool Avp::valid(const parent_t & parent, Message *answer) const throw(anna::RuntimeException) {
1087   // OAM
1088   OamModule &oamModule = OamModule::instantiate();
1089   // Dictionary stack avp:
1090   const stack::Avp *stackAvp = getStackAvp();
1091   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1092
1093   if(!stackAvp) {
1094     // No dictionary avp reference found. Cannot validate
1095     return true; // perhaps a unknown Avp
1096   }
1097
1098   // Me as parent:
1099   parent_t me = parent;
1100   me.addAvp(a_id, stackAvp->getName().c_str());
1101
1102   if(!stackFormat) {
1103     // No format avp reference found. Cannot validate
1104     return true; // perhaps a unknown Avp
1105   }
1106
1107   //////////////////////////////
1108   // Flags coherence checking //
1109   //////////////////////////////
1110   bool result = flagsOK();
1111
1112   if(!result) {
1113     // OAM & Depth management
1114     oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()));
1115     oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules);
1116
1117     if(answer) {
1118       answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS);
1119       answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); // RFC 6733 says nothing about Failed-AVP in this case...
1120     }
1121
1122     getEngine()->validationAnomaly(anna::functions::asString("The AVP %s flags (%d) does not fulfill the defined flag rules: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())));
1123   }
1124
1125   //////////////////////
1126   // Enumerated range //
1127   //////////////////////
1128   if(stackFormat->isEnumerated()) {
1129     if(!stackAvp->allowEnum(a_Enumerated->getValue())) {
1130       result = false;
1131       // OAM & Depth management
1132       oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums());
1133       oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction);
1134
1135       if(answer) {
1136         answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
1137         answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str());
1138       }
1139
1140       getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums()));
1141     }
1142   }
1143
1144   ////////////////////
1145   // Level checking //
1146   ////////////////////
1147   result = Avp::validLevel(a_avps, stackAvp->avprule_begin(), stackAvp->avprule_end(), getEngine(), me, answer) && result;
1148
1149   ////////////////////////
1150   // Childrens checking //
1151   ////////////////////////
1152   if(a_id == helpers::base::AVPID__Failed_AVP) return result;  // DON'T VALIDATE CONTENT FOR Failed-AVP, because it won't be valid...
1153
1154   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++)
1155     result = ((*it).second->valid(me, answer)) && result;
1156
1157   return result;
1158 }
1159
1160
1161 //------------------------------------------------------------------------------
1162 //------------------------------------------------------------------ Avp::code()
1163 //------------------------------------------------------------------------------
1164 void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) {
1165   // Code
1166   buffer[0] = (S8)(a_id.first >> 24);
1167   buffer[1] = (S8)(a_id.first >> 16);
1168   buffer[2] = (S8)(a_id.first >> 8);
1169   buffer[3] = (S8) a_id.first;
1170   // Flags and length
1171   size = getLength();
1172   buffer[4] = (S8) a_flags;
1173   buffer[5] = (S8)(size >> 16);
1174   buffer[6] = (S8)(size >> 8);
1175   buffer[7] = (S8) size;
1176
1177   // Vendor-id
1178   if(vendorBit()) {
1179     buffer[8] = (S8)(a_id.second >> 24);
1180     buffer[9] = (S8)(a_id.second >> 16);
1181     buffer[10] = (S8)(a_id.second >> 8);
1182     buffer[11] = (S8) a_id.second;
1183   }
1184
1185   // Data start position:
1186   int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
1187   // Data part:
1188   S8 * dataPart = buffer + startDataPos;
1189   int dataBytes; // not used but could be useful for checking (size - startDataPos)
1190
1191   if(startDataPos == size) {
1192     LOGDEBUG(anna::Logger::debug("There is no data part to encode", ANNA_FILE_LOCATION));
1193     return;
1194   }
1195
1196   // Avp format:
1197   const stack::Avp *stackAvp = getStackAvp();
1198   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1199
1200   if(!stackFormat) {
1201     a_Unknown->code(dataPart, dataBytes);
1202     return;
1203   }
1204
1205   if(stackFormat->isOctetString()) a_OctetString->code(dataPart, dataBytes);
1206   else if(stackFormat->isInteger32()) a_Integer32->code(dataPart, dataBytes);
1207   else if(stackFormat->isInteger64()) a_Integer64->code(dataPart, dataBytes);
1208   else if(stackFormat->isUnsigned32()) a_Unsigned32->code(dataPart, dataBytes);
1209   else if(stackFormat->isUnsigned64()) a_Unsigned64->code(dataPart, dataBytes);
1210   else if(stackFormat->isFloat32()) a_Float32->code(dataPart, dataBytes);
1211   else if(stackFormat->isFloat64()) a_Float64->code(dataPart, dataBytes);
1212   else if(stackFormat->isGrouped()) {
1213 //      // Each avp encoding will remain padding octets depending on format. In order to
1214 //      //  code grouped content (each avp will be multiple of 4) we clean the entire buffer
1215 //      //  to ensure padding (easier than custom-made for each format):
1216 //      memset(dataPart, 0, size - startDataPos);
1217     char *dataPartGrouped = dataPart;
1218     int dataBytesGrouped;
1219
1220     for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
1221       avp(it)->code(dataPartGrouped, dataBytesGrouped);
1222       dataPartGrouped = dataPartGrouped + 4 * REQUIRED_WORDS(dataBytesGrouped);
1223     }
1224   } else if(stackFormat->isAddress()) a_Address->code(dataPart, dataBytes);
1225   else if(stackFormat->isTime()) a_Time->code(dataPart, dataBytes);
1226   else if(stackFormat->isUTF8String()) a_UTF8String->code(dataPart, dataBytes);
1227   else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->code(dataPart, dataBytes);
1228   else if(stackFormat->isDiameterURI()) a_DiameterURI->code(dataPart, dataBytes);
1229   else if(stackFormat->isEnumerated()) a_Enumerated->code(dataPart, dataBytes);
1230   else if(stackFormat->isIPFilterRule()) a_IPFilterRule->code(dataPart, dataBytes);
1231   else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->code(dataPart, dataBytes);
1232
1233   /////////////////////
1234   // Format specific //
1235   /////////////////////
1236   codeByFormat(dataPart, stackFormat);
1237 }
1238
1239
1240 //------------------------------------------------------------------------------
1241 //------------------------------------------------------------ Avp::getXMLdata()
1242 //------------------------------------------------------------------------------
1243 std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() {
1244   std::string result = "";
1245   isHex = false;
1246   // Unknown
1247 //   try {
1248 //      if (!stackFormat) {
1249 //         isHex = true;
1250 //         return a_Unknown->asHexString();
1251 //      }
1252 //   } catch (anna::RuntimeException &ex) {
1253 //      ex.trace();
1254 //   }
1255
1256   if(!stackFormat) {
1257     isHex = true;
1258     return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad
1259   }
1260
1261   // Special case for Address: could launch exception if not printable
1262   try {
1263     if(stackFormat->isAddress()) return a_Address->asPrintableString();
1264   } catch(anna::RuntimeException&) {
1265     //ex.trace();
1266     isHex = true;
1267     return a_Address->asHexString();
1268   }
1269
1270   try {
1271     if(stackFormat->isOctetString()) {
1272       isHex = true;
1273       return a_OctetString->asHexString();
1274     }
1275
1276     // Non-hexadecimal
1277     if(stackFormat->isInteger32()) return a_Integer32->asPrintableString();
1278
1279     if(stackFormat->isInteger64()) return a_Integer64->asPrintableString();
1280
1281     if(stackFormat->isUnsigned32()) return a_Unsigned32->asPrintableString();
1282
1283     if(stackFormat->isUnsigned64()) return a_Unsigned64->asPrintableString();
1284
1285     if(stackFormat->isFloat32()) return a_Float32->asPrintableString();
1286
1287     if(stackFormat->isFloat64()) return a_Float64->asPrintableString();
1288
1289     //if (stackFormat->isAddress()) return a_Address->asPrintableString();
1290
1291     if(stackFormat->isTime()) return a_Time->asPrintableString();
1292
1293     if(stackFormat->isUTF8String()) return a_UTF8String->asPrintableString();
1294
1295     if(stackFormat->isDiameterIdentity()) return a_DiameterIdentity->asPrintableString();
1296
1297     if(stackFormat->isDiameterURI()) return a_DiameterURI->asPrintableString();
1298
1299     if(stackFormat->isEnumerated()) return a_Enumerated->asPrintableString();
1300
1301     if(stackFormat->isIPFilterRule()) return a_IPFilterRule->asPrintableString();
1302
1303     if(stackFormat->isQoSFilterRule()) return a_QoSFilterRule->asPrintableString();
1304
1305     /////////////////////
1306     // Format specific //
1307     /////////////////////
1308     return getXMLdataByFormat(isHex, stackFormat);
1309   } catch(anna::RuntimeException &ex) {
1310     ex.trace();
1311   }
1312
1313   return result;
1314 }
1315
1316
1317 //------------------------------------------------------------------------------
1318 //---------------------------------------------------------------- Avp::decode()
1319 //------------------------------------------------------------------------------
1320 void Avp::decode(const anna::DataBlock &db) throw(anna::RuntimeException) {
1321
1322   parent_t parent;
1323   parent.setMessage(CommandId(0,false), "No-Parent");
1324   decode(db, parent, NULL);
1325 }
1326
1327
1328 //------------------------------------------------------------------------------
1329 //--------------------------------------------------------------- Avp::fromXML()
1330 //------------------------------------------------------------------------------
1331 void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) {
1332   // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1333   const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData;
1334   name = avpNode->getAttribute("name", false /* no exception */);
1335   code = avpNode->getAttribute("code", false /* no exception */);
1336   vendorCode = avpNode->getAttribute("vendor-code", false /* no exception */);
1337   flags = avpNode->getAttribute("flags", false /* no exception */);
1338   data = avpNode->getAttribute("data", false /* no exception */);
1339   hexData = avpNode->getAttribute("hex-data", false /* no exception */);
1340   // Dictionary
1341   const stack::Dictionary * dictionary = getEngine()->getDictionary();
1342   const stack::Avp *stackAvp = NULL;
1343   const stack::Format *stackFormat = NULL;
1344
1345   // Compact mode
1346   if(name) {
1347     if(!dictionary) {
1348       std::string msg = "Error processing avp <name '"; msg += name->getValue();
1349       msg += "'>: no dictionary available. Load one or use <'code' + 'flags' + 'vendorCode'> instead of <'name'>";
1350       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1351     }
1352
1353     stackAvp = dictionary->getAvp(name->getValue());
1354
1355     if(!stackAvp) {
1356       std::string msg = "Error processing avp <name '"; msg += name->getValue();
1357       msg += "'>: no avp found for this identifier at available dictionary";
1358       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1359     }
1360
1361     stackFormat = stackAvp->getFormat();
1362   }
1363
1364   // Check attributes exclusiveness
1365   if(name) {  // compact mode
1366     if(code || flags || vendorCode) {
1367       std::string msg = "Error processing avp <name '"; msg += name->getValue();
1368       msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided";
1369       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1370     }
1371
1372     setId(stackAvp->getId());
1373   } else {
1374     if(!code || !flags || !vendorCode) {
1375       std::string s_code = code ? code->getValue() : "?";
1376       std::string s_flags = flags ? flags->getValue() : "?";
1377       std::string s_vendorCode = vendorCode ? vendorCode->getValue() : "?";
1378       std::string msg = "Error processing avp <code '"; msg += s_code;
1379       msg += "' + flags '"; msg += s_flags;
1380       msg += "' + vendorCode '"; msg += s_vendorCode;
1381       msg += "'>: all must be provided if <'name'> don't";
1382       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1383     }
1384
1385     // Code check
1386     int i_aux = code->getIntegerValue();
1387
1388     if(i_aux < 0) {
1389       std::string msg = "Error processing avp <code '"; msg += code->getValue();
1390       msg += "': negative values are not allowed";
1391       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1392     }
1393
1394     U24 u_code = i_aux;
1395     // Flags check
1396     i_aux = flags->getIntegerValue();
1397
1398     if(i_aux < 0 || i_aux > 256) {
1399       std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1400       msg += "': out of range [0,256]";
1401       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1402     }
1403
1404     a_flags = i_aux;
1405     int flagsBCK = a_flags;
1406     // VendorCode checks
1407     i_aux = vendorCode->getIntegerValue();
1408
1409     if(i_aux < 0) {
1410       std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1411       msg += "': negative values are not allowed";
1412       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1413     }
1414
1415     U32 u_vendorCode = i_aux;
1416     bool vendorSpecific1 = (u_vendorCode != 0);
1417     bool vendorSpecific2 = (((a_flags) & VBitMask) != 0x00);
1418
1419     if(vendorSpecific1 != vendorSpecific2) {
1420       std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1421       msg += "' and avp <flags '"; msg += flags->getValue();
1422       msg += "': incompatible vendor-specific properties";
1423       throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1424     }
1425
1426     // Final assignments
1427     setId(AvpId(u_code, u_vendorCode));
1428     // Flags could have been updated regarding dictionary, but during parsing we must respect xml file:
1429     a_flags = flagsBCK;
1430     stackAvp = getStackAvp();
1431     stackFormat = stackAvp ? stackAvp->getFormat() : NULL;
1432   }
1433
1434   // Childrens
1435   // Check if grouped not confirmed
1436   anna::xml::Node::const_child_iterator it;
1437   anna::xml::Node::const_child_iterator minii = avpNode->child_begin();
1438   anna::xml::Node::const_child_iterator maxii = avpNode->child_end();
1439   const bool hasChildren(minii != maxii);
1440
1441   if(hasChildren) {
1442     // We need to confirm is grouped
1443     if(!stackFormat)
1444       throw anna::RuntimeException("An xml avp node with children nodes could not confirmed as Grouped", ANNA_FILE_LOCATION);
1445
1446     if(!stackFormat->isGrouped())
1447       throw anna::RuntimeException("An xml avp node with children nodes is not grouped type", ANNA_FILE_LOCATION);
1448
1449     if(data || hexData)
1450       throw anna::RuntimeException("An xml avp node with children nodes has 'data' or 'hex-data' field", ANNA_FILE_LOCATION);
1451   }
1452
1453   // Presentation
1454   std::string s_avp = name ? (name->getValue()) : (anna::diameter::functions::avpIdAsPairString(a_id));
1455
1456   if(data && hexData) {
1457     std::string msg = "Not allowed both 'data' and 'hex-data' definitions. Avp ";
1458     msg += s_avp;
1459     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1460   }
1461
1462   LOGWARNING(
1463     bool unknown = !stackFormat;
1464     bool octetString = stackFormat && (stackFormat->isOctetString());
1465
1466   if(data && (unknown || octetString)) {
1467   std::string msg = "Not recommended 'data' field at ";
1468   msg += unknown ? "Unknown" : "OctetString";
1469   msg += "-format Avp "; msg += s_avp;
1470   msg += ". Use better 'hex-data' or omit content fields if empty";
1471   anna::Logger::warning(msg, ANNA_FILE_LOCATION);
1472   }
1473   );
1474
1475   if(!stackFormat) {
1476     if(data) a_Unknown->fromPrintableString(data->getValue().c_str());
1477     else if(hexData) a_Unknown->fromHexString(hexData->getValue());
1478
1479     return;
1480   }
1481
1482   if(stackFormat->isOctetString()) {
1483     if(data) a_OctetString->fromPrintableString(data->getValue().c_str());
1484     else if(hexData) a_OctetString->fromHexString(hexData->getValue());
1485   } else if(stackFormat->isInteger32()) {
1486     if(data) a_Integer32->fromPrintableString(data->getValue().c_str());
1487     else if(hexData) a_Integer32->fromHexString(hexData->getValue());
1488   } else if(stackFormat->isInteger64()) {
1489     if(data) a_Integer64->fromPrintableString(data->getValue().c_str());
1490     else if(hexData) a_Integer64->fromHexString(hexData->getValue());
1491   } else if(stackFormat->isUnsigned32()) {
1492     if(data) a_Unsigned32->fromPrintableString(data->getValue().c_str());
1493     else if(hexData) a_Unsigned32->fromHexString(hexData->getValue());
1494   } else if(stackFormat->isUnsigned64()) {
1495     if(data) a_Unsigned64->fromPrintableString(data->getValue().c_str());
1496     else if(hexData) a_Unsigned64->fromHexString(hexData->getValue());
1497   } else if(stackFormat->isFloat32()) {
1498     if(data) a_Float32->fromPrintableString(data->getValue().c_str());
1499     else if(hexData) a_Float32->fromHexString(hexData->getValue());
1500   } else if(stackFormat->isFloat64()) {
1501     if(data) a_Float64->fromPrintableString(data->getValue().c_str());
1502     else if(hexData) a_Float64->fromHexString(hexData->getValue());
1503   } else if(stackFormat->isGrouped()) {
1504     // Childrens
1505     Avp *avp;
1506
1507     for(it = minii; it != maxii; it++) {
1508       std::string nodeName = (*it)->getName();
1509
1510       if(nodeName != "avp") {
1511         std::string msg = "Unsupported grouped avp child node name '"; msg += nodeName;
1512         msg += "': use 'avp'";
1513         throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1514       }
1515
1516       try {
1517         avp =  getEngine()->allocateAvp();
1518         avp -> fromXML(*it);
1519       } catch(anna::RuntimeException &ex) {
1520         getEngine()->releaseAvp(avp);
1521         throw;
1522       }
1523
1524       addAvp(avp);
1525     }
1526   } else if(stackFormat->isAddress()) {
1527     if(data) a_Address->fromPrintableString(data->getValue().c_str());
1528     else if(hexData) a_Address->fromHexString(hexData->getValue());
1529   } else if(stackFormat->isTime()) {
1530     if(data) a_Time->fromPrintableString(data->getValue().c_str());
1531     else if(hexData) a_Time->fromHexString(hexData->getValue());
1532   } else if(stackFormat->isUTF8String()) {
1533     if(data) a_UTF8String->fromPrintableString(data->getValue().c_str());
1534     else if(hexData) a_UTF8String->fromHexString(hexData->getValue());
1535   } else if(stackFormat->isDiameterIdentity()) {
1536     if(data) a_DiameterIdentity->fromPrintableString(data->getValue().c_str());
1537     else if(hexData) a_DiameterIdentity->fromHexString(hexData->getValue());
1538   } else if(stackFormat->isDiameterURI()) {
1539     if(data) a_DiameterURI->fromPrintableString(data->getValue().c_str());
1540     else if(hexData) a_DiameterURI->fromHexString(hexData->getValue());
1541   } else if(stackFormat->isEnumerated()) {
1542     if(data) a_Enumerated->fromPrintableString(data->getValue().c_str());
1543     else if(hexData) a_Enumerated->fromHexString(hexData->getValue());
1544   } else if(stackFormat->isIPFilterRule()) {
1545     if(data) a_IPFilterRule->fromPrintableString(data->getValue().c_str());
1546     else if(hexData) a_IPFilterRule->fromHexString(hexData->getValue());
1547   } else if(stackFormat->isQoSFilterRule()) {
1548     if(data) a_QoSFilterRule->fromPrintableString(data->getValue().c_str());
1549     else if(hexData) a_QoSFilterRule->fromHexString(hexData->getValue());
1550   }
1551
1552   /////////////////////
1553   // Format specific //
1554   /////////////////////
1555   fromXMLByFormat(data, hexData, stackFormat);
1556 }
1557
1558 //------------------------------------------------------------------------------
1559 //----------------------------------------------------------------- Avp::asXML()
1560 //------------------------------------------------------------------------------
1561 anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() {
1562   // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1563   anna::xml::Node* result = parent->createChild("avp");
1564   // Dictionary stack avp and format:
1565   const stack::Avp *stackAvp = getStackAvp();
1566   const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1567   bool compactMode = (stackAvp && flagsOK());
1568
1569   if(compactMode) {
1570     result->createAttribute("name", stackAvp->getName());
1571   } else {
1572     result->createAttribute("code", a_id.first);
1573     result->createAttribute("vendor-code", a_id.second);
1574     result->createAttribute("flags", (int)a_flags);
1575   }
1576
1577   // Grouped special case:
1578   if(stackFormat && stackFormat->isGrouped()) {
1579     for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) avp(it)->asXML(result);
1580
1581     return result;
1582   }
1583
1584   // Data part literals:
1585   bool isHex;
1586   std::string value = getXMLdata(isHex, stackFormat);
1587
1588   if(isHex) {
1589     result->createAttribute("hex-data", value);
1590   } else {
1591     result->createAttribute("data", value);
1592     const char *alias = stackAvp->getAlias(value);
1593
1594     if(alias) result->createAttribute("alias", alias);  // additional information
1595   }
1596
1597   return result;
1598 }
1599
1600
1601 //------------------------------------------------------------------------------
1602 //----------------------------------------------------------- Avp::asXMLString()
1603 //------------------------------------------------------------------------------
1604 std::string Avp::asXMLString() const throw() {
1605   anna::xml::Node root("root");
1606   return anna::xml::Compiler().apply(asXML(&root));
1607 }
1608
1609
1610 //------------------------------------------------------------------------------
1611 //---------------------------------------------------------------- Avp::isLike()
1612 //------------------------------------------------------------------------------
1613 bool Avp::isLike(const std::string &pattern) const throw() {
1614   anna::RegularExpression re(pattern);
1615   return re.isLike(asXMLString());
1616 }