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