1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
10 #include <anna/diameter/codec/Avp.hpp>
11 #include <anna/diameter/codec/Format.hpp>
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>
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>
37 using namespace anna::diameter::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);
55 //------------------------------------------------------------------------------
56 //------------------------------------------------------------------- Avp::Avp()
57 //------------------------------------------------------------------------------
58 Avp::Avp(Engine *engine) : a_engine(engine) {
62 //------------------------------------------------------------------------------
63 //------------------------------------------------------------------- Avp::Avp()
64 //------------------------------------------------------------------------------
65 Avp::Avp(AvpId id, Engine *engine) : a_engine(engine) {
70 //------------------------------------------------------------------------------
71 //------------------------------------------------------------------ Avp::~Avp()
72 //------------------------------------------------------------------------------
77 //------------------------------------------------------------------------------
78 //------------------------------------------------------------- Avp::setEngine()
79 //------------------------------------------------------------------------------
80 void Avp::setEngine(Engine *engine) throw() {
81 if (a_engine && engine != a_engine) {
82 LOGWARNING(anna::Logger::warning("Ignored: it is not a good practice to change the codec engine once assigned. Clear the avp first to set the engine again.", ANNA_FILE_LOCATION));
89 //------------------------------------------------------------------------------
90 //------------------------------------------------------------- Avp::getEngine()
91 //------------------------------------------------------------------------------
92 Engine * Avp::getEngine() const throw(anna::RuntimeException) {
94 throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION);
100 //------------------------------------------------------------------------------
101 //------------------------------------------------------------ Avp::initialize()
102 //------------------------------------------------------------------------------
103 void Avp::initialize() throw() {
104 a_id = helpers::AVPID__AVP; // (0,0)
106 a_insertionPositionForChilds = 0;
107 a_OctetString = NULL;
118 a_DiameterIdentity = NULL;
119 a_DiameterURI = NULL;
121 a_IPFilterRule = NULL;
122 a_QoSFilterRule = NULL;
125 /////////////////////
126 // Format specific //
127 /////////////////////
128 initializeByFormat();
132 //------------------------------------------------------------------------------
133 //----------------------------------------------------------------- Avp::clear()
134 //------------------------------------------------------------------------------
135 void Avp::clear() throw(anna::RuntimeException) {
136 delete a_OctetString;
144 for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(avp(it)); }
150 delete a_DiameterIdentity;
151 delete a_DiameterURI;
153 delete a_IPFilterRule;
154 delete a_QoSFilterRule;
158 /////////////////////
159 // Format specific //
160 /////////////////////
167 //------------------------------------------------------------------------------
168 //-------------------------------------------------------------- Avp::avp_find()
169 //------------------------------------------------------------------------------
170 avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() {
174 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
177 if(aux && (aux->getId() == id)) {
180 if(match == position) return it;
188 //------------------------------------------------------------------------------
189 //---------------------------------------------------------------- Avp::addAvp()
190 //------------------------------------------------------------------------------
191 Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() {
192 Avp * result = engine->createAvp(NULL);
194 addChild(avps, insertionPositionForChilds, result);
199 //------------------------------------------------------------------------------
200 //---------------------------------------------------------------- Avp::addAvp()
201 //------------------------------------------------------------------------------
202 Avp * Avp::addAvp(Avp * avp) throw(anna::RuntimeException) {
203 if(!avp) return NULL;
204 if (avp->getEngine() != getEngine()) return NULL;
210 //------------------------------------------------------------------------------
211 //------------------------------------------------------------- Avp::removeAvp()
212 //------------------------------------------------------------------------------
213 bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() {
214 bool removed = false;
215 bool do_remove = true;
216 int position = ocurrence;
218 if(position < 0) { /* reversed access */
219 position = countAvp(avps, id) + 1 + position;
221 // Special cases -> 0 and negative results:
222 // (1) User wants to remove the last, but no avp is found: position = 0 + 1 - 1 = 0 (would removes all but, no avp will be found: return now)
223 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (would removes all !!!: return to avoid unexpected behaviour)
224 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
225 if(position <= 0) do_remove = false;
229 int n = position ? position : 1 /* will search always the first and remove, the first and remove, the first and remove ... */;
232 while((it = avp_find(avps, id, n)) != avps.end()) {
233 engine->releaseAvp((*it).second);
242 // Cache system reset (remove will invalidate cached findings):
245 const stack::Avp *stackAvp = getStackAvp(id, engine);
246 std::string msg = "Removed Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
247 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
248 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
252 const stack::Avp *stackAvp = getStackAvp(id, engine);
253 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
254 msg += anna::functions::asString(" with provided ocurrence (%d), in order to be removed", ocurrence);
255 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
263 //------------------------------------------------------------------------------
264 //-------------------------------------------------------------- Avp::countAvp()
265 //------------------------------------------------------------------------------
266 int Avp::countAvp(const avp_container &avps, AvpId id) throw() {
268 const_avp_iterator it;
270 while((it = avp_find(avps, id, result + 1)) != avps.end()) result++;
276 //------------------------------------------------------------------------------
277 //-------------------------------------------------------------- Avp::firstAvp()
278 //------------------------------------------------------------------------------
279 const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() {
280 const_avp_iterator it = avp_find(avps, id, 1);
289 //------------------------------------------------------------------------------
290 //----------------------------------------------------------- Avp::countChilds()
291 //------------------------------------------------------------------------------
292 int Avp::countChilds(const avp_container &avps) throw() {
297 //------------------------------------------------------------------------------
298 //---------------------------------------------------------------- Avp::getAvp()
299 //------------------------------------------------------------------------------
300 const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
302 LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION));
306 bool do_search = true;
308 int position = ocurrence;
310 if(position < 0) { /* reversed access */
311 position = countAvp(avps, id) + 1 + position;
313 // Special cases -> 0 and negative results:
314 // (1) User wants to get the last, but no avp is found: position = 0 + 1 - 1 = 0 (can't find 0-position ...)
315 // (2) User wants to get some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (can't find 0-position ...)
316 // (2) User wants to get some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
317 if(position <= 0) do_search = false;
320 const Avp * result = NULL;
323 // Search at cache finds:
324 find_key key(id, position);
325 find_iterator fit = finds.find(key);
326 cached = (fit != finds.end());
329 result = (*fit).second;
331 const_avp_iterator it = avp_find(avps, id, position);
333 if(it != avps.end()) {
334 result = (*it).second;
335 finds[key] = const_cast<Avp*>(result); // store in cache
343 const stack::Avp *stackAvp = getStackAvp(id, engine);
344 std::string msg = "Found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
345 msg += anna::functions::asString(" with provided ocurrence (%d) which was ", ocurrence);
346 msg += cached ? "already cached:\n" : "the first search, now cached:\n";
347 msg += result->asXMLString();
348 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
355 case anna::Exception::Mode::Throw: {
356 const stack::Avp *stackAvp = getStackAvp(id, engine);
357 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
358 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
359 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
362 case anna::Exception::Mode::Trace: {
364 const stack::Avp *stackAvp = getStackAvp(id, engine);
365 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
366 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
367 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
371 case anna::Exception::Mode::Ignore: {
373 const stack::Avp *stackAvp = getStackAvp(id, engine);
374 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
375 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
376 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
386 //------------------------------------------------------------------------------
387 //--------------------------------------------------------------- Avp::_getAvp()
388 //------------------------------------------------------------------------------
389 const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
390 // Dictionary stack avp and format (this):
391 const stack::Avp *stackAvp = getStackAvp();
392 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
394 if(!stackFormat || !stackFormat->isGrouped())
395 throw anna::RuntimeException("This method only applies over grouped avps.", ANNA_FILE_LOCATION);
397 return getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
401 //------------------------------------------------------------------------------
402 //---------------------------------------------------------- Avp::assertFormat()
403 //------------------------------------------------------------------------------
404 void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) {
405 // Dictionary stack avp and format:
406 const stack::Avp *stackAvp = getStackAvp();
407 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
408 std::string format = stackFormat ? stackFormat->getName() : "Unknown";
411 std::string msg = "The Avp ";
412 msg += anna::diameter::functions::avpIdAsPairString(a_id);
413 msg += " with format '";
415 msg += "' is not compatible with the API method used (";
418 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
423 //------------------------------------------------------------------------------
424 //--------------------------------------------------------------- Avp::flagsOK()
425 //------------------------------------------------------------------------------
426 bool Avp::flagsOK() const throw() {
427 // Dictionary stack avp:
428 const stack::Avp *stackAvp = getStackAvp();
431 std::string msg = "Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok for Avp ";
432 msg += anna::diameter::functions::avpIdAsPairString(a_id);
433 anna::Logger::error(msg, ANNA_FILE_LOCATION);
438 bool Vnone = (stackAvp->getVbit() == stack::Avp::FlagRule::None);
440 bool Vmust = (stackAvp->getVbit() == stack::Avp::FlagRule::must);
442 bool Vmustnot = (stackAvp->getVbit() == stack::Avp::FlagRule::mustnot);
444 bool Mnone = (stackAvp->getMbit() == stack::Avp::FlagRule::None);
446 bool Mmust = (stackAvp->getMbit() == stack::Avp::FlagRule::must);
448 bool Mmustnot = (stackAvp->getMbit() == stack::Avp::FlagRule::mustnot);
450 bool Pnone = (stackAvp->getPbit() == stack::Avp::FlagRule::None);
452 bool Pmust = (stackAvp->getPbit() == stack::Avp::FlagRule::must);
454 bool Pmustnot = (stackAvp->getPbit() == stack::Avp::FlagRule::mustnot);
457 if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) {
458 std::string msg = "Vendor Bit (V) incoherence found for Avp ";
459 msg += stackAvp->getName();
460 anna::Logger::error(msg, ANNA_FILE_LOCATION);
464 // Exit on permissive mode:
465 if(getEngine()->ignoreFlagsOnValidation()) return true; // Ignore checking for AVP 'M' & 'P' bits
468 if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) {
469 std::string msg = "Mandatory Bit (M) incoherence found for Avp ";
470 msg += stackAvp->getName();
471 anna::Logger::error(msg, ANNA_FILE_LOCATION);
476 if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) {
477 std::string msg = "Encryption Bit (P) incoherence found for Avp ";
478 msg += stackAvp->getName();
479 anna::Logger::error(msg, ANNA_FILE_LOCATION);
484 if((a_flags & 0x1f) != 0x00) {
485 std::string msg = "Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null. Avp is ";
486 msg += stackAvp->getName();
487 anna::Logger::error(msg, ANNA_FILE_LOCATION);
495 //------------------------------------------------------------------------------
496 //----------------------------------------------------------------- Avp::setId()
497 //------------------------------------------------------------------------------
498 void Avp::setId(AvpId id) throw(anna::RuntimeException) {
499 // Generic AVP assignment has no sense
500 if(id == helpers::AVPID__AVP) return;
502 // Clear class content:
506 // Dictionary stack avp and format:
507 const stack::Avp *stackAvp = getStackAvp(); // based on dictionary and a_id
508 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
510 // Dictionary flags for known types:
512 if(stackAvp->getVbit() == stack::Avp::FlagRule::must) a_flags |= VBitMask;
514 if(stackAvp->getMbit() == stack::Avp::FlagRule::must) a_flags |= MBitMask;
516 if(stackAvp->getPbit() == stack::Avp::FlagRule::must) a_flags |= PBitMask;
518 if(a_id.second != 0) a_flags |= VBitMask; else a_flags &= (~VBitMask);
521 if(!stackFormat) { // Unknown Avp
523 std::string msg = "Unknown format for AVP identifier ";
524 msg += anna::diameter::functions::avpIdAsPairString(id);
525 msg += ". Raw data without specific format will be managed";
526 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
528 a_Unknown = new Unknown();
532 // Avp class formats (Avp child classes should implement this source code block for application-specific formats):
533 if(stackFormat->isOctetString()) a_OctetString = new OctetString();
534 else if(stackFormat->isInteger32()) a_Integer32 = new Integer32();
535 else if(stackFormat->isInteger64()) a_Integer64 = new Integer64();
536 else if(stackFormat->isUnsigned32()) a_Unsigned32 = new Unsigned32();
537 else if(stackFormat->isUnsigned64()) a_Unsigned64 = new Unsigned64();
538 else if(stackFormat->isFloat32()) a_Float32 = new Float32();
539 else if(stackFormat->isFloat64()) a_Float64 = new Float64();
540 //else if (stackFormat->isGrouped())
541 else if(stackFormat->isAddress()) a_Address = new Address();
542 else if(stackFormat->isTime()) a_Time = new Time();
543 else if(stackFormat->isUTF8String()) a_UTF8String = new UTF8String();
544 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity = new DiameterIdentity();
545 else if(stackFormat->isDiameterURI()) a_DiameterURI = new DiameterURI();
546 else if(stackFormat->isEnumerated()) a_Enumerated = new Enumerated();
547 else if(stackFormat->isIPFilterRule()) a_IPFilterRule = new IPFilterRule();
548 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule = new QoSFilterRule();
550 /////////////////////
551 // Format specific //
552 /////////////////////
553 allocationByFormat(stackFormat);
557 //------------------------------------------------------------------------------
558 //----------------------------------------------------------------- Avp::setId()
559 //------------------------------------------------------------------------------
560 void Avp::setId(const char *name) throw(anna::RuntimeException) {
561 setId(getEngine()->avpIdForName(name));
565 //------------------------------------------------------------------------------
566 //---------------------------------------------------------------- Avp::addAvp()
567 //------------------------------------------------------------------------------
568 Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) {
569 return addAvp(getEngine()->avpIdForName(name));
573 //------------------------------------------------------------------------------
574 //------------------------------------------------------------- Avp::removeAvp()
575 //------------------------------------------------------------------------------
576 bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) {
577 return removeAvp(getEngine()->avpIdForName(name), ocurrence);
581 //------------------------------------------------------------------------------
582 //--------------------------------------------------------------- Avp::_getAvp()
583 //------------------------------------------------------------------------------
584 const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
585 return getAvp(getEngine()->avpIdForName(name), ocurrence, emode);
589 //------------------------------------------------------------------------------
590 //-------------------------------------------------------------- Avp::countAvp()
591 //------------------------------------------------------------------------------
592 int Avp::countAvp(const char *name) const throw(anna::RuntimeException) {
593 return countAvp(getEngine()->avpIdForName(name));
596 //------------------------------------------------------------------------------
597 //------------------------------------------------------------- Avp::getLength()
598 //------------------------------------------------------------------------------
599 U24 Avp::getLength() const throw() {
602 const stack::Avp *stackAvp = getStackAvp();
603 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
605 result = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
608 result += a_Unknown->getSize();
612 if(stackFormat->isOctetString()) result += a_OctetString->getSize();
613 else if(stackFormat->isInteger32()) result += a_Integer32->getSize();
614 else if(stackFormat->isInteger64()) result += a_Integer64->getSize();
615 else if(stackFormat->isUnsigned32()) result += a_Unsigned32->getSize();
616 else if(stackFormat->isUnsigned64()) result += a_Unsigned64->getSize();
617 else if(stackFormat->isFloat32()) result += a_Float32->getSize();
618 else if(stackFormat->isFloat64()) result += a_Float64->getSize();
619 else if(stackFormat->isGrouped()) for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(avp(it)->getLength());
620 else if(stackFormat->isAddress()) result += a_Address->getSize();
621 else if(stackFormat->isTime()) result += a_Time->getSize();
622 else if(stackFormat->isUTF8String()) result += a_UTF8String->getSize();
623 else if(stackFormat->isDiameterIdentity()) result += a_DiameterIdentity->getSize();
624 else if(stackFormat->isDiameterURI()) result += a_DiameterURI->getSize();
625 else if(stackFormat->isEnumerated()) result += a_Enumerated->getSize();
626 else if(stackFormat->isIPFilterRule()) result += a_IPFilterRule->getSize();
627 else if(stackFormat->isQoSFilterRule()) result += a_QoSFilterRule->getSize();
629 /////////////////////
630 // Format specific //
631 /////////////////////
632 result += getLengthByFormat(stackFormat);
637 //------------------------------------------------------------------------------
638 //-------------------------------------------- Avp::unknownAvpWithMandatoryBit()
639 //------------------------------------------------------------------------------
640 void Avp::unknownAvpWithMandatoryBit() const throw(anna::RuntimeException) {
641 OamModule &oamModule = OamModule::instantiate();
642 const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id));
643 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid);
644 oamModule.count(OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit);
646 std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid);
647 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
651 //------------------------------------------------------------------------------
652 //-------------------------------------------------------- Avp::decodeDataPart()
653 //------------------------------------------------------------------------------
654 void Avp::decodeDataPart(const char * buffer, int size, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
656 OamModule &oamModule = OamModule::instantiate();
657 // Dictionary stack avp and format:
658 const stack::Avp *stackAvp = getStackAvp();
659 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
662 a_Unknown->decode(buffer, size);
666 if(stackFormat->isOctetString()) a_OctetString->decode(buffer, size);
667 else if(stackFormat->isInteger32()) a_Integer32->decode(buffer, size);
668 else if(stackFormat->isInteger64()) a_Integer64->decode(buffer, size);
669 else if(stackFormat->isUnsigned32()) a_Unsigned32->decode(buffer, size);
670 else if(stackFormat->isUnsigned64()) a_Unsigned64->decode(buffer, size);
671 else if(stackFormat->isFloat32()) a_Float32->decode(buffer, size);
672 else if(stackFormat->isFloat64()) a_Float64->decode(buffer, size);
673 else if(stackFormat->isGrouped()) {
675 LOGDEBUG(anna::Logger::debug("Grouped Avp has empty data part", ANNA_FILE_LOCATION));
679 if((size % 4) != 0) {
680 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
681 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
684 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
685 answer->setFailedAvp(parent, a_id);
688 throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION);
695 parent_t me = parent;
698 while(avpPos < size) {
700 avp = getEngine()->createAvp(NULL);
701 db.assign(buffer + avpPos, size - avpPos /* is valid to pass total size (indeed i don't know the real avp size) because it will be limited and this has deep copy disabled (no memory is reserved) */);
702 avp -> decode(db, me, answer);
703 } catch(anna::RuntimeException &ex) {
704 getEngine()->releaseAvp(avp);
709 avpPos += 4 * REQUIRED_WORDS(avp->getLength());
711 } else if(stackFormat->isAddress()) a_Address->decode(buffer, size);
712 else if(stackFormat->isTime()) a_Time->decode(buffer, size);
713 else if(stackFormat->isUTF8String()) a_UTF8String->decode(buffer, size);
714 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->decode(buffer, size);
715 else if(stackFormat->isDiameterURI()) a_DiameterURI->decode(buffer, size);
716 else if(stackFormat->isEnumerated()) a_Enumerated->decode(buffer, size);
717 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->decode(buffer, size);
718 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->decode(buffer, size);
720 /////////////////////
721 // Format specific //
722 /////////////////////
723 decodeDataPartByFormat(buffer, size, stackFormat);
726 //------------------------------------------------------------------------------
727 //---------------------------------------------------------------- Avp::decode()
728 //------------------------------------------------------------------------------
729 void Avp::decode(const anna::DataBlock &db, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
731 OamModule &oamModule = OamModule::instantiate();
733 if(db.getSize() < HeaderLengthVinactive) {
734 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
735 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
736 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
737 throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION);
740 const char * buffer = db.getData();
743 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
744 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
746 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
747 // | AVP Flags | AVP Length |
748 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749 // | Vendor-ID (opt) |
750 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753 // Code flags and vendor-id
754 U32 code = DECODE4BYTES_INDX_VALUETYPE(buffer, 0, U32);
756 a_flags = (S8)buffer[4];
758 U32 vendorID = helpers::VENDORID__base;
761 if(db.getSize() < HeaderLengthVactive) {
762 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
763 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
764 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
765 throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION);
768 vendorID = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32);
770 if(vendorID == helpers::VENDORID__base) {
771 // A vendor ID value of zero (0) corresponds to the IETF adopted AVP
772 // values, as managed by the IANA. Since the absence of the vendor
773 // ID field implies that the AVP in question is not vendor specific,
775 // implementations MUST NOT use the zero (0) vendor ID.
776 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
777 oamModule.count(OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
778 throw anna::RuntimeException(anna::functions::asString("Incoherence between activated V bit and zeroed vendor-id value received (avp code = %u)", code), ANNA_FILE_LOCATION);
783 setId(AvpId(code, vendorID));
784 // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received:
785 a_flags = (S8)buffer[4];
787 // Here i know id and flags:
788 // The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by
789 // a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
790 // Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
791 if(!getStackAvp() && mandatoryBit()) {
793 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED);
794 answer->setFailedAvp(parent, a_id);
797 unknownAvpWithMandatoryBit();
801 U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24);
802 // Data start position:
803 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
805 int dataBytes = length - startDataPos;
808 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
809 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
812 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
813 answer->setFailedAvp(parent, a_id);
816 throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION);
820 decodeDataPart(buffer + startDataPos, dataBytes, parent, answer);
821 } catch(anna::RuntimeException &ex) {
822 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence);
823 oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence);
826 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
827 answer->setFailedAvp(parent, a_id);
830 throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION);
835 //------------------------------------------------------------------------------
836 //----------------------------------------------------------- Avp::getStackAvp()
837 //------------------------------------------------------------------------------
838 const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() {
839 const stack::Dictionary * dictionary = engine->getDictionary();
840 return (dictionary ? (dictionary->getAvp(id)) : NULL);
844 //------------------------------------------------------------------------------
845 //------------------------------------------------------------------- Avp::fix()
846 //------------------------------------------------------------------------------
847 void Avp::fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw() {
849 if(avps.size() == 0) return; // empty content, nothing to fix
851 if(ruleBegin == ruleEnd) return; // no reference. Cannot fix
853 // Copy reference container and clear internal map in order to build a fixed version:
854 avp_container unfixedAvps;
856 for(const_avp_iterator it = avps.begin(); it != avps.end(); it++)
857 unfixedAvps[(*it).first] = (*it).second;
860 // Cache system reset (fix probably will invalidate cached findings):
862 insertionPositionForChilds = 0;
866 for(anna::diameter::stack::const_avprule_iterator rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
867 while((avp_it = Avp::avp_find(unfixedAvps, (*rule_it).second.getId(), 1)) != unfixedAvps.end()) {
868 avp = (*avp_it).second;
869 addChild(avps, insertionPositionForChilds, avp);
870 unfixedAvps.erase(avp_it); // processed
874 // Add remaining avps:
875 for(avp_it = unfixedAvps.begin(); avp_it != unfixedAvps.end(); avp_it++) {
876 avp = (*avp_it).second;
878 if(avp) addChild(avps, insertionPositionForChilds, avp);
882 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
885 if(avp->hasChildren()) avp->fix();
890 //------------------------------------------------------------------------------
891 //------------------------------------------------------------------- Avp::fix()
892 //------------------------------------------------------------------------------
893 void Avp::fix() throw() {
894 // Dictionary stack avp:
895 const stack::Avp *stackAvp = getStackAvp();
896 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
899 //LOGDEBUG(anna::Logger::debug("No dictionary avp reference found. Cannot fix.", ANNA_FILE_LOCATION));
903 if(!stackFormat || !stackFormat->isGrouped()) {
904 //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing to fix.", ANNA_FILE_LOCATION));
908 fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackAvp->avprule_begin(), stackAvp->avprule_end());
912 //------------------------------------------------------------------------------
913 //------------------------------------------------------------ Avp::validLevel()
914 //------------------------------------------------------------------------------
915 bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
918 OamModule &oamModule = OamModule::instantiate();
924 const_avp_iterator avp_it = avps.begin();
925 anna::diameter::stack::const_avprule_iterator rule_it;
928 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
931 if((*rule_it).second.isFixed()) {
932 if(avps.size() == 0) break; // cardinality checking will show this anomaly
934 if(avp_it != avps.end()) {
935 id = Avp::avp(avp_it)->getId();
937 if(id != (*rule_it).second.getId()) {
939 // Missing fixed rule: %s
940 } else if(Avp::avp_find(avps, id, 2) != avps.end()) {
942 // More than one fixed ocurrency for rule %s (*)
946 // (*) for (int k = 0; k < (*rule_it).second.getQualMax(); k++) avp_it++
952 // OAM & Depth management
953 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
954 oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule);
957 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
958 answer->setFailedAvp(parent, (*rule_it).second.getId());
961 engine->validationAnomaly(anna::functions::asString("Missing fixed rule %s inside %s", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
963 } else break; // finish fixed
967 // Cardinality // Mandatory control is implicit here
969 anna::diameter::stack::const_avprule_iterator generic_rule_it = ruleEnd;
970 int min, max, amount;
972 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
973 if((*rule_it).second.isAny()) { generic_rule_it = rule_it; continue; } // generic Avp will be managed after
975 id = (*rule_it).second.getId();
976 min = (*rule_it).second.getQualMin();
977 max = (*rule_it).second.getQualMax(); // -1 means infinite
978 amount = Avp::countAvp(avps, id);
980 if((amount < min) || ((max != -1) && (amount > max))) {
981 // Failed rule %s for cardinality (found %d items)
983 // OAM & Depth management
984 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
985 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality);
988 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded);
991 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
992 answer->setFailedAvp(parent, id);
995 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded);
998 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES);
999 answer->setFailedAvp(parent, id);
1003 engine->validationAnomaly(anna::functions::asString("Failed rule %s for cardinality (found %d items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1007 bool haveGeneric = (generic_rule_it != ruleEnd);
1012 std::map < AvpId, int /* dummy */ > disregarded; // 'Disregardeds' are Avps not in rules list
1013 std::map < AvpId, int /* dummy */ >::const_iterator disregarded_it;
1015 for(avp_it = avps.begin(); avp_it != avps.end(); avp_it++) {
1016 id = Avp::avp(avp_it)->getId();
1017 // Find rule for the child:
1018 foundInRules = false;
1020 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
1021 if((*rule_it).second.getId() == id) {
1022 foundInRules = true;
1028 disregarded[id] = 0;
1032 // Generic AVP cardinality checkings
1033 int disregardeds = disregarded.size();
1036 min = (*generic_rule_it).second.getQualMin();
1037 max = (*generic_rule_it).second.getQualMax(); // -1 means infinite
1038 amount = disregardeds;
1040 if((amount < min) || ((max != -1) && (amount > max))) {
1041 // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)
1043 // OAM & Depth management
1044 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
1045 oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem);
1048 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1049 answer->setFailedAvp(parent, id); // NO SENSE... what to put ?
1052 engine->validationAnomaly(anna::functions::asString("Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1054 } else if(disregardeds) { // When Generic AVP missing, no disregarded Avps are allowed
1055 // Found %d disregarded items inside %s and Generic AVP was not specified
1057 // Build disregarded list as string (unknown as avp id pair):
1058 std::string s_disregardeds = "";
1059 const stack::Avp *stackAvp;
1061 for(disregarded_it = disregarded.begin(); disregarded_it != disregarded.end(); disregarded_it++) {
1062 id = (*disregarded_it).first;
1063 stackAvp = getStackAvp(id, engine);
1064 s_disregardeds += (stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)));
1065 s_disregardeds += ", ";
1067 // We wouldn't know where are these disregarded, but...
1069 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1070 answer->setFailedAvp(parent, id);
1074 s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', '
1075 // OAM & Depth management
1076 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds));
1077 oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified);
1078 engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)));
1085 //------------------------------------------------------------------------------
1086 //----------------------------------------------------------------- Avp::valid()
1087 //------------------------------------------------------------------------------
1088 bool Avp::valid(const parent_t & parent, Message *answer) const throw(anna::RuntimeException) {
1090 OamModule &oamModule = OamModule::instantiate();
1091 // Dictionary stack avp:
1092 const stack::Avp *stackAvp = getStackAvp();
1093 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1096 // No dictionary avp reference found. Cannot validate
1097 return true; // perhaps a unknown Avp
1101 parent_t me = parent;
1102 me.addAvp(a_id, stackAvp->getName().c_str());
1105 // No format avp reference found. Cannot validate
1106 return true; // perhaps a unknown Avp
1109 //////////////////////////////
1110 // Flags coherence checking //
1111 //////////////////////////////
1112 bool result = flagsOK();
1115 // OAM & Depth management
1116 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()));
1117 oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules);
1120 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS);
1121 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); // RFC 6733 says nothing about Failed-AVP in this case...
1124 getEngine()->validationAnomaly(anna::functions::asString("The AVP %s flags (%d) does not fulfill the defined flag rules: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())));
1127 //////////////////////
1128 // Enumerated range //
1129 //////////////////////
1130 if(stackFormat->isEnumerated()) {
1131 if(!stackAvp->allowEnum(a_Enumerated->getValue())) {
1133 // OAM & Depth management
1134 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums());
1135 oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction);
1138 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
1139 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str());
1142 getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums()));
1146 ////////////////////
1147 // Level checking //
1148 ////////////////////
1149 result = Avp::validLevel(a_avps, stackAvp->avprule_begin(), stackAvp->avprule_end(), getEngine(), me, answer) && result;
1151 ////////////////////////
1152 // Childrens checking //
1153 ////////////////////////
1154 if(a_id == helpers::base::AVPID__Failed_AVP) return result; // DON'T VALIDATE CONTENT FOR Failed-AVP, because it won't be valid...
1156 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++)
1157 result = ((*it).second->valid(me, answer)) && result;
1163 //------------------------------------------------------------------------------
1164 //------------------------------------------------------------------ Avp::code()
1165 //------------------------------------------------------------------------------
1166 void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) {
1168 buffer[0] = (S8)(a_id.first >> 24);
1169 buffer[1] = (S8)(a_id.first >> 16);
1170 buffer[2] = (S8)(a_id.first >> 8);
1171 buffer[3] = (S8) a_id.first;
1174 buffer[4] = (S8) a_flags;
1175 buffer[5] = (S8)(size >> 16);
1176 buffer[6] = (S8)(size >> 8);
1177 buffer[7] = (S8) size;
1181 buffer[8] = (S8)(a_id.second >> 24);
1182 buffer[9] = (S8)(a_id.second >> 16);
1183 buffer[10] = (S8)(a_id.second >> 8);
1184 buffer[11] = (S8) a_id.second;
1187 // Data start position:
1188 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
1190 S8 * dataPart = buffer + startDataPos;
1191 int dataBytes; // not used but could be useful for checking (size - startDataPos)
1193 if(startDataPos == size) {
1194 LOGDEBUG(anna::Logger::debug("There is no data part to encode", ANNA_FILE_LOCATION));
1199 const stack::Avp *stackAvp = getStackAvp();
1200 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1203 a_Unknown->code(dataPart, dataBytes);
1207 if(stackFormat->isOctetString()) a_OctetString->code(dataPart, dataBytes);
1208 else if(stackFormat->isInteger32()) a_Integer32->code(dataPart, dataBytes);
1209 else if(stackFormat->isInteger64()) a_Integer64->code(dataPart, dataBytes);
1210 else if(stackFormat->isUnsigned32()) a_Unsigned32->code(dataPart, dataBytes);
1211 else if(stackFormat->isUnsigned64()) a_Unsigned64->code(dataPart, dataBytes);
1212 else if(stackFormat->isFloat32()) a_Float32->code(dataPart, dataBytes);
1213 else if(stackFormat->isFloat64()) a_Float64->code(dataPart, dataBytes);
1214 else if(stackFormat->isGrouped()) {
1215 // // Each avp encoding will remain padding octets depending on format. In order to
1216 // // code grouped content (each avp will be multiple of 4) we clean the entire buffer
1217 // // to ensure padding (easier than custom-made for each format):
1218 // memset(dataPart, 0, size - startDataPos);
1219 char *dataPartGrouped = dataPart;
1220 int dataBytesGrouped;
1222 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
1223 avp(it)->code(dataPartGrouped, dataBytesGrouped);
1224 dataPartGrouped = dataPartGrouped + 4 * REQUIRED_WORDS(dataBytesGrouped);
1226 } else if(stackFormat->isAddress()) a_Address->code(dataPart, dataBytes);
1227 else if(stackFormat->isTime()) a_Time->code(dataPart, dataBytes);
1228 else if(stackFormat->isUTF8String()) a_UTF8String->code(dataPart, dataBytes);
1229 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->code(dataPart, dataBytes);
1230 else if(stackFormat->isDiameterURI()) a_DiameterURI->code(dataPart, dataBytes);
1231 else if(stackFormat->isEnumerated()) a_Enumerated->code(dataPart, dataBytes);
1232 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->code(dataPart, dataBytes);
1233 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->code(dataPart, dataBytes);
1235 /////////////////////
1236 // Format specific //
1237 /////////////////////
1238 codeByFormat(dataPart, stackFormat);
1242 //------------------------------------------------------------------------------
1243 //------------------------------------------------------------ Avp::getXMLdata()
1244 //------------------------------------------------------------------------------
1245 std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() {
1246 std::string result = "";
1250 // if (!stackFormat) {
1252 // return a_Unknown->asHexString();
1254 // } catch (anna::RuntimeException &ex) {
1260 // Tricky situation: if you change the dictionary dynamically, and a previous formatted avp
1261 // becomes unknown (the change consists in remove Avps basically), then this would get a core
1262 // dump: a_Unknown = NULL. We are not going to protect that situation because it represents a
1263 // implementation fault, and there are many points which could have similar bad behaviour
1264 // (those where we access directly the a_Unknown pointer).
1265 // The best way to afford this is ... TODO:
1266 // Freeze dictionary after use from any resource (avp, message), setting a flag which deny
1267 // any modification in such dictionary. The best way to do this is on engine configuration
1268 // for Avp o Message, where we could invoke something like getEngine()->getDictionary()->freeze()
1270 return a_Unknown->asHexString(); // asHexString for OctetString cannot launch exception
1273 // Special case for Address: could launch exception if not printable
1275 if(stackFormat->isAddress()) return a_Address->asPrintableString();
1276 } catch(anna::RuntimeException&) {
1279 return a_Address->asHexString();
1283 if(stackFormat->isOctetString()) {
1285 return a_OctetString->asHexString();
1289 if(stackFormat->isInteger32()) return a_Integer32->asPrintableString();
1291 if(stackFormat->isInteger64()) return a_Integer64->asPrintableString();
1293 if(stackFormat->isUnsigned32()) return a_Unsigned32->asPrintableString();
1295 if(stackFormat->isUnsigned64()) return a_Unsigned64->asPrintableString();
1297 if(stackFormat->isFloat32()) return a_Float32->asPrintableString();
1299 if(stackFormat->isFloat64()) return a_Float64->asPrintableString();
1301 //if (stackFormat->isAddress()) return a_Address->asPrintableString();
1303 if(stackFormat->isTime()) return a_Time->asPrintableString();
1305 if(stackFormat->isUTF8String()) return a_UTF8String->asPrintableString();
1307 if(stackFormat->isDiameterIdentity()) return a_DiameterIdentity->asPrintableString();
1309 if(stackFormat->isDiameterURI()) return a_DiameterURI->asPrintableString();
1311 if(stackFormat->isEnumerated()) return a_Enumerated->asPrintableString();
1313 if(stackFormat->isIPFilterRule()) return a_IPFilterRule->asPrintableString();
1315 if(stackFormat->isQoSFilterRule()) return a_QoSFilterRule->asPrintableString();
1317 /////////////////////
1318 // Format specific //
1319 /////////////////////
1320 return getXMLdataByFormat(isHex, stackFormat);
1321 } catch(anna::RuntimeException &ex) {
1329 //------------------------------------------------------------------------------
1330 //---------------------------------------------------------------- Avp::decode()
1331 //------------------------------------------------------------------------------
1332 void Avp::decode(const anna::DataBlock &db) throw(anna::RuntimeException) {
1334 parent.setMessage(CommandId(0, false), "No-Parent");
1335 decode(db, parent, NULL);
1339 //------------------------------------------------------------------------------
1340 //--------------------------------------------------------------- Avp::fromXML()
1341 //------------------------------------------------------------------------------
1342 void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) {
1343 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1344 const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData;
1345 name = avpNode->getAttribute("name", false /* no exception */);
1346 code = avpNode->getAttribute("code", false /* no exception */);
1347 vendorCode = avpNode->getAttribute("vendor-code", false /* no exception */);
1348 flags = avpNode->getAttribute("flags", false /* no exception */);
1349 data = avpNode->getAttribute("data", false /* no exception */);
1350 hexData = avpNode->getAttribute("hex-data", false /* no exception */);
1352 const stack::Dictionary * dictionary = getEngine()->getDictionary();
1353 const stack::Avp *stackAvp = NULL;
1354 const stack::Format *stackFormat = NULL;
1359 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1360 msg += "'>: no dictionary available. Load one or use <'code' + 'flags' + 'vendorCode'> instead of <'name'>";
1361 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1364 stackAvp = dictionary->getAvp(name->getValue());
1367 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1368 msg += "'>: no avp found for this identifier at available dictionary";
1369 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1372 stackFormat = stackAvp->getFormat();
1375 // Check attributes exclusiveness
1376 if(name) { // compact mode
1378 if(code || vendorCode) {
1379 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1380 msg += "'>: avp attributes <'code' + 'vendorCode'> are not allowed if <'name'> is provided";
1381 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1384 // flags uncertainty:
1385 bool flagsUncertainty = ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1386 || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1387 /* umm, perhaps we could omit for bit P, whic is deprecated ... */
1388 /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ );
1389 if(flags && !flagsUncertainty) {
1390 std::string msg = "Be careful processing avp <name '"; msg += name->getValue();
1391 msg += "'> together with avp 'flags' attribute, because may/shouldnot uncertainty was not specified";
1392 LOGINFORMATION(Logger::information(msg, ANNA_FILE_LOCATION));
1395 setId(stackAvp->getId());
1397 //if (flags && flagsUncertainty) {
1400 int i_aux = flags->getIntegerValue();
1402 if(i_aux < 0 || i_aux > 256) {
1403 std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1404 msg += "': out of range [0,256]";
1405 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1413 if(!code || !flags || !vendorCode) {
1414 std::string s_code = code ? code->getValue() : "?";
1415 std::string s_flags = flags ? flags->getValue() : "?";
1416 std::string s_vendorCode = vendorCode ? vendorCode->getValue() : "?";
1417 std::string msg = "Error processing avp <code '"; msg += s_code;
1418 msg += "' + flags '"; msg += s_flags;
1419 msg += "' + vendorCode '"; msg += s_vendorCode;
1420 msg += "'>: all must be provided if <'name'> don't";
1421 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1425 int i_aux = code->getIntegerValue();
1429 std::string msg = "Error processing avp <code '"; msg += code->getValue();
1430 msg += "': negative value read from xml";
1431 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
1437 i_aux = flags->getIntegerValue();
1439 if(i_aux < 0 || i_aux > 256) {
1440 std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1441 msg += "': out of range [0,256]";
1442 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1446 int flagsBCK = a_flags;
1447 // VendorCode checks
1448 i_aux = vendorCode->getIntegerValue();
1451 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1452 msg += "': negative values are not allowed";
1453 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1456 U32 u_vendorCode = i_aux;
1457 bool vendorSpecific1 = (u_vendorCode != 0);
1458 bool vendorSpecific2 = (((a_flags) & VBitMask) != 0x00);
1460 if(vendorSpecific1 != vendorSpecific2) {
1461 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1462 msg += "' and avp <flags '"; msg += flags->getValue();
1463 msg += "': incompatible vendor-specific properties";
1464 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1467 // Final assignments
1468 setId(AvpId(u_code, u_vendorCode));
1469 // Flags could have been updated regarding dictionary, but during parsing we must respect xml file:
1471 stackAvp = getStackAvp();
1472 stackFormat = stackAvp ? stackAvp->getFormat() : NULL;
1476 // Check if grouped not confirmed
1477 anna::xml::Node::const_child_iterator it;
1478 anna::xml::Node::const_child_iterator minii = avpNode->child_begin();
1479 anna::xml::Node::const_child_iterator maxii = avpNode->child_end();
1480 const bool hasChildren(minii != maxii);
1483 // We need to confirm is grouped
1485 throw anna::RuntimeException("An xml avp node with children nodes could not confirmed as Grouped", ANNA_FILE_LOCATION);
1487 if(!stackFormat->isGrouped())
1488 throw anna::RuntimeException("An xml avp node with children nodes is not grouped type", ANNA_FILE_LOCATION);
1491 throw anna::RuntimeException("An xml avp node with children nodes has 'data' or 'hex-data' field", ANNA_FILE_LOCATION);
1495 std::string s_avp = name ? (name->getValue()) : (anna::diameter::functions::avpIdAsPairString(a_id));
1497 if(data && hexData) {
1498 std::string msg = "Not allowed both 'data' and 'hex-data' definitions. Avp ";
1500 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1504 bool unknown = !stackFormat;
1505 bool octetString = stackFormat && (stackFormat->isOctetString());
1507 if(data && (unknown || octetString)) {
1508 std::string msg = "Not recommended 'data' field at ";
1509 msg += unknown ? "Unknown" : "OctetString";
1510 msg += "-format Avp "; msg += s_avp;
1511 msg += ". Use better 'hex-data' or omit content fields if empty";
1512 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
1517 if(data) a_Unknown->fromPrintableString(data->getValue().c_str());
1518 else if(hexData) a_Unknown->fromHexString(hexData->getValue());
1523 if(stackFormat->isOctetString()) {
1524 if(data) a_OctetString->fromPrintableString(data->getValue().c_str());
1525 else if(hexData) a_OctetString->fromHexString(hexData->getValue());
1526 } else if(stackFormat->isInteger32()) {
1527 if(data) a_Integer32->fromPrintableString(data->getValue().c_str());
1528 else if(hexData) a_Integer32->fromHexString(hexData->getValue());
1529 } else if(stackFormat->isInteger64()) {
1530 if(data) a_Integer64->fromPrintableString(data->getValue().c_str());
1531 else if(hexData) a_Integer64->fromHexString(hexData->getValue());
1532 } else if(stackFormat->isUnsigned32()) {
1533 if(data) a_Unsigned32->fromPrintableString(data->getValue().c_str());
1534 else if(hexData) a_Unsigned32->fromHexString(hexData->getValue());
1535 } else if(stackFormat->isUnsigned64()) {
1536 if(data) a_Unsigned64->fromPrintableString(data->getValue().c_str());
1537 else if(hexData) a_Unsigned64->fromHexString(hexData->getValue());
1538 } else if(stackFormat->isFloat32()) {
1539 if(data) a_Float32->fromPrintableString(data->getValue().c_str());
1540 else if(hexData) a_Float32->fromHexString(hexData->getValue());
1541 } else if(stackFormat->isFloat64()) {
1542 if(data) a_Float64->fromPrintableString(data->getValue().c_str());
1543 else if(hexData) a_Float64->fromHexString(hexData->getValue());
1544 } else if(stackFormat->isGrouped()) {
1548 for(it = minii; it != maxii; it++) {
1549 std::string nodeName = (*it)->getName();
1551 if(nodeName != "avp") {
1552 std::string msg = "Unsupported grouped avp child node name '"; msg += nodeName;
1553 msg += "': use 'avp'";
1554 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1558 avp = getEngine()->createAvp(NULL);
1559 avp -> fromXML(*it);
1560 } catch(anna::RuntimeException &ex) {
1561 getEngine()->releaseAvp(avp);
1567 } else if(stackFormat->isAddress()) {
1568 if(data) a_Address->fromPrintableString(data->getValue().c_str());
1569 else if(hexData) a_Address->fromHexString(hexData->getValue());
1570 } else if(stackFormat->isTime()) {
1571 if(data) a_Time->fromPrintableString(data->getValue().c_str());
1572 else if(hexData) a_Time->fromHexString(hexData->getValue());
1573 } else if(stackFormat->isUTF8String()) {
1574 if(data) a_UTF8String->fromPrintableString(data->getValue().c_str());
1575 else if(hexData) a_UTF8String->fromHexString(hexData->getValue());
1576 } else if(stackFormat->isDiameterIdentity()) {
1577 if(data) a_DiameterIdentity->fromPrintableString(data->getValue().c_str());
1578 else if(hexData) a_DiameterIdentity->fromHexString(hexData->getValue());
1579 } else if(stackFormat->isDiameterURI()) {
1580 if(data) a_DiameterURI->fromPrintableString(data->getValue().c_str());
1581 else if(hexData) a_DiameterURI->fromHexString(hexData->getValue());
1582 } else if(stackFormat->isEnumerated()) {
1583 if(data) a_Enumerated->fromPrintableString(data->getValue().c_str());
1584 else if(hexData) a_Enumerated->fromHexString(hexData->getValue());
1585 } else if(stackFormat->isIPFilterRule()) {
1586 if(data) a_IPFilterRule->fromPrintableString(data->getValue().c_str());
1587 else if(hexData) a_IPFilterRule->fromHexString(hexData->getValue());
1588 } else if(stackFormat->isQoSFilterRule()) {
1589 if(data) a_QoSFilterRule->fromPrintableString(data->getValue().c_str());
1590 else if(hexData) a_QoSFilterRule->fromHexString(hexData->getValue());
1593 /////////////////////
1594 // Format specific //
1595 /////////////////////
1596 fromXMLByFormat(data, hexData, stackFormat);
1599 //------------------------------------------------------------------------------
1600 //----------------------------------------------------------------- Avp::asXML()
1601 //------------------------------------------------------------------------------
1602 anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() {
1603 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1604 anna::xml::Node* result = parent->createChild("avp");
1605 // Dictionary stack avp and format:
1606 const stack::Avp *stackAvp = getStackAvp();
1607 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1608 bool compactMode = (stackAvp && flagsOK());
1611 result->createAttribute("name", stackAvp->getName());
1612 // If may or shouldnot is present in AVP definition, we have to show flags to avoid uncertainty
1613 if ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1614 || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1615 /* umm, perhaps we could omit for bit P, whic is deprecated ... */
1616 /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ )
1617 result->createAttribute("flags", (int)a_flags);
1619 result->createAttribute("code", a_id.first);
1620 result->createAttribute("vendor-code", a_id.second);
1621 result->createAttribute("flags", (int)a_flags);
1624 // Grouped special case:
1625 if(stackFormat && stackFormat->isGrouped()) {
1626 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) avp(it)->asXML(result);
1631 // Data part literals:
1633 std::string value = getXMLdata(isHex, stackFormat);
1636 result->createAttribute("hex-data", value);
1638 result->createAttribute("data", value);
1639 const char *alias = stackAvp->getAlias(value);
1641 if(alias) result->createAttribute("alias", alias); // additional information
1648 //------------------------------------------------------------------------------
1649 //----------------------------------------------------------- Avp::asXMLString()
1650 //------------------------------------------------------------------------------
1651 std::string Avp::asXMLString() const throw() {
1652 anna::xml::Node root("root");
1653 return anna::xml::Compiler().apply(asXML(&root));
1657 //------------------------------------------------------------------------------
1658 //---------------------------------------------------------------- Avp::isLike()
1659 //------------------------------------------------------------------------------
1660 bool Avp::isLike(const std::string &pattern) const throw() {
1661 anna::RegularExpression re(pattern);
1662 return re.isLike(asXMLString());