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