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