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