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 //------------------------------------------------------------------------------
63 //------------------------------------------------------------------------------
64 //------------------------------------------------------------------- Avp::Avp()
65 //------------------------------------------------------------------------------
72 //------------------------------------------------------------------------------
73 //------------------------------------------------------------------ Avp::~Avp()
74 //------------------------------------------------------------------------------
80 //------------------------------------------------------------------------------
81 //------------------------------------------------------------- Avp::getEngine()
82 //------------------------------------------------------------------------------
83 Engine * Avp::getEngine() const throw(anna::RuntimeException) {
84 return a_engine ? a_engine : (a_engine = anna::functions::component <Engine> (ANNA_FILE_LOCATION));
88 //------------------------------------------------------------------------------
89 //------------------------------------------------------------ Avp::initialize()
90 //------------------------------------------------------------------------------
91 void Avp::initialize() throw() {
93 a_id = helpers::AVPID__AVP; // (0,0)
95 a_insertionPositionForChilds = 0;
107 a_DiameterIdentity = NULL;
108 a_DiameterURI = NULL;
110 a_IPFilterRule = NULL;
111 a_QoSFilterRule = NULL;
114 /////////////////////
115 // Format specific //
116 /////////////////////
117 initializeByFormat();
121 //------------------------------------------------------------------------------
122 //----------------------------------------------------------------- Avp::clear()
123 //------------------------------------------------------------------------------
124 void Avp::clear() throw(anna::RuntimeException) {
125 delete a_OctetString;
133 for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(avp(it)); }
139 delete a_DiameterIdentity;
140 delete a_DiameterURI;
142 delete a_IPFilterRule;
143 delete a_QoSFilterRule;
147 /////////////////////
148 // Format specific //
149 /////////////////////
156 //------------------------------------------------------------------------------
157 //-------------------------------------------------------------- Avp::avp_find()
158 //------------------------------------------------------------------------------
159 avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() {
163 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
166 if(aux && (aux->getId() == id)) {
169 if(match == position) return it;
177 //------------------------------------------------------------------------------
178 //---------------------------------------------------------------- Avp::addAvp()
179 //------------------------------------------------------------------------------
180 Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() {
181 Avp * result = engine->allocateAvp();
183 addChild(avps, insertionPositionForChilds, result);
188 //------------------------------------------------------------------------------
189 //------------------------------------------------------------- Avp::removeAvp()
190 //------------------------------------------------------------------------------
191 bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() {
192 bool removed = false;
193 bool do_remove = true;
194 int position = ocurrence;
196 if(position < 0) { /* reversed access */
197 position = countAvp(avps, id) + 1 + position;
199 // Special cases -> 0 and negative results:
200 // (1) User wants to remove the last, but no avp is found: position = 0 + 1 - 1 = 0 (would removes all but, no avp will be found: return now)
201 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (would removes all !!!: return to avoid unexpected behaviour)
202 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
203 if(position <= 0) do_remove = false;
207 int n = position ? position : 1 /* will search always the first and remove, the first and remove, the first and remove ... */;
210 while((it = avp_find(avps, id, n)) != avps.end()) {
211 engine->releaseAvp((*it).second);
220 // Cache system reset (remove will invalidate cached findings):
223 const stack::Avp *stackAvp = getStackAvp(id, engine);
224 std::string msg = "Removed Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
225 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
226 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
230 const stack::Avp *stackAvp = getStackAvp(id, engine);
231 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
232 msg += anna::functions::asString(" with provided ocurrence (%d), in order to be removed", ocurrence);
233 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
241 //------------------------------------------------------------------------------
242 //-------------------------------------------------------------- Avp::countAvp()
243 //------------------------------------------------------------------------------
244 int Avp::countAvp(const avp_container &avps, AvpId id) throw() {
246 const_avp_iterator it;
248 while((it = avp_find(avps, id, result + 1)) != avps.end()) result++;
254 //------------------------------------------------------------------------------
255 //-------------------------------------------------------------- Avp::firstAvp()
256 //------------------------------------------------------------------------------
257 const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() {
258 const_avp_iterator it = avp_find(avps, id, 1);
267 //------------------------------------------------------------------------------
268 //----------------------------------------------------------- Avp::countChilds()
269 //------------------------------------------------------------------------------
270 int Avp::countChilds(const avp_container &avps) throw() {
275 //------------------------------------------------------------------------------
276 //---------------------------------------------------------------- Avp::getAvp()
277 //------------------------------------------------------------------------------
278 const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
280 LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION));
284 bool do_search = true;
286 int position = ocurrence;
288 if(position < 0) { /* reversed access */
289 position = countAvp(avps, id) + 1 + position;
291 // Special cases -> 0 and negative results:
292 // (1) User wants to get the last, but no avp is found: position = 0 + 1 - 1 = 0 (can't find 0-position ...)
293 // (2) User wants to get some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (can't find 0-position ...)
294 // (2) User wants to get some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
295 if(position <= 0) do_search = false;
298 const Avp * result = NULL;
301 // Search at cache finds:
302 find_key key(id, position);
303 find_iterator fit = finds.find(key);
304 cached = (fit != finds.end());
307 result = (*fit).second;
309 const_avp_iterator it = avp_find(avps, id, position);
311 if(it != avps.end()) {
312 result = (*it).second;
313 finds[key] = const_cast<Avp*>(result); // store in cache
321 const stack::Avp *stackAvp = getStackAvp(id, engine);
322 std::string msg = "Found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
323 msg += anna::functions::asString(" with provided ocurrence (%d) which was ", ocurrence);
324 msg += cached ? "already cached:\n" : "the first search, now cached:\n";
325 msg += result->asXMLString();
326 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
333 case anna::Exception::Mode::Throw: {
334 const stack::Avp *stackAvp = getStackAvp(id, engine);
335 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
336 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
337 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
340 case anna::Exception::Mode::Trace: {
342 const stack::Avp *stackAvp = getStackAvp(id, engine);
343 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
344 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
345 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
349 case anna::Exception::Mode::Ignore: {
351 const stack::Avp *stackAvp = getStackAvp(id, engine);
352 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
353 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
354 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
364 //------------------------------------------------------------------------------
365 //--------------------------------------------------------------- Avp::_getAvp()
366 //------------------------------------------------------------------------------
367 const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
368 // Dictionary stack avp and format (this):
369 const stack::Avp *stackAvp = getStackAvp();
370 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
372 if(!stackFormat || !stackFormat->isGrouped())
373 throw anna::RuntimeException("This method only applies over grouped avps.", ANNA_FILE_LOCATION);
375 return getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
379 //------------------------------------------------------------------------------
380 //---------------------------------------------------------- Avp::assertFormat()
381 //------------------------------------------------------------------------------
382 void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) {
383 // Dictionary stack avp and format:
384 const stack::Avp *stackAvp = getStackAvp();
385 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
386 std::string format = stackFormat ? stackFormat->getName() : "Unknown";
389 std::string msg = "The Avp ";
390 msg += anna::diameter::functions::avpIdAsPairString(a_id);
391 msg += " with format '";
393 msg += "' is not compatible with the API method used (";
396 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
401 //------------------------------------------------------------------------------
402 //--------------------------------------------------------------- Avp::flagsOK()
403 //------------------------------------------------------------------------------
404 bool Avp::flagsOK() const throw() {
405 // Dictionary stack avp:
406 const stack::Avp *stackAvp = getStackAvp();
409 anna::Logger::error("Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok", ANNA_FILE_LOCATION);
414 bool Vnone = (stackAvp->getVbit() == stack::Avp::FlagRule::None);
416 bool Vmust = (stackAvp->getVbit() == stack::Avp::FlagRule::must);
418 bool Vmustnot = (stackAvp->getVbit() == stack::Avp::FlagRule::mustnot);
420 bool Mnone = (stackAvp->getMbit() == stack::Avp::FlagRule::None);
422 bool Mmust = (stackAvp->getMbit() == stack::Avp::FlagRule::must);
424 bool Mmustnot = (stackAvp->getMbit() == stack::Avp::FlagRule::mustnot);
426 bool Pnone = (stackAvp->getPbit() == stack::Avp::FlagRule::None);
428 bool Pmust = (stackAvp->getPbit() == stack::Avp::FlagRule::must);
430 bool Pmustnot = (stackAvp->getPbit() == stack::Avp::FlagRule::mustnot);
433 if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) {
434 anna::Logger::error("Vendor Bit (V) incoherence found", ANNA_FILE_LOCATION);
438 // Exit on permissive mode:
439 if(getEngine()->ignoreFlagsOnValidation()) return true; // Ignore checking for AVP 'M' & 'P' bits
442 if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) {
443 anna::Logger::error("Mandatory Bit (M) incoherence found", ANNA_FILE_LOCATION);
448 if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) {
449 anna::Logger::error("Encryption Bit (P) incoherence found", ANNA_FILE_LOCATION);
454 if((a_flags & 0x1f) != 0x00) {
455 anna::Logger::error("Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION);
463 //------------------------------------------------------------------------------
464 //----------------------------------------------------------------- Avp::setId()
465 //------------------------------------------------------------------------------
466 void Avp::setId(AvpId id) throw(anna::RuntimeException) {
467 // Generic AVP assignment has no sense
468 if(id == helpers::AVPID__AVP) return;
470 // Clear class content:
474 // Dictionary stack avp and format:
475 const stack::Avp *stackAvp = getStackAvp(); // based on dictionary and a_id
476 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
478 // Dictionary flags for known types:
480 if(stackAvp->getVbit() == stack::Avp::FlagRule::must) a_flags |= VBitMask;
482 if(stackAvp->getMbit() == stack::Avp::FlagRule::must) a_flags |= MBitMask;
484 if(stackAvp->getPbit() == stack::Avp::FlagRule::must) a_flags |= PBitMask;
486 if(a_id.second != 0) a_flags |= VBitMask; else a_flags &= (~VBitMask);
489 if(!stackFormat) { // Unknown Avp
491 std::string msg = "Unknown format for AVP identifier ";
492 msg += anna::diameter::functions::avpIdAsPairString(id);
493 msg += ". Raw data without specific format will be managed";
494 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
496 a_Unknown = new Unknown();
500 // Avp class formats (Avp child classes should implement this source code block for application-specific formats):
501 if(stackFormat->isOctetString()) a_OctetString = new OctetString();
502 else if(stackFormat->isInteger32()) a_Integer32 = new Integer32();
503 else if(stackFormat->isInteger64()) a_Integer64 = new Integer64();
504 else if(stackFormat->isUnsigned32()) a_Unsigned32 = new Unsigned32();
505 else if(stackFormat->isUnsigned64()) a_Unsigned64 = new Unsigned64();
506 else if(stackFormat->isFloat32()) a_Float32 = new Float32();
507 else if(stackFormat->isFloat64()) a_Float64 = new Float64();
508 //else if (stackFormat->isGrouped())
509 else if(stackFormat->isAddress()) a_Address = new Address();
510 else if(stackFormat->isTime()) a_Time = new Time();
511 else if(stackFormat->isUTF8String()) a_UTF8String = new UTF8String();
512 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity = new DiameterIdentity();
513 else if(stackFormat->isDiameterURI()) a_DiameterURI = new DiameterURI();
514 else if(stackFormat->isEnumerated()) a_Enumerated = new Enumerated();
515 else if(stackFormat->isIPFilterRule()) a_IPFilterRule = new IPFilterRule();
516 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule = new QoSFilterRule();
518 /////////////////////
519 // Format specific //
520 /////////////////////
521 allocationByFormat(stackFormat);
525 //------------------------------------------------------------------------------
526 //----------------------------------------------------------------- Avp::setId()
527 //------------------------------------------------------------------------------
528 void Avp::setId(const char *name) throw(anna::RuntimeException) {
529 setId(getEngine()->avpIdForName(name));
533 //------------------------------------------------------------------------------
534 //---------------------------------------------------------------- Avp::addAvp()
535 //------------------------------------------------------------------------------
536 Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) {
537 return addAvp(getEngine()->avpIdForName(name));
541 //------------------------------------------------------------------------------
542 //------------------------------------------------------------- Avp::removeAvp()
543 //------------------------------------------------------------------------------
544 bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) {
545 return removeAvp(getEngine()->avpIdForName(name), ocurrence);
549 //------------------------------------------------------------------------------
550 //--------------------------------------------------------------- Avp::_getAvp()
551 //------------------------------------------------------------------------------
552 const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
553 return getAvp(getEngine()->avpIdForName(name), ocurrence, emode);
557 //------------------------------------------------------------------------------
558 //-------------------------------------------------------------- Avp::countAvp()
559 //------------------------------------------------------------------------------
560 int Avp::countAvp(const char *name) const throw(anna::RuntimeException) {
561 return countAvp(getEngine()->avpIdForName(name));
564 //------------------------------------------------------------------------------
565 //------------------------------------------------------------- Avp::getLength()
566 //------------------------------------------------------------------------------
567 U24 Avp::getLength() const throw() {
570 const stack::Avp *stackAvp = getStackAvp();
571 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
573 result = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
576 result += a_Unknown->getSize();
580 if(stackFormat->isOctetString()) result += a_OctetString->getSize();
581 else if(stackFormat->isInteger32()) result += a_Integer32->getSize();
582 else if(stackFormat->isInteger64()) result += a_Integer64->getSize();
583 else if(stackFormat->isUnsigned32()) result += a_Unsigned32->getSize();
584 else if(stackFormat->isUnsigned64()) result += a_Unsigned64->getSize();
585 else if(stackFormat->isFloat32()) result += a_Float32->getSize();
586 else if(stackFormat->isFloat64()) result += a_Float64->getSize();
587 else if(stackFormat->isGrouped()) for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(avp(it)->getLength());
588 else if(stackFormat->isAddress()) result += a_Address->getSize();
589 else if(stackFormat->isTime()) result += a_Time->getSize();
590 else if(stackFormat->isUTF8String()) result += a_UTF8String->getSize();
591 else if(stackFormat->isDiameterIdentity()) result += a_DiameterIdentity->getSize();
592 else if(stackFormat->isDiameterURI()) result += a_DiameterURI->getSize();
593 else if(stackFormat->isEnumerated()) result += a_Enumerated->getSize();
594 else if(stackFormat->isIPFilterRule()) result += a_IPFilterRule->getSize();
595 else if(stackFormat->isQoSFilterRule()) result += a_QoSFilterRule->getSize();
597 /////////////////////
598 // Format specific //
599 /////////////////////
600 result += getLengthByFormat(stackFormat);
605 //------------------------------------------------------------------------------
606 //-------------------------------------------- Avp::unknownAvpWithMandatoryBit()
607 //------------------------------------------------------------------------------
608 void Avp::unknownAvpWithMandatoryBit() const throw(anna::RuntimeException) {
609 OamModule &oamModule = OamModule::instantiate();
610 const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id));
611 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid);
612 oamModule.count(OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit);
614 std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid);
615 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
619 //------------------------------------------------------------------------------
620 //-------------------------------------------------------- Avp::decodeDataPart()
621 //------------------------------------------------------------------------------
622 void Avp::decodeDataPart(const char * buffer, int size, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
624 OamModule &oamModule = OamModule::instantiate();
625 // Dictionary stack avp and format:
626 const stack::Avp *stackAvp = getStackAvp();
627 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
630 a_Unknown->decode(buffer, size);
634 if(stackFormat->isOctetString()) a_OctetString->decode(buffer, size);
635 else if(stackFormat->isInteger32()) a_Integer32->decode(buffer, size);
636 else if(stackFormat->isInteger64()) a_Integer64->decode(buffer, size);
637 else if(stackFormat->isUnsigned32()) a_Unsigned32->decode(buffer, size);
638 else if(stackFormat->isUnsigned64()) a_Unsigned64->decode(buffer, size);
639 else if(stackFormat->isFloat32()) a_Float32->decode(buffer, size);
640 else if(stackFormat->isFloat64()) a_Float64->decode(buffer, size);
641 else if(stackFormat->isGrouped()) {
643 LOGDEBUG(anna::Logger::debug("Grouped Avp has empty data part", ANNA_FILE_LOCATION));
647 if((size % 4) != 0) {
648 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
649 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
652 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
653 answer->setFailedAvp(parent, a_id);
656 throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION);
663 parent_t me = parent;
666 while(avpPos < size) {
668 avp = getEngine()->allocateAvp();
669 db.assign(buffer + avpPos, size - avpPos /* is valid to pass total size (indeed i don't know the real avp size) because it will be limited and this has deep copy disabled (no memory is reserved) */);
670 avp -> decode(db, me, answer);
671 } catch(anna::RuntimeException &ex) {
672 getEngine()->releaseAvp(avp);
677 avpPos += 4 * REQUIRED_WORDS(avp->getLength());
679 } else if(stackFormat->isAddress()) a_Address->decode(buffer, size);
680 else if(stackFormat->isTime()) a_Time->decode(buffer, size);
681 else if(stackFormat->isUTF8String()) a_UTF8String->decode(buffer, size);
682 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->decode(buffer, size);
683 else if(stackFormat->isDiameterURI()) a_DiameterURI->decode(buffer, size);
684 else if(stackFormat->isEnumerated()) a_Enumerated->decode(buffer, size);
685 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->decode(buffer, size);
686 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->decode(buffer, size);
688 /////////////////////
689 // Format specific //
690 /////////////////////
691 decodeDataPartByFormat(buffer, size, stackFormat);
694 //------------------------------------------------------------------------------
695 //---------------------------------------------------------------- Avp::decode()
696 //------------------------------------------------------------------------------
697 void Avp::decode(const anna::DataBlock &db, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
699 OamModule &oamModule = OamModule::instantiate();
701 if(db.getSize() < HeaderLengthVinactive) {
702 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
703 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
704 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
705 throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION);
708 const char * buffer = db.getData();
711 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
712 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
714 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
715 // | AVP Flags | AVP Length |
716 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
717 // | Vendor-ID (opt) |
718 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
721 // Code flags and vendor-id
722 U32 code = DECODE4BYTES_INDX_VALUETYPE(buffer, 0, U32);
724 a_flags = (S8)buffer[4];
726 U32 vendorID = helpers::VENDORID__base;
729 if(db.getSize() < HeaderLengthVactive) {
730 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
731 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
732 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
733 throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION);
736 vendorID = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32);
738 if(vendorID == helpers::VENDORID__base) {
739 // A vendor ID value of zero (0) corresponds to the IETF adopted AVP
740 // values, as managed by the IANA. Since the absence of the vendor
741 // ID field implies that the AVP in question is not vendor specific,
743 // implementations MUST NOT use the zero (0) vendor ID.
744 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
745 oamModule.count(OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
746 throw anna::RuntimeException(anna::functions::asString("Incoherence between activated V bit and zeroed vendor-id value received (avp code = %u)", code), ANNA_FILE_LOCATION);
751 setId(AvpId(code, vendorID));
752 // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received:
753 a_flags = (S8)buffer[4];
755 // Here i know id and flags:
756 // The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by
757 // a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
758 // Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
759 if(!getStackAvp() && mandatoryBit()) {
761 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED);
762 answer->setFailedAvp(parent, a_id);
765 unknownAvpWithMandatoryBit();
769 U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24);
770 // Data start position:
771 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
773 int dataBytes = length - startDataPos;
776 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
777 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
780 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
781 answer->setFailedAvp(parent, a_id);
784 throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION);
788 decodeDataPart(buffer + startDataPos, dataBytes, parent, answer);
789 } catch(anna::RuntimeException &ex) {
790 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence);
791 oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence);
794 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
795 answer->setFailedAvp(parent, a_id);
798 throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION);
803 //------------------------------------------------------------------------------
804 //----------------------------------------------------------- Avp::getStackAvp()
805 //------------------------------------------------------------------------------
806 const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() {
807 const stack::Dictionary * dictionary = engine->getDictionary();
808 return (dictionary ? (dictionary->getAvp(id)) : NULL);
812 //------------------------------------------------------------------------------
813 //------------------------------------------------------------------- Avp::fix()
814 //------------------------------------------------------------------------------
815 void Avp::fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw() {
817 if(avps.size() == 0) return; // empty content, nothing to fix
819 if(ruleBegin == ruleEnd) return; // no reference. Cannot fix
821 // Copy reference container and clear internal map in order to build a fixed version:
822 avp_container unfixedAvps;
824 for(const_avp_iterator it = avps.begin(); it != avps.end(); it++)
825 unfixedAvps[(*it).first] = (*it).second;
828 // Cache system reset (fix probably will invalidate cached findings):
830 insertionPositionForChilds = 0;
834 for(anna::diameter::stack::const_avprule_iterator rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
835 while((avp_it = Avp::avp_find(unfixedAvps, (*rule_it).second.getId(), 1)) != unfixedAvps.end()) {
836 avp = (*avp_it).second;
837 addChild(avps, insertionPositionForChilds, avp);
838 unfixedAvps.erase(avp_it); // processed
842 // Add remaining avps:
843 for(avp_it = unfixedAvps.begin(); avp_it != unfixedAvps.end(); avp_it++) {
844 avp = (*avp_it).second;
846 if(avp) addChild(avps, insertionPositionForChilds, avp);
850 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
853 if(avp->hasChildren()) avp->fix();
858 //------------------------------------------------------------------------------
859 //------------------------------------------------------------------- Avp::fix()
860 //------------------------------------------------------------------------------
861 void Avp::fix() throw() {
862 // Dictionary stack avp:
863 const stack::Avp *stackAvp = getStackAvp();
864 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
867 //LOGDEBUG(anna::Logger::debug("No dictionary avp reference found. Cannot fix.", ANNA_FILE_LOCATION));
871 if(!stackFormat || !stackFormat->isGrouped()) {
872 //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing to fix.", ANNA_FILE_LOCATION));
876 fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackAvp->avprule_begin(), stackAvp->avprule_end());
880 //------------------------------------------------------------------------------
881 //------------------------------------------------------------ Avp::validLevel()
882 //------------------------------------------------------------------------------
883 bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
886 OamModule &oamModule = OamModule::instantiate();
892 const_avp_iterator avp_it = avps.begin();
893 anna::diameter::stack::const_avprule_iterator rule_it;
896 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
899 if((*rule_it).second.isFixed()) {
900 if(avps.size() == 0) break; // cardinality checking will show this anomaly
902 if(avp_it != avps.end()) {
903 id = Avp::avp(avp_it)->getId();
905 if(id != (*rule_it).second.getId()) {
907 // Missing fixed rule: %s
908 } else if(Avp::avp_find(avps, id, 2) != avps.end()) {
910 // More than one fixed ocurrency for rule %s (*)
914 // (*) for (int k = 0; k < (*rule_it).second.getQualMax(); k++) avp_it++
920 // OAM & Depth management
921 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
922 oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule);
925 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
926 answer->setFailedAvp(parent, (*rule_it).second.getId());
929 engine->validationAnomaly(anna::functions::asString("Missing fixed rule %s inside %s", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
931 } else break; // finish fixed
935 // Cardinality // Mandatory control is implicit here
937 anna::diameter::stack::const_avprule_iterator generic_rule_it = ruleEnd;
938 int min, max, amount;
940 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
941 if((*rule_it).second.isAny()) { generic_rule_it = rule_it; continue; } // generic Avp will be managed after
943 id = (*rule_it).second.getId();
944 min = (*rule_it).second.getQualMin();
945 max = (*rule_it).second.getQualMax(); // -1 means infinite
946 amount = Avp::countAvp(avps, id);
948 if((amount < min) || ((max != -1) && (amount > max))) {
949 // Failed rule %s for cardinality (found %d items)
951 // OAM & Depth management
952 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
953 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality);
956 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded);
959 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
960 answer->setFailedAvp(parent, id);
963 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded);
966 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES);
967 answer->setFailedAvp(parent, id);
971 engine->validationAnomaly(anna::functions::asString("Failed rule %s for cardinality (found %d items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
975 bool haveGeneric = (generic_rule_it != ruleEnd);
980 std::map < AvpId, int /* dummy */ > disregarded; // 'Disregardeds' are Avps not in rules list
981 std::map < AvpId, int /* dummy */ >::const_iterator disregarded_it;
983 for(avp_it = avps.begin(); avp_it != avps.end(); avp_it++) {
984 id = Avp::avp(avp_it)->getId();
985 // Find rule for the child:
986 foundInRules = false;
988 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
989 if((*rule_it).second.getId() == id) {
1000 // Generic AVP cardinality checkings
1001 int disregardeds = disregarded.size();
1004 min = (*generic_rule_it).second.getQualMin();
1005 max = (*generic_rule_it).second.getQualMax(); // -1 means infinite
1006 amount = disregardeds;
1008 if((amount < min) || ((max != -1) && (amount > max))) {
1009 // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)
1011 // OAM & Depth management
1012 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
1013 oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem);
1016 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1017 answer->setFailedAvp(parent, id); // NO SENSE... what to put ?
1020 engine->validationAnomaly(anna::functions::asString("Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1022 } else if(disregardeds) { // When Generic AVP missing, no disregarded Avps are allowed
1023 // Found %d disregarded items inside %s and Generic AVP was not specified
1025 // Build disregarded list as string (unknown as avp id pair):
1026 std::string s_disregardeds = "";
1027 const stack::Avp *stackAvp;
1029 for(disregarded_it = disregarded.begin(); disregarded_it != disregarded.end(); disregarded_it++) {
1030 id = (*disregarded_it).first;
1031 stackAvp = getStackAvp(id, engine);
1032 s_disregardeds += (stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)));
1033 s_disregardeds += ", ";
1035 // We wouldn't know where are these disregarded, but...
1037 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1038 answer->setFailedAvp(parent, id);
1042 s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', '
1043 // OAM & Depth management
1044 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds));
1045 oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified);
1046 engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)));
1053 //------------------------------------------------------------------------------
1054 //----------------------------------------------------------------- Avp::valid()
1055 //------------------------------------------------------------------------------
1056 bool Avp::valid(const parent_t & parent, Message *answer) const throw(anna::RuntimeException) {
1058 OamModule &oamModule = OamModule::instantiate();
1059 // Dictionary stack avp:
1060 const stack::Avp *stackAvp = getStackAvp();
1061 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1064 // No dictionary avp reference found. Cannot validate
1065 return true; // perhaps a unknown Avp
1069 parent_t me = parent;
1070 me.addAvp(a_id, stackAvp->getName().c_str());
1073 // No format avp reference found. Cannot validate
1074 return true; // perhaps a unknown Avp
1077 //////////////////////////////
1078 // Flags coherence checking //
1079 //////////////////////////////
1080 bool result = flagsOK();
1083 // OAM & Depth management
1084 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()));
1085 oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules);
1088 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS);
1089 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); // RFC 6733 says nothing about Failed-AVP in this case...
1092 getEngine()->validationAnomaly(anna::functions::asString("The AVP %s flags (%d) does not fulfill the defined flag rules: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())));
1095 //////////////////////
1096 // Enumerated range //
1097 //////////////////////
1098 if(stackFormat->isEnumerated()) {
1099 if(!stackAvp->allowEnum(a_Enumerated->getValue())) {
1101 // OAM & Depth management
1102 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums());
1103 oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction);
1106 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
1107 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str());
1110 getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums()));
1114 ////////////////////
1115 // Level checking //
1116 ////////////////////
1117 result = Avp::validLevel(a_avps, stackAvp->avprule_begin(), stackAvp->avprule_end(), getEngine(), me, answer) && result;
1119 ////////////////////////
1120 // Childrens checking //
1121 ////////////////////////
1122 if(a_id == helpers::base::AVPID__Failed_AVP) return result; // DON'T VALIDATE CONTENT FOR Failed-AVP, because it won't be valid...
1124 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++)
1125 result = ((*it).second->valid(me, answer)) && result;
1131 //------------------------------------------------------------------------------
1132 //------------------------------------------------------------------ Avp::code()
1133 //------------------------------------------------------------------------------
1134 void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) {
1136 buffer[0] = (S8)(a_id.first >> 24);
1137 buffer[1] = (S8)(a_id.first >> 16);
1138 buffer[2] = (S8)(a_id.first >> 8);
1139 buffer[3] = (S8) a_id.first;
1142 buffer[4] = (S8) a_flags;
1143 buffer[5] = (S8)(size >> 16);
1144 buffer[6] = (S8)(size >> 8);
1145 buffer[7] = (S8) size;
1149 buffer[8] = (S8)(a_id.second >> 24);
1150 buffer[9] = (S8)(a_id.second >> 16);
1151 buffer[10] = (S8)(a_id.second >> 8);
1152 buffer[11] = (S8) a_id.second;
1155 // Data start position:
1156 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
1158 S8 * dataPart = buffer + startDataPos;
1159 int dataBytes; // not used but could be useful for checking (size - startDataPos)
1161 if(startDataPos == size) {
1162 LOGDEBUG(anna::Logger::debug("There is no data part to encode", ANNA_FILE_LOCATION));
1167 const stack::Avp *stackAvp = getStackAvp();
1168 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1171 a_Unknown->code(dataPart, dataBytes);
1175 if(stackFormat->isOctetString()) a_OctetString->code(dataPart, dataBytes);
1176 else if(stackFormat->isInteger32()) a_Integer32->code(dataPart, dataBytes);
1177 else if(stackFormat->isInteger64()) a_Integer64->code(dataPart, dataBytes);
1178 else if(stackFormat->isUnsigned32()) a_Unsigned32->code(dataPart, dataBytes);
1179 else if(stackFormat->isUnsigned64()) a_Unsigned64->code(dataPart, dataBytes);
1180 else if(stackFormat->isFloat32()) a_Float32->code(dataPart, dataBytes);
1181 else if(stackFormat->isFloat64()) a_Float64->code(dataPart, dataBytes);
1182 else if(stackFormat->isGrouped()) {
1183 // // Each avp encoding will remain padding octets depending on format. In order to
1184 // // code grouped content (each avp will be multiple of 4) we clean the entire buffer
1185 // // to ensure padding (easier than custom-made for each format):
1186 // memset(dataPart, 0, size - startDataPos);
1187 char *dataPartGrouped = dataPart;
1188 int dataBytesGrouped;
1190 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
1191 avp(it)->code(dataPartGrouped, dataBytesGrouped);
1192 dataPartGrouped = dataPartGrouped + 4 * REQUIRED_WORDS(dataBytesGrouped);
1194 } else if(stackFormat->isAddress()) a_Address->code(dataPart, dataBytes);
1195 else if(stackFormat->isTime()) a_Time->code(dataPart, dataBytes);
1196 else if(stackFormat->isUTF8String()) a_UTF8String->code(dataPart, dataBytes);
1197 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->code(dataPart, dataBytes);
1198 else if(stackFormat->isDiameterURI()) a_DiameterURI->code(dataPart, dataBytes);
1199 else if(stackFormat->isEnumerated()) a_Enumerated->code(dataPart, dataBytes);
1200 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->code(dataPart, dataBytes);
1201 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->code(dataPart, dataBytes);
1203 /////////////////////
1204 // Format specific //
1205 /////////////////////
1206 codeByFormat(dataPart, stackFormat);
1210 //------------------------------------------------------------------------------
1211 //------------------------------------------------------------ Avp::getXMLdata()
1212 //------------------------------------------------------------------------------
1213 std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() {
1214 std::string result = "";
1218 // if (!stackFormat) {
1220 // return a_Unknown->asHexString();
1222 // } catch (anna::RuntimeException &ex) {
1228 return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad
1231 // Special case for Address: could launch exception if not printable
1233 if(stackFormat->isAddress()) return a_Address->asPrintableString();
1234 } catch(anna::RuntimeException&) {
1237 return a_Address->asHexString();
1241 if(stackFormat->isOctetString()) {
1243 return a_OctetString->asHexString();
1247 if(stackFormat->isInteger32()) return a_Integer32->asPrintableString();
1249 if(stackFormat->isInteger64()) return a_Integer64->asPrintableString();
1251 if(stackFormat->isUnsigned32()) return a_Unsigned32->asPrintableString();
1253 if(stackFormat->isUnsigned64()) return a_Unsigned64->asPrintableString();
1255 if(stackFormat->isFloat32()) return a_Float32->asPrintableString();
1257 if(stackFormat->isFloat64()) return a_Float64->asPrintableString();
1259 //if (stackFormat->isAddress()) return a_Address->asPrintableString();
1261 if(stackFormat->isTime()) return a_Time->asPrintableString();
1263 if(stackFormat->isUTF8String()) return a_UTF8String->asPrintableString();
1265 if(stackFormat->isDiameterIdentity()) return a_DiameterIdentity->asPrintableString();
1267 if(stackFormat->isDiameterURI()) return a_DiameterURI->asPrintableString();
1269 if(stackFormat->isEnumerated()) return a_Enumerated->asPrintableString();
1271 if(stackFormat->isIPFilterRule()) return a_IPFilterRule->asPrintableString();
1273 if(stackFormat->isQoSFilterRule()) return a_QoSFilterRule->asPrintableString();
1275 /////////////////////
1276 // Format specific //
1277 /////////////////////
1278 return getXMLdataByFormat(isHex, stackFormat);
1279 } catch(anna::RuntimeException &ex) {
1287 //------------------------------------------------------------------------------
1288 //---------------------------------------------------------------- Avp::decode()
1289 //------------------------------------------------------------------------------
1290 void Avp::decode(const anna::DataBlock &db) throw(anna::RuntimeException) {
1292 parent.setMessage(CommandId(0, false), "No-Parent");
1293 decode(db, parent, NULL);
1297 //------------------------------------------------------------------------------
1298 //--------------------------------------------------------------- Avp::fromXML()
1299 //------------------------------------------------------------------------------
1300 void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) {
1301 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1302 const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData;
1303 name = avpNode->getAttribute("name", false /* no exception */);
1304 code = avpNode->getAttribute("code", false /* no exception */);
1305 vendorCode = avpNode->getAttribute("vendor-code", false /* no exception */);
1306 flags = avpNode->getAttribute("flags", false /* no exception */);
1307 data = avpNode->getAttribute("data", false /* no exception */);
1308 hexData = avpNode->getAttribute("hex-data", false /* no exception */);
1310 const stack::Dictionary * dictionary = getEngine()->getDictionary();
1311 const stack::Avp *stackAvp = NULL;
1312 const stack::Format *stackFormat = NULL;
1317 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1318 msg += "'>: no dictionary available. Load one or use <'code' + 'flags' + 'vendorCode'> instead of <'name'>";
1319 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1322 stackAvp = dictionary->getAvp(name->getValue());
1325 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1326 msg += "'>: no avp found for this identifier at available dictionary";
1327 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1330 stackFormat = stackAvp->getFormat();
1333 // Check attributes exclusiveness
1334 if(name) { // compact mode
1335 bool allowFlagsField = ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1336 || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1337 /* umm, perhaps we could omit for bit P, whic is deprecated ... */
1338 /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ );
1339 if(code || (flags && !allowFlagsField) || vendorCode) {
1340 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1341 if (flags) msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided (also flags is not permitted: no may, no shouldnot)";
1342 else msg += "'>: avp attributes <'code' + 'vendorCode'> are not allowed if <'name'> is provided";
1343 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1346 setId(stackAvp->getId());
1348 if (flags && allowFlagsField) {
1350 int i_aux = flags->getIntegerValue();
1352 if(i_aux < 0 || i_aux > 256) {
1353 std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1354 msg += "': out of range [0,256]";
1355 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1363 if(!code || !flags || !vendorCode) {
1364 std::string s_code = code ? code->getValue() : "?";
1365 std::string s_flags = flags ? flags->getValue() : "?";
1366 std::string s_vendorCode = vendorCode ? vendorCode->getValue() : "?";
1367 std::string msg = "Error processing avp <code '"; msg += s_code;
1368 msg += "' + flags '"; msg += s_flags;
1369 msg += "' + vendorCode '"; msg += s_vendorCode;
1370 msg += "'>: all must be provided if <'name'> don't";
1371 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1375 int i_aux = code->getIntegerValue();
1378 std::string msg = "Error processing avp <code '"; msg += code->getValue();
1379 msg += "': negative values are not allowed";
1380 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1385 i_aux = flags->getIntegerValue();
1387 if(i_aux < 0 || i_aux > 256) {
1388 std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1389 msg += "': out of range [0,256]";
1390 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1394 int flagsBCK = a_flags;
1395 // VendorCode checks
1396 i_aux = vendorCode->getIntegerValue();
1399 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1400 msg += "': negative values are not allowed";
1401 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1404 U32 u_vendorCode = i_aux;
1405 bool vendorSpecific1 = (u_vendorCode != 0);
1406 bool vendorSpecific2 = (((a_flags) & VBitMask) != 0x00);
1408 if(vendorSpecific1 != vendorSpecific2) {
1409 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1410 msg += "' and avp <flags '"; msg += flags->getValue();
1411 msg += "': incompatible vendor-specific properties";
1412 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1415 // Final assignments
1416 setId(AvpId(u_code, u_vendorCode));
1417 // Flags could have been updated regarding dictionary, but during parsing we must respect xml file:
1419 stackAvp = getStackAvp();
1420 stackFormat = stackAvp ? stackAvp->getFormat() : NULL;
1424 // Check if grouped not confirmed
1425 anna::xml::Node::const_child_iterator it;
1426 anna::xml::Node::const_child_iterator minii = avpNode->child_begin();
1427 anna::xml::Node::const_child_iterator maxii = avpNode->child_end();
1428 const bool hasChildren(minii != maxii);
1431 // We need to confirm is grouped
1433 throw anna::RuntimeException("An xml avp node with children nodes could not confirmed as Grouped", ANNA_FILE_LOCATION);
1435 if(!stackFormat->isGrouped())
1436 throw anna::RuntimeException("An xml avp node with children nodes is not grouped type", ANNA_FILE_LOCATION);
1439 throw anna::RuntimeException("An xml avp node with children nodes has 'data' or 'hex-data' field", ANNA_FILE_LOCATION);
1443 std::string s_avp = name ? (name->getValue()) : (anna::diameter::functions::avpIdAsPairString(a_id));
1445 if(data && hexData) {
1446 std::string msg = "Not allowed both 'data' and 'hex-data' definitions. Avp ";
1448 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1452 bool unknown = !stackFormat;
1453 bool octetString = stackFormat && (stackFormat->isOctetString());
1455 if(data && (unknown || octetString)) {
1456 std::string msg = "Not recommended 'data' field at ";
1457 msg += unknown ? "Unknown" : "OctetString";
1458 msg += "-format Avp "; msg += s_avp;
1459 msg += ". Use better 'hex-data' or omit content fields if empty";
1460 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
1465 if(data) a_Unknown->fromPrintableString(data->getValue().c_str());
1466 else if(hexData) a_Unknown->fromHexString(hexData->getValue());
1471 if(stackFormat->isOctetString()) {
1472 if(data) a_OctetString->fromPrintableString(data->getValue().c_str());
1473 else if(hexData) a_OctetString->fromHexString(hexData->getValue());
1474 } else if(stackFormat->isInteger32()) {
1475 if(data) a_Integer32->fromPrintableString(data->getValue().c_str());
1476 else if(hexData) a_Integer32->fromHexString(hexData->getValue());
1477 } else if(stackFormat->isInteger64()) {
1478 if(data) a_Integer64->fromPrintableString(data->getValue().c_str());
1479 else if(hexData) a_Integer64->fromHexString(hexData->getValue());
1480 } else if(stackFormat->isUnsigned32()) {
1481 if(data) a_Unsigned32->fromPrintableString(data->getValue().c_str());
1482 else if(hexData) a_Unsigned32->fromHexString(hexData->getValue());
1483 } else if(stackFormat->isUnsigned64()) {
1484 if(data) a_Unsigned64->fromPrintableString(data->getValue().c_str());
1485 else if(hexData) a_Unsigned64->fromHexString(hexData->getValue());
1486 } else if(stackFormat->isFloat32()) {
1487 if(data) a_Float32->fromPrintableString(data->getValue().c_str());
1488 else if(hexData) a_Float32->fromHexString(hexData->getValue());
1489 } else if(stackFormat->isFloat64()) {
1490 if(data) a_Float64->fromPrintableString(data->getValue().c_str());
1491 else if(hexData) a_Float64->fromHexString(hexData->getValue());
1492 } else if(stackFormat->isGrouped()) {
1496 for(it = minii; it != maxii; it++) {
1497 std::string nodeName = (*it)->getName();
1499 if(nodeName != "avp") {
1500 std::string msg = "Unsupported grouped avp child node name '"; msg += nodeName;
1501 msg += "': use 'avp'";
1502 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1506 avp = getEngine()->allocateAvp();
1507 avp -> fromXML(*it);
1508 } catch(anna::RuntimeException &ex) {
1509 getEngine()->releaseAvp(avp);
1515 } else if(stackFormat->isAddress()) {
1516 if(data) a_Address->fromPrintableString(data->getValue().c_str());
1517 else if(hexData) a_Address->fromHexString(hexData->getValue());
1518 } else if(stackFormat->isTime()) {
1519 if(data) a_Time->fromPrintableString(data->getValue().c_str());
1520 else if(hexData) a_Time->fromHexString(hexData->getValue());
1521 } else if(stackFormat->isUTF8String()) {
1522 if(data) a_UTF8String->fromPrintableString(data->getValue().c_str());
1523 else if(hexData) a_UTF8String->fromHexString(hexData->getValue());
1524 } else if(stackFormat->isDiameterIdentity()) {
1525 if(data) a_DiameterIdentity->fromPrintableString(data->getValue().c_str());
1526 else if(hexData) a_DiameterIdentity->fromHexString(hexData->getValue());
1527 } else if(stackFormat->isDiameterURI()) {
1528 if(data) a_DiameterURI->fromPrintableString(data->getValue().c_str());
1529 else if(hexData) a_DiameterURI->fromHexString(hexData->getValue());
1530 } else if(stackFormat->isEnumerated()) {
1531 if(data) a_Enumerated->fromPrintableString(data->getValue().c_str());
1532 else if(hexData) a_Enumerated->fromHexString(hexData->getValue());
1533 } else if(stackFormat->isIPFilterRule()) {
1534 if(data) a_IPFilterRule->fromPrintableString(data->getValue().c_str());
1535 else if(hexData) a_IPFilterRule->fromHexString(hexData->getValue());
1536 } else if(stackFormat->isQoSFilterRule()) {
1537 if(data) a_QoSFilterRule->fromPrintableString(data->getValue().c_str());
1538 else if(hexData) a_QoSFilterRule->fromHexString(hexData->getValue());
1541 /////////////////////
1542 // Format specific //
1543 /////////////////////
1544 fromXMLByFormat(data, hexData, stackFormat);
1547 //------------------------------------------------------------------------------
1548 //----------------------------------------------------------------- Avp::asXML()
1549 //------------------------------------------------------------------------------
1550 anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() {
1551 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1552 anna::xml::Node* result = parent->createChild("avp");
1553 // Dictionary stack avp and format:
1554 const stack::Avp *stackAvp = getStackAvp();
1555 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1556 bool compactMode = (stackAvp && flagsOK());
1559 result->createAttribute("name", stackAvp->getName());
1560 // If may or shouldnot is present in AVP definition, we have to show flags to avoid uncertainty
1561 if ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1562 || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
1563 /* umm, perhaps we could omit for bit P, whic is deprecated ... */
1564 /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ )
1565 result->createAttribute("flags", (int)a_flags);
1567 result->createAttribute("code", a_id.first);
1568 result->createAttribute("vendor-code", a_id.second);
1569 result->createAttribute("flags", (int)a_flags);
1572 // Grouped special case:
1573 if(stackFormat && stackFormat->isGrouped()) {
1574 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) avp(it)->asXML(result);
1579 // Data part literals:
1581 std::string value = getXMLdata(isHex, stackFormat);
1584 result->createAttribute("hex-data", value);
1586 result->createAttribute("data", value);
1587 const char *alias = stackAvp->getAlias(value);
1589 if(alias) result->createAttribute("alias", alias); // additional information
1596 //------------------------------------------------------------------------------
1597 //----------------------------------------------------------- Avp::asXMLString()
1598 //------------------------------------------------------------------------------
1599 std::string Avp::asXMLString() const throw() {
1600 anna::xml::Node root("root");
1601 return anna::xml::Compiler().apply(asXML(&root));
1605 //------------------------------------------------------------------------------
1606 //---------------------------------------------------------------- Avp::isLike()
1607 //------------------------------------------------------------------------------
1608 bool Avp::isLike(const std::string &pattern) const throw() {
1609 anna::RegularExpression re(pattern);
1610 return re.isLike(asXMLString());