1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
38 #include <anna/diameter/codec/Avp.hpp>
39 #include <anna/diameter/codec/Format.hpp>
41 #include <anna/config/defines.hpp> // general types, decoding helpers (DECODE[2/3/4]BYTES_INDX_VALUETYPE), etc.
42 #include <anna/diameter/functions.hpp>
43 #include <anna/diameter/helpers/defines.hpp>
44 #include <anna/diameter/codec/basetypes/basetypes.hpp>
45 #include <anna/diameter/codec/functions.hpp> // REQUIRED_WORDS
46 #include <anna/diameter/codec/OamModule.hpp>
47 #include <anna/diameter/stack/Avp.hpp>
48 #include <anna/diameter/stack/Format.hpp>
49 #include <anna/diameter/stack/Dictionary.hpp>
50 #include <anna/diameter/stack/Engine.hpp>
51 #include <anna/diameter/codec/Engine.hpp>
52 #include <anna/core/functions.hpp>
54 #include <anna/core/tracing/Logger.hpp>
55 #include <anna/core/functions.hpp>
56 #include <anna/core/tracing/TraceMethod.hpp>
57 #include <anna/xml/xml.hpp>
64 using namespace anna::diameter::codec;
73 const int Avp::HeaderLengthVactive(12);
74 const int Avp::HeaderLengthVinactive(8);
75 const U8 Avp::VBitMask(0x80);
76 const U8 Avp::MBitMask(0x40);
77 const U8 Avp::PBitMask(0x20);
82 //------------------------------------------------------------------------------
83 //------------------------------------------------------------------- Avp::Avp()
84 //------------------------------------------------------------------------------
90 //------------------------------------------------------------------------------
91 //------------------------------------------------------------------- Avp::Avp()
92 //------------------------------------------------------------------------------
99 //------------------------------------------------------------------------------
100 //------------------------------------------------------------------ Avp::~Avp()
101 //------------------------------------------------------------------------------
107 //------------------------------------------------------------------------------
108 //------------------------------------------------------------- Avp::getEngine()
109 //------------------------------------------------------------------------------
110 Engine * Avp::getEngine() const throw(anna::RuntimeException) {
111 return a_engine ? a_engine : (a_engine = anna::functions::component <Engine> (ANNA_FILE_LOCATION));
115 //------------------------------------------------------------------------------
116 //------------------------------------------------------------ Avp::initialize()
117 //------------------------------------------------------------------------------
118 void Avp::initialize() throw() {
120 a_id = helpers::AVPID__AVP; // (0,0)
122 a_insertionPositionForChilds = 0;
123 a_OctetString = NULL;
134 a_DiameterIdentity = NULL;
135 a_DiameterURI = NULL;
137 a_IPFilterRule = NULL;
138 a_QoSFilterRule = NULL;
141 /////////////////////
142 // Format specific //
143 /////////////////////
144 initializeByFormat();
148 //------------------------------------------------------------------------------
149 //----------------------------------------------------------------- Avp::clear()
150 //------------------------------------------------------------------------------
151 void Avp::clear() throw(anna::RuntimeException) {
152 delete a_OctetString;
160 for(avp_iterator it = avp_begin(); it != avp_end(); it++) { /*avp(it)->clear(); */getEngine()->releaseAvp(avp(it)); }
166 delete a_DiameterIdentity;
167 delete a_DiameterURI;
169 delete a_IPFilterRule;
170 delete a_QoSFilterRule;
174 /////////////////////
175 // Format specific //
176 /////////////////////
183 //------------------------------------------------------------------------------
184 //-------------------------------------------------------------- Avp::avp_find()
185 //------------------------------------------------------------------------------
186 avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() {
190 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
193 if(aux && (aux->getId() == id)) {
196 if(match == position) return it;
204 //------------------------------------------------------------------------------
205 //---------------------------------------------------------------- Avp::addAvp()
206 //------------------------------------------------------------------------------
207 Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() {
208 Avp * result = engine->allocateAvp();
210 addChild(avps, insertionPositionForChilds, result);
215 //------------------------------------------------------------------------------
216 //------------------------------------------------------------- Avp::removeAvp()
217 //------------------------------------------------------------------------------
218 bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() {
219 bool removed = false;
220 bool do_remove = true;
221 int position = ocurrence;
223 if(position < 0) { /* reversed access */
224 position = countAvp(avps, id) + 1 + position;
226 // Special cases -> 0 and negative results:
227 // (1) User wants to remove the last, but no avp is found: position = 0 + 1 - 1 = 0 (would removes all but, no avp will be found: return now)
228 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (would removes all !!!: return to avoid unexpected behaviour)
229 // (2) User wants to remove some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
230 if(position <= 0) do_remove = false;
234 int n = position ? position : 1 /* will search always the first and remove, the first and remove, the first and remove ... */;
237 while((it = avp_find(avps, id, n)) != avps.end()) {
238 engine->releaseAvp((*it).second);
247 // Cache system reset (remove will invalidate cached findings):
250 const stack::Avp *stackAvp = getStackAvp(id, engine);
251 std::string msg = "Removed Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
252 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
253 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
257 const stack::Avp *stackAvp = getStackAvp(id, engine);
258 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
259 msg += anna::functions::asString(" with provided ocurrence (%d), in order to be removed", ocurrence);
260 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
268 //------------------------------------------------------------------------------
269 //-------------------------------------------------------------- Avp::countAvp()
270 //------------------------------------------------------------------------------
271 int Avp::countAvp(const avp_container &avps, AvpId id) throw() {
273 const_avp_iterator it;
275 while((it = avp_find(avps, id, result + 1)) != avps.end()) result++;
281 //------------------------------------------------------------------------------
282 //-------------------------------------------------------------- Avp::firstAvp()
283 //------------------------------------------------------------------------------
284 const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() {
285 const_avp_iterator it = avp_find(avps, id, 1);
294 //------------------------------------------------------------------------------
295 //----------------------------------------------------------- Avp::countChilds()
296 //------------------------------------------------------------------------------
297 int Avp::countChilds(const avp_container &avps) throw() {
302 //------------------------------------------------------------------------------
303 //---------------------------------------------------------------- Avp::getAvp()
304 //------------------------------------------------------------------------------
305 const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
307 LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION));
311 bool do_search = true;
313 int position = ocurrence;
315 if(position < 0) { /* reversed access */
316 position = countAvp(avps, id) + 1 + position;
318 // Special cases -> 0 and negative results:
319 // (1) User wants to get the last, but no avp is found: position = 0 + 1 - 1 = 0 (can't find 0-position ...)
320 // (2) User wants to get some intermediate avp, i.e. '-5', but only 4 avps are found: 4 + 1 - 5 = 0 (can't find 0-position ...)
321 // (2) User wants to get some intermediate avp, i.e. '-5', but only 3 avps are found: 3 + 1 - 5 = -1 (can't find negative positions ...)
322 if(position <= 0) do_search = false;
325 const Avp * result = NULL;
328 // Search at cache finds:
329 find_key key(id, position);
330 find_iterator fit = finds.find(key);
331 cached = (fit != finds.end());
334 result = (*fit).second;
336 const_avp_iterator it = avp_find(avps, id, position);
338 if(it != avps.end()) {
339 result = (*it).second;
340 finds[key] = const_cast<Avp*>(result); // store in cache
348 const stack::Avp *stackAvp = getStackAvp(id, engine);
349 std::string msg = "Found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
350 msg += anna::functions::asString(" with provided ocurrence (%d) which was ", ocurrence);
351 msg += cached ? "already cached:\n" : "the first search, now cached:\n";
352 msg += result->asXMLString();
353 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
360 case anna::Exception::Mode::Throw: {
361 const stack::Avp *stackAvp = getStackAvp(id, engine);
362 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
363 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
364 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
367 case anna::Exception::Mode::Trace: {
369 const stack::Avp *stackAvp = getStackAvp(id, engine);
370 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
371 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
372 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
376 case anna::Exception::Mode::Ignore: {
378 const stack::Avp *stackAvp = getStackAvp(id, engine);
379 std::string msg = "Can't found Avp "; msg += stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id));
380 msg += anna::functions::asString(" with provided ocurrence (%d)", ocurrence);
381 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
391 //------------------------------------------------------------------------------
392 //--------------------------------------------------------------- Avp::_getAvp()
393 //------------------------------------------------------------------------------
394 const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
395 // Dictionary stack avp and format (this):
396 const stack::Avp *stackAvp = getStackAvp();
397 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
399 if(!stackFormat || !stackFormat->isGrouped())
400 throw anna::RuntimeException("This method only applies over grouped avps.", ANNA_FILE_LOCATION);
402 return getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
406 //------------------------------------------------------------------------------
407 //---------------------------------------------------------- Avp::assertFormat()
408 //------------------------------------------------------------------------------
409 void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) {
410 // Dictionary stack avp and format:
411 const stack::Avp *stackAvp = getStackAvp();
412 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
413 std::string format = stackFormat ? stackFormat->getName() : "Unknown";
416 std::string msg = "The Avp ";
417 msg += anna::diameter::functions::avpIdAsPairString(a_id);
418 msg += " with format '";
420 msg += "' is not compatible with the API method used (";
423 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
428 //------------------------------------------------------------------------------
429 //--------------------------------------------------------------- Avp::flagsOK()
430 //------------------------------------------------------------------------------
431 bool Avp::flagsOK() const throw() {
432 // Dictionary stack avp:
433 const stack::Avp *stackAvp = getStackAvp();
436 anna::Logger::error("Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok", ANNA_FILE_LOCATION);
441 bool Vnone = (stackAvp->getVbit() == stack::Avp::FlagRule::None);
443 bool Vmust = (stackAvp->getVbit() == stack::Avp::FlagRule::must);
445 bool Vmustnot = (stackAvp->getVbit() == stack::Avp::FlagRule::mustnot);
447 bool Mnone = (stackAvp->getMbit() == stack::Avp::FlagRule::None);
449 bool Mmust = (stackAvp->getMbit() == stack::Avp::FlagRule::must);
451 bool Mmustnot = (stackAvp->getMbit() == stack::Avp::FlagRule::mustnot);
453 bool Pnone = (stackAvp->getPbit() == stack::Avp::FlagRule::None);
455 bool Pmust = (stackAvp->getPbit() == stack::Avp::FlagRule::must);
457 bool Pmustnot = (stackAvp->getPbit() == stack::Avp::FlagRule::mustnot);
460 if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) {
461 anna::Logger::error("Vendor Bit (V) incoherence found", ANNA_FILE_LOCATION);
465 // Exit on permissive mode:
466 if(getEngine()->ignoreFlagsOnValidation()) return true; // Ignore checking for AVP 'M' & 'P' bits
469 if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) {
470 anna::Logger::error("Mandatory Bit (M) incoherence found", ANNA_FILE_LOCATION);
475 if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) {
476 anna::Logger::error("Encryption Bit (P) incoherence found", ANNA_FILE_LOCATION);
481 if((a_flags & 0x1f) != 0x00) {
482 anna::Logger::error("Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null", ANNA_FILE_LOCATION);
490 //------------------------------------------------------------------------------
491 //----------------------------------------------------------------- Avp::setId()
492 //------------------------------------------------------------------------------
493 void Avp::setId(AvpId id) throw(anna::RuntimeException) {
494 // Generic AVP assignment has no sense
495 if(id == helpers::AVPID__AVP) return;
497 // Clear class content:
501 // Dictionary stack avp and format:
502 const stack::Avp *stackAvp = getStackAvp(); // based on dictionary and a_id
503 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
505 // Dictionary flags for known types:
507 if(stackAvp->getVbit() == stack::Avp::FlagRule::must) a_flags |= VBitMask;
509 if(stackAvp->getMbit() == stack::Avp::FlagRule::must) a_flags |= MBitMask;
511 if(stackAvp->getPbit() == stack::Avp::FlagRule::must) a_flags |= PBitMask;
513 if(a_id.second != 0) a_flags |= VBitMask; else a_flags &= (~VBitMask);
516 if(!stackFormat) { // Unknown Avp
518 std::string msg = "Unknown format for AVP identifier ";
519 msg += anna::diameter::functions::avpIdAsPairString(id);
520 msg += ". Raw data without specific format will be managed";
521 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
523 a_Unknown = new Unknown();
527 // Avp class formats (Avp child classes should implement this source code block for application-specific formats):
528 if(stackFormat->isOctetString()) a_OctetString = new OctetString();
529 else if(stackFormat->isInteger32()) a_Integer32 = new Integer32();
530 else if(stackFormat->isInteger64()) a_Integer64 = new Integer64();
531 else if(stackFormat->isUnsigned32()) a_Unsigned32 = new Unsigned32();
532 else if(stackFormat->isUnsigned64()) a_Unsigned64 = new Unsigned64();
533 else if(stackFormat->isFloat32()) a_Float32 = new Float32();
534 else if(stackFormat->isFloat64()) a_Float64 = new Float64();
535 //else if (stackFormat->isGrouped())
536 else if(stackFormat->isAddress()) a_Address = new Address();
537 else if(stackFormat->isTime()) a_Time = new Time();
538 else if(stackFormat->isUTF8String()) a_UTF8String = new UTF8String();
539 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity = new DiameterIdentity();
540 else if(stackFormat->isDiameterURI()) a_DiameterURI = new DiameterURI();
541 else if(stackFormat->isEnumerated()) a_Enumerated = new Enumerated();
542 else if(stackFormat->isIPFilterRule()) a_IPFilterRule = new IPFilterRule();
543 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule = new QoSFilterRule();
545 /////////////////////
546 // Format specific //
547 /////////////////////
548 allocationByFormat(stackFormat);
552 //------------------------------------------------------------------------------
553 //----------------------------------------------------------------- Avp::setId()
554 //------------------------------------------------------------------------------
555 void Avp::setId(const char *name) throw(anna::RuntimeException) {
556 setId(getEngine()->avpIdForName(name));
560 //------------------------------------------------------------------------------
561 //---------------------------------------------------------------- Avp::addAvp()
562 //------------------------------------------------------------------------------
563 Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) {
564 return addAvp(getEngine()->avpIdForName(name));
568 //------------------------------------------------------------------------------
569 //------------------------------------------------------------- Avp::removeAvp()
570 //------------------------------------------------------------------------------
571 bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) {
572 return removeAvp(getEngine()->avpIdForName(name), ocurrence);
576 //------------------------------------------------------------------------------
577 //--------------------------------------------------------------- Avp::_getAvp()
578 //------------------------------------------------------------------------------
579 const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) {
580 return getAvp(getEngine()->avpIdForName(name), ocurrence, emode);
584 //------------------------------------------------------------------------------
585 //-------------------------------------------------------------- Avp::countAvp()
586 //------------------------------------------------------------------------------
587 int Avp::countAvp(const char *name) const throw(anna::RuntimeException) {
588 return countAvp(getEngine()->avpIdForName(name));
591 //------------------------------------------------------------------------------
592 //------------------------------------------------------------- Avp::getLength()
593 //------------------------------------------------------------------------------
594 U24 Avp::getLength() const throw() {
597 const stack::Avp *stackAvp = getStackAvp();
598 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
600 result = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
603 result += a_Unknown->getSize();
607 if(stackFormat->isOctetString()) result += a_OctetString->getSize();
608 else if(stackFormat->isInteger32()) result += a_Integer32->getSize();
609 else if(stackFormat->isInteger64()) result += a_Integer64->getSize();
610 else if(stackFormat->isUnsigned32()) result += a_Unsigned32->getSize();
611 else if(stackFormat->isUnsigned64()) result += a_Unsigned64->getSize();
612 else if(stackFormat->isFloat32()) result += a_Float32->getSize();
613 else if(stackFormat->isFloat64()) result += a_Float64->getSize();
614 else if(stackFormat->isGrouped()) for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) result += 4 * REQUIRED_WORDS(avp(it)->getLength());
615 else if(stackFormat->isAddress()) result += a_Address->getSize();
616 else if(stackFormat->isTime()) result += a_Time->getSize();
617 else if(stackFormat->isUTF8String()) result += a_UTF8String->getSize();
618 else if(stackFormat->isDiameterIdentity()) result += a_DiameterIdentity->getSize();
619 else if(stackFormat->isDiameterURI()) result += a_DiameterURI->getSize();
620 else if(stackFormat->isEnumerated()) result += a_Enumerated->getSize();
621 else if(stackFormat->isIPFilterRule()) result += a_IPFilterRule->getSize();
622 else if(stackFormat->isQoSFilterRule()) result += a_QoSFilterRule->getSize();
624 /////////////////////
625 // Format specific //
626 /////////////////////
627 result += getLengthByFormat(stackFormat);
632 //------------------------------------------------------------------------------
633 //-------------------------------------------- Avp::unknownAvpWithMandatoryBit()
634 //------------------------------------------------------------------------------
635 void Avp::unknownAvpWithMandatoryBit() const throw(anna::RuntimeException) {
636 OamModule &oamModule = OamModule::instantiate();
637 const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id));
638 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid);
639 oamModule.count(OamModule::Counter::AvpDecode__UnknownAvpWithMandatoryBit);
641 std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid);
642 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
646 //------------------------------------------------------------------------------
647 //-------------------------------------------------------- Avp::decodeDataPart()
648 //------------------------------------------------------------------------------
649 void Avp::decodeDataPart(const char * buffer, int size, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
651 OamModule &oamModule = OamModule::instantiate();
652 // Dictionary stack avp and format:
653 const stack::Avp *stackAvp = getStackAvp();
654 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
657 a_Unknown->decode(buffer, size);
661 if(stackFormat->isOctetString()) a_OctetString->decode(buffer, size);
662 else if(stackFormat->isInteger32()) a_Integer32->decode(buffer, size);
663 else if(stackFormat->isInteger64()) a_Integer64->decode(buffer, size);
664 else if(stackFormat->isUnsigned32()) a_Unsigned32->decode(buffer, size);
665 else if(stackFormat->isUnsigned64()) a_Unsigned64->decode(buffer, size);
666 else if(stackFormat->isFloat32()) a_Float32->decode(buffer, size);
667 else if(stackFormat->isFloat64()) a_Float64->decode(buffer, size);
668 else if(stackFormat->isGrouped()) {
670 LOGDEBUG(anna::Logger::debug("Grouped Avp has empty data part", ANNA_FILE_LOCATION));
674 if((size % 4) != 0) {
675 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
676 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
679 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
680 answer->setFailedAvp(parent, a_id);
683 throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION);
691 parent_t me = parent;
694 while(avpPos < size) {
696 avp = getEngine()->allocateAvp();
697 db.assign(buffer + avpPos, size - avpPos /* is valid to pass total size (indeed i don't know the real avp size) because it will be limited and this has deep copy disabled (no memory is reserved) */);
698 avp -> decode(db, me, answer);
699 } catch(anna::RuntimeException &ex) {
700 getEngine()->releaseAvp(avp);
705 avpPos += 4 * REQUIRED_WORDS(avp->getLength());
707 } else if(stackFormat->isAddress()) a_Address->decode(buffer, size);
708 else if(stackFormat->isTime()) a_Time->decode(buffer, size);
709 else if(stackFormat->isUTF8String()) a_UTF8String->decode(buffer, size);
710 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->decode(buffer, size);
711 else if(stackFormat->isDiameterURI()) a_DiameterURI->decode(buffer, size);
712 else if(stackFormat->isEnumerated()) a_Enumerated->decode(buffer, size);
713 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->decode(buffer, size);
714 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->decode(buffer, size);
716 /////////////////////
717 // Format specific //
718 /////////////////////
719 decodeDataPartByFormat(buffer, size, stackFormat);
722 //------------------------------------------------------------------------------
723 //---------------------------------------------------------------- Avp::decode()
724 //------------------------------------------------------------------------------
725 void Avp::decode(const anna::DataBlock &db, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
727 OamModule &oamModule = OamModule::instantiate();
729 if(db.getSize() < HeaderLengthVinactive) {
730 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
731 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
732 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
733 throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION);
736 const char * buffer = db.getData();
739 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
740 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743 // | AVP Flags | AVP Length |
744 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
745 // | Vendor-ID (opt) |
746 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749 // Code flags and vendor-id
750 U32 code = DECODE4BYTES_INDX_VALUETYPE(buffer, 0, U32);
752 a_flags = (S8)buffer[4];
754 U32 vendorID = helpers::VENDORID__base;
757 if(db.getSize() < HeaderLengthVactive) {
758 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
759 oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength);
760 // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code
761 throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION);
764 vendorID = DECODE4BYTES_INDX_VALUETYPE(buffer, 8, U32);
766 if(vendorID == helpers::VENDORID__base) {
767 // A vendor ID value of zero (0) corresponds to the IETF adopted AVP
768 // values, as managed by the IANA. Since the absence of the vendor
769 // ID field implies that the AVP in question is not vendor specific,
771 // implementations MUST NOT use the zero (0) vendor ID.
772 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
773 oamModule.count(OamModule::Counter::AvpDecode__IncoherenceBetweenActivatedVBitAndZeroedVendorIDValueReceived);
774 throw anna::RuntimeException(anna::functions::asString("Incoherence between activated V bit and zeroed vendor-id value received (avp code = %u)", code), ANNA_FILE_LOCATION);
779 setId(AvpId(code, vendorID));
780 // Flags could have been updated regarding dictionary, but during decoding we must respect buffer received:
781 a_flags = (S8)buffer[4];
783 // Here i know id and flags:
784 // The 'M' Bit, known as the Mandatory bit, indicates whether support of the AVP is required. If an AVP with the 'M' bit set is received by
785 // a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected.
786 // Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs.
787 if(!getStackAvp() && mandatoryBit()) {
790 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED);
791 answer->setFailedAvp(parent, a_id);
794 unknownAvpWithMandatoryBit();
798 U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24);
799 // Data start position:
800 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
802 int dataBytes = length - startDataPos;
805 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength);
806 oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength);
809 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
810 answer->setFailedAvp(parent, a_id);
813 throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION);
817 decodeDataPart(buffer + startDataPos, dataBytes, parent, answer);
818 } catch(anna::RuntimeException &ex) {
819 oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence);
820 oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence);
823 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
824 answer->setFailedAvp(parent, a_id);
827 throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION);
832 //------------------------------------------------------------------------------
833 //----------------------------------------------------------- Avp::getStackAvp()
834 //------------------------------------------------------------------------------
835 const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() {
836 const stack::Dictionary * dictionary = engine->getDictionary();
837 return (dictionary ? (dictionary->getAvp(id)) : NULL);
841 //------------------------------------------------------------------------------
842 //------------------------------------------------------------------- Avp::fix()
843 //------------------------------------------------------------------------------
844 void Avp::fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw() {
846 if(avps.size() == 0) return; // empty content, nothing to fix
848 if(ruleBegin == ruleEnd) return; // no reference. Cannot fix
850 // Copy reference container and clear internal map in order to build a fixed version:
851 avp_container unfixedAvps;
853 for(const_avp_iterator it = avps.begin(); it != avps.end(); it++)
854 unfixedAvps[(*it).first] = (*it).second;
857 // Cache system reset (fix probably will invalidate cached findings):
859 insertionPositionForChilds = 0;
863 for(anna::diameter::stack::const_avprule_iterator rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
864 while((avp_it = Avp::avp_find(unfixedAvps, (*rule_it).second.getId(), 1)) != unfixedAvps.end()) {
865 avp = (*avp_it).second;
866 addChild(avps, insertionPositionForChilds, avp);
867 unfixedAvps.erase(avp_it); // processed
871 // Add remaining avps:
872 for(avp_it = unfixedAvps.begin(); avp_it != unfixedAvps.end(); avp_it++) {
873 avp = (*avp_it).second;
875 if(avp) addChild(avps, insertionPositionForChilds, avp);
879 for(avp_iterator it = avps.begin(); it != avps.end(); it++) {
882 if(avp->hasChildren()) avp->fix();
887 //------------------------------------------------------------------------------
888 //------------------------------------------------------------------- Avp::fix()
889 //------------------------------------------------------------------------------
890 void Avp::fix() throw() {
891 // Dictionary stack avp:
892 const stack::Avp *stackAvp = getStackAvp();
893 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
896 //LOGDEBUG(anna::Logger::debug("No dictionary avp reference found. Cannot fix.", ANNA_FILE_LOCATION));
900 if(!stackFormat || !stackFormat->isGrouped()) {
901 //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing to fix.", ANNA_FILE_LOCATION));
905 fix(a_avps, (find_container&)a_finds, a_insertionPositionForChilds, stackAvp->avprule_begin(), stackAvp->avprule_end());
909 //------------------------------------------------------------------------------
910 //------------------------------------------------------------ Avp::validLevel()
911 //------------------------------------------------------------------------------
912 bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const parent_t & parent, Message *answer) throw(anna::RuntimeException) {
915 OamModule &oamModule = OamModule::instantiate();
921 const_avp_iterator avp_it = avps.begin();
922 anna::diameter::stack::const_avprule_iterator rule_it;
925 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
928 if((*rule_it).second.isFixed()) {
929 if(avps.size() == 0) break; // cardinality checking will show this anomaly
931 if(avp_it != avps.end()) {
932 id = Avp::avp(avp_it)->getId();
934 if(id != (*rule_it).second.getId()) {
936 // Missing fixed rule: %s
937 } else if(Avp::avp_find(avps, id, 2) != avps.end()) {
939 // More than one fixed ocurrency for rule %s (*)
943 // (*) for (int k = 0; k < (*rule_it).second.getQualMax(); k++) avp_it++
949 // OAM & Depth management
950 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
951 oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule);
954 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
955 answer->setFailedAvp(parent, (*rule_it).second.getId());
958 engine->validationAnomaly(anna::functions::asString("Missing fixed rule %s inside %s", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
960 } else break; // finish fixed
964 // Cardinality // Mandatory control is implicit here
966 anna::diameter::stack::const_avprule_iterator generic_rule_it = ruleEnd;
967 int min, max, amount;
969 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
970 if((*rule_it).second.isAny()) { generic_rule_it = rule_it; continue; } // generic Avp will be managed after
972 id = (*rule_it).second.getId();
973 min = (*rule_it).second.getQualMin();
974 max = (*rule_it).second.getQualMax(); // -1 means infinite
975 amount = Avp::countAvp(avps, id);
977 if((amount < min) || ((max != -1) && (amount > max))) {
978 // Failed rule %s for cardinality (found %d items)
980 // OAM & Depth management
981 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedRule__s__ForCardinality_Found__d__ItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
982 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality);
985 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityLessThanNeeded);
988 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
989 answer->setFailedAvp(parent, id);
992 oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded);
995 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES);
996 answer->setFailedAvp(parent, id);
1000 engine->validationAnomaly(anna::functions::asString("Failed rule %s for cardinality (found %d items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1004 bool haveGeneric = (generic_rule_it != ruleEnd);
1009 std::map < AvpId, int /* dummy */ > disregarded; // 'Disregardeds' are Avps not in rules list
1010 std::map < AvpId, int /* dummy */ >::const_iterator disregarded_it;
1012 for(avp_it = avps.begin(); avp_it != avps.end(); avp_it++) {
1013 id = Avp::avp(avp_it)->getId();
1014 // Find rule for the child:
1015 foundInRules = false;
1017 for(rule_it = ruleBegin; rule_it != ruleEnd; rule_it++) {
1018 if((*rule_it).second.getId() == id) {
1019 foundInRules = true;
1025 disregarded[id] = 0;
1029 // Generic AVP cardinality checkings
1030 int disregardeds = disregarded.size();
1033 min = (*generic_rule_it).second.getQualMin();
1034 max = (*generic_rule_it).second.getQualMax(); // -1 means infinite
1035 amount = disregardeds;
1037 if((amount < min) || ((max != -1) && (amount > max))) {
1038 // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)
1040 // OAM & Depth management
1041 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FailedGenericAvpRule__s__ForCardinality_Found__d__DisregardedItemsInside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()));
1042 oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem);
1045 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1046 answer->setFailedAvp(parent, id); // NO SENSE... what to put ?
1049 engine->validationAnomaly(anna::functions::asString("Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s)", STRING_WITH_QUOTATION_MARKS__C_STR((*generic_rule_it).second.asString(false /*ommit dots & pair*/)), amount, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString())));
1051 } else if(disregardeds) { // When Generic AVP missing, no disregarded Avps are allowed
1052 // Found %d disregarded items inside %s and Generic AVP was not specified
1054 // Build disregarded list as string (unknown as avp id pair):
1055 std::string s_disregardeds = "";
1056 const stack::Avp *stackAvp;
1058 for(disregarded_it = disregarded.begin(); disregarded_it != disregarded.end(); disregarded_it++) {
1059 id = (*disregarded_it).first;
1060 stackAvp = getStackAvp(id, engine);
1061 s_disregardeds += (stackAvp ? (stackAvp->getName()) : (anna::diameter::functions::avpIdAsPairString(id)));
1062 s_disregardeds += ", ";
1064 // We wouldn't know where are these disregarded, but...
1066 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
1067 answer->setFailedAvp(parent, id);
1071 s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', '
1072 // OAM & Depth management
1073 oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds));
1074 oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified);
1075 engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parent.asString()), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)));
1082 //------------------------------------------------------------------------------
1083 //----------------------------------------------------------------- Avp::valid()
1084 //------------------------------------------------------------------------------
1085 bool Avp::valid(const parent_t & parent, Message *answer) const throw(anna::RuntimeException) {
1087 OamModule &oamModule = OamModule::instantiate();
1088 // Dictionary stack avp:
1089 const stack::Avp *stackAvp = getStackAvp();
1090 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1093 // No dictionary avp reference found. Cannot validate
1094 return true; // perhaps a unknown Avp
1098 parent_t me = parent;
1099 me.addAvp(a_id, stackAvp->getName().c_str());
1102 // No format avp reference found. Cannot validate
1103 return true; // perhaps a unknown Avp
1106 //////////////////////////////
1107 // Flags coherence checking //
1108 //////////////////////////////
1109 bool result = flagsOK();
1112 // OAM & Depth management
1113 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()));
1114 oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules);
1117 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS);
1118 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); // RFC 6733 says nothing about Failed-AVP in this case...
1121 getEngine()->validationAnomaly(anna::functions::asString("The AVP %s flags (%d) does not fulfill the defined flag rules: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())));
1124 //////////////////////
1125 // Enumerated range //
1126 //////////////////////
1127 if(stackFormat->isEnumerated()) {
1128 if(!stackAvp->allowEnum(a_Enumerated->getValue())) {
1130 // OAM & Depth management
1131 oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums());
1132 oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction);
1135 answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE);
1136 answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str());
1139 getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums()));
1143 ////////////////////
1144 // Level checking //
1145 ////////////////////
1146 result = Avp::validLevel(a_avps, stackAvp->avprule_begin(), stackAvp->avprule_end(), getEngine(), me, answer) && result;
1148 ////////////////////////
1149 // Childrens checking //
1150 ////////////////////////
1151 if(a_id == helpers::base::AVPID__Failed_AVP) return result; // DON'T VALIDATE CONTENT FOR Failed-AVP, because it won't be valid...
1153 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++)
1154 result = ((*it).second->valid(me, answer)) && result;
1160 //------------------------------------------------------------------------------
1161 //------------------------------------------------------------------ Avp::code()
1162 //------------------------------------------------------------------------------
1163 void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) {
1165 buffer[0] = (S8)(a_id.first >> 24);
1166 buffer[1] = (S8)(a_id.first >> 16);
1167 buffer[2] = (S8)(a_id.first >> 8);
1168 buffer[3] = (S8) a_id.first;
1171 buffer[4] = (S8) a_flags;
1172 buffer[5] = (S8)(size >> 16);
1173 buffer[6] = (S8)(size >> 8);
1174 buffer[7] = (S8) size;
1178 buffer[8] = (S8)(a_id.second >> 24);
1179 buffer[9] = (S8)(a_id.second >> 16);
1180 buffer[10] = (S8)(a_id.second >> 8);
1181 buffer[11] = (S8) a_id.second;
1184 // Data start position:
1185 int startDataPos = vendorBit() ? HeaderLengthVactive : HeaderLengthVinactive;
1187 S8 * dataPart = buffer + startDataPos;
1188 int dataBytes; // not used but could be useful for checking (size - startDataPos)
1190 if(startDataPos == size) {
1191 LOGDEBUG(anna::Logger::debug("There is no data part to encode", ANNA_FILE_LOCATION));
1196 const stack::Avp *stackAvp = getStackAvp();
1197 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1200 a_Unknown->code(dataPart, dataBytes);
1204 if(stackFormat->isOctetString()) a_OctetString->code(dataPart, dataBytes);
1205 else if(stackFormat->isInteger32()) a_Integer32->code(dataPart, dataBytes);
1206 else if(stackFormat->isInteger64()) a_Integer64->code(dataPart, dataBytes);
1207 else if(stackFormat->isUnsigned32()) a_Unsigned32->code(dataPart, dataBytes);
1208 else if(stackFormat->isUnsigned64()) a_Unsigned64->code(dataPart, dataBytes);
1209 else if(stackFormat->isFloat32()) a_Float32->code(dataPart, dataBytes);
1210 else if(stackFormat->isFloat64()) a_Float64->code(dataPart, dataBytes);
1211 else if(stackFormat->isGrouped()) {
1212 // // Each avp encoding will remain padding octets depending on format. In order to
1213 // // code grouped content (each avp will be multiple of 4) we clean the entire buffer
1214 // // to ensure padding (easier than custom-made for each format):
1215 // memset(dataPart, 0, size - startDataPos);
1216 char *dataPartGrouped = dataPart;
1217 int dataBytesGrouped;
1219 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
1220 avp(it)->code(dataPartGrouped, dataBytesGrouped);
1221 dataPartGrouped = dataPartGrouped + 4 * REQUIRED_WORDS(dataBytesGrouped);
1223 } else if(stackFormat->isAddress()) a_Address->code(dataPart, dataBytes);
1224 else if(stackFormat->isTime()) a_Time->code(dataPart, dataBytes);
1225 else if(stackFormat->isUTF8String()) a_UTF8String->code(dataPart, dataBytes);
1226 else if(stackFormat->isDiameterIdentity()) a_DiameterIdentity->code(dataPart, dataBytes);
1227 else if(stackFormat->isDiameterURI()) a_DiameterURI->code(dataPart, dataBytes);
1228 else if(stackFormat->isEnumerated()) a_Enumerated->code(dataPart, dataBytes);
1229 else if(stackFormat->isIPFilterRule()) a_IPFilterRule->code(dataPart, dataBytes);
1230 else if(stackFormat->isQoSFilterRule()) a_QoSFilterRule->code(dataPart, dataBytes);
1232 /////////////////////
1233 // Format specific //
1234 /////////////////////
1235 codeByFormat(dataPart, stackFormat);
1239 //------------------------------------------------------------------------------
1240 //------------------------------------------------------------ Avp::getXMLdata()
1241 //------------------------------------------------------------------------------
1242 std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() {
1243 std::string result = "";
1247 // if (!stackFormat) {
1249 // return a_Unknown->asHexString();
1251 // } catch (anna::RuntimeException &ex) {
1257 return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad
1260 // Special case for Address: could launch exception if not printable
1262 if(stackFormat->isAddress()) return a_Address->asPrintableString();
1263 } catch(anna::RuntimeException&) {
1266 return a_Address->asHexString();
1270 if(stackFormat->isOctetString()) {
1272 return a_OctetString->asHexString();
1276 if(stackFormat->isInteger32()) return a_Integer32->asPrintableString();
1278 if(stackFormat->isInteger64()) return a_Integer64->asPrintableString();
1280 if(stackFormat->isUnsigned32()) return a_Unsigned32->asPrintableString();
1282 if(stackFormat->isUnsigned64()) return a_Unsigned64->asPrintableString();
1284 if(stackFormat->isFloat32()) return a_Float32->asPrintableString();
1286 if(stackFormat->isFloat64()) return a_Float64->asPrintableString();
1288 //if (stackFormat->isAddress()) return a_Address->asPrintableString();
1290 if(stackFormat->isTime()) return a_Time->asPrintableString();
1292 if(stackFormat->isUTF8String()) return a_UTF8String->asPrintableString();
1294 if(stackFormat->isDiameterIdentity()) return a_DiameterIdentity->asPrintableString();
1296 if(stackFormat->isDiameterURI()) return a_DiameterURI->asPrintableString();
1298 if(stackFormat->isEnumerated()) return a_Enumerated->asPrintableString();
1300 if(stackFormat->isIPFilterRule()) return a_IPFilterRule->asPrintableString();
1302 if(stackFormat->isQoSFilterRule()) return a_QoSFilterRule->asPrintableString();
1304 /////////////////////
1305 // Format specific //
1306 /////////////////////
1307 return getXMLdataByFormat(isHex, stackFormat);
1308 } catch(anna::RuntimeException &ex) {
1316 //------------------------------------------------------------------------------
1317 //--------------------------------------------------------------- Avp::fromXML()
1318 //------------------------------------------------------------------------------
1319 void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) {
1320 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1321 const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData;
1322 name = avpNode->getAttribute("name", false /* no exception */);
1323 code = avpNode->getAttribute("code", false /* no exception */);
1324 vendorCode = avpNode->getAttribute("vendor-code", false /* no exception */);
1325 flags = avpNode->getAttribute("flags", false /* no exception */);
1326 data = avpNode->getAttribute("data", false /* no exception */);
1327 hexData = avpNode->getAttribute("hex-data", false /* no exception */);
1329 const stack::Dictionary * dictionary = getEngine()->getDictionary();
1330 const stack::Avp *stackAvp = NULL;
1331 const stack::Format *stackFormat = NULL;
1336 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1337 msg += "'>: no dictionary available. Load one or use <'code' + 'flags' + 'vendorCode'> instead of <'name'>";
1338 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1341 stackAvp = dictionary->getAvp(name->getValue());
1344 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1345 msg += "'>: no avp found for this identifier at available dictionary";
1346 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1349 stackFormat = stackAvp->getFormat();
1352 // Check attributes exclusiveness
1353 if(name) { // compact mode
1354 if(code || flags || vendorCode) {
1355 std::string msg = "Error processing avp <name '"; msg += name->getValue();
1356 msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided";
1357 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1360 setId(stackAvp->getId());
1362 if(!code || !flags || !vendorCode) {
1363 std::string s_code = code ? code->getValue() : "?";
1364 std::string s_flags = flags ? flags->getValue() : "?";
1365 std::string s_vendorCode = vendorCode ? vendorCode->getValue() : "?";
1366 std::string msg = "Error processing avp <code '"; msg += s_code;
1367 msg += "' + flags '"; msg += s_flags;
1368 msg += "' + vendorCode '"; msg += s_vendorCode;
1369 msg += "'>: all must be provided if <'name'> don't";
1370 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1374 int i_aux = code->getIntegerValue();
1377 std::string msg = "Error processing avp <code '"; msg += code->getValue();
1378 msg += "': negative values are not allowed";
1379 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1384 i_aux = flags->getIntegerValue();
1386 if(i_aux < 0 || i_aux > 256) {
1387 std::string msg = "Error processing avp <flags '"; msg += flags->getValue();
1388 msg += "': out of range [0,256]";
1389 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1393 int flagsBCK = a_flags;
1394 // VendorCode checks
1395 i_aux = vendorCode->getIntegerValue();
1398 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1399 msg += "': negative values are not allowed";
1400 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1403 U32 u_vendorCode = i_aux;
1404 bool vendorSpecific1 = (u_vendorCode != 0);
1405 bool vendorSpecific2 = (((a_flags) & VBitMask) != 0x00);
1407 if(vendorSpecific1 != vendorSpecific2) {
1408 std::string msg = "Error processing avp <vendorCode '"; msg += vendorCode->getValue();
1409 msg += "' and avp <flags '"; msg += flags->getValue();
1410 msg += "': incompatible vendor-specific properties";
1411 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1414 // Final assignments
1415 setId(AvpId(u_code, u_vendorCode));
1416 // Flags could have been updated regarding dictionary, but during parsing we must respect xml file:
1418 stackAvp = getStackAvp();
1419 stackFormat = stackAvp ? stackAvp->getFormat() : NULL;
1423 // Check if grouped not confirmed
1424 anna::xml::Node::const_child_iterator it;
1425 anna::xml::Node::const_child_iterator minii = avpNode->child_begin();
1426 anna::xml::Node::const_child_iterator maxii = avpNode->child_end();
1427 const bool hasChildren(minii != maxii);
1430 // We need to confirm is grouped
1432 throw anna::RuntimeException("An xml avp node with children nodes could not confirmed as Grouped", ANNA_FILE_LOCATION);
1434 if(!stackFormat->isGrouped())
1435 throw anna::RuntimeException("An xml avp node with children nodes is not grouped type", ANNA_FILE_LOCATION);
1438 throw anna::RuntimeException("An xml avp node with children nodes has 'data' or 'hex-data' field", ANNA_FILE_LOCATION);
1442 std::string s_avp = name ? (name->getValue()) : (anna::diameter::functions::avpIdAsPairString(a_id));
1444 if(data && hexData) {
1445 std::string msg = "Not allowed both 'data' and 'hex-data' definitions. Avp ";
1447 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1451 bool unknown = !stackFormat;
1452 bool octetString = stackFormat && (stackFormat->isOctetString());
1454 if(data && (unknown || octetString)) {
1455 std::string msg = "Not recommended 'data' field at ";
1456 msg += unknown ? "Unknown" : "OctetString";
1457 msg += "-format Avp "; msg += s_avp;
1458 msg += ". Use better 'hex-data' or omit content fields if empty";
1459 anna::Logger::warning(msg, ANNA_FILE_LOCATION);
1464 if(data) a_Unknown->fromPrintableString(data->getValue().c_str());
1465 else if(hexData) a_Unknown->fromHexString(hexData->getValue());
1470 if(stackFormat->isOctetString()) {
1471 if(data) a_OctetString->fromPrintableString(data->getValue().c_str());
1472 else if(hexData) a_OctetString->fromHexString(hexData->getValue());
1473 } else if(stackFormat->isInteger32()) {
1474 if(data) a_Integer32->fromPrintableString(data->getValue().c_str());
1475 else if(hexData) a_Integer32->fromHexString(hexData->getValue());
1476 } else if(stackFormat->isInteger64()) {
1477 if(data) a_Integer64->fromPrintableString(data->getValue().c_str());
1478 else if(hexData) a_Integer64->fromHexString(hexData->getValue());
1479 } else if(stackFormat->isUnsigned32()) {
1480 if(data) a_Unsigned32->fromPrintableString(data->getValue().c_str());
1481 else if(hexData) a_Unsigned32->fromHexString(hexData->getValue());
1482 } else if(stackFormat->isUnsigned64()) {
1483 if(data) a_Unsigned64->fromPrintableString(data->getValue().c_str());
1484 else if(hexData) a_Unsigned64->fromHexString(hexData->getValue());
1485 } else if(stackFormat->isFloat32()) {
1486 if(data) a_Float32->fromPrintableString(data->getValue().c_str());
1487 else if(hexData) a_Float32->fromHexString(hexData->getValue());
1488 } else if(stackFormat->isFloat64()) {
1489 if(data) a_Float64->fromPrintableString(data->getValue().c_str());
1490 else if(hexData) a_Float64->fromHexString(hexData->getValue());
1491 } else if(stackFormat->isGrouped()) {
1495 for(it = minii; it != maxii; it++) {
1496 std::string nodeName = (*it)->getName();
1498 if(nodeName != "avp") {
1499 std::string msg = "Unsupported grouped avp child node name '"; msg += nodeName;
1500 msg += "': use 'avp'";
1501 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1505 avp = getEngine()->allocateAvp();
1506 avp -> fromXML(*it);
1507 } catch(anna::RuntimeException &ex) {
1508 getEngine()->releaseAvp(avp);
1514 } else if(stackFormat->isAddress()) {
1515 if(data) a_Address->fromPrintableString(data->getValue().c_str());
1516 else if(hexData) a_Address->fromHexString(hexData->getValue());
1517 } else if(stackFormat->isTime()) {
1518 if(data) a_Time->fromPrintableString(data->getValue().c_str());
1519 else if(hexData) a_Time->fromHexString(hexData->getValue());
1520 } else if(stackFormat->isUTF8String()) {
1521 if(data) a_UTF8String->fromPrintableString(data->getValue().c_str());
1522 else if(hexData) a_UTF8String->fromHexString(hexData->getValue());
1523 } else if(stackFormat->isDiameterIdentity()) {
1524 if(data) a_DiameterIdentity->fromPrintableString(data->getValue().c_str());
1525 else if(hexData) a_DiameterIdentity->fromHexString(hexData->getValue());
1526 } else if(stackFormat->isDiameterURI()) {
1527 if(data) a_DiameterURI->fromPrintableString(data->getValue().c_str());
1528 else if(hexData) a_DiameterURI->fromHexString(hexData->getValue());
1529 } else if(stackFormat->isEnumerated()) {
1530 if(data) a_Enumerated->fromPrintableString(data->getValue().c_str());
1531 else if(hexData) a_Enumerated->fromHexString(hexData->getValue());
1532 } else if(stackFormat->isIPFilterRule()) {
1533 if(data) a_IPFilterRule->fromPrintableString(data->getValue().c_str());
1534 else if(hexData) a_IPFilterRule->fromHexString(hexData->getValue());
1535 } else if(stackFormat->isQoSFilterRule()) {
1536 if(data) a_QoSFilterRule->fromPrintableString(data->getValue().c_str());
1537 else if(hexData) a_QoSFilterRule->fromHexString(hexData->getValue());
1540 /////////////////////
1541 // Format specific //
1542 /////////////////////
1543 fromXMLByFormat(data, hexData, stackFormat);
1546 //------------------------------------------------------------------------------
1547 //----------------------------------------------------------------- Avp::asXML()
1548 //------------------------------------------------------------------------------
1549 anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() {
1550 // <!ATTLIST avp id CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
1551 anna::xml::Node* result = parent->createChild("avp");
1552 // Dictionary stack avp and format:
1553 const stack::Avp *stackAvp = getStackAvp();
1554 const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/;
1555 bool compactMode = (stackAvp && flagsOK());
1558 result->createAttribute("name", stackAvp->getName());
1560 result->createAttribute("code", a_id.first);
1561 result->createAttribute("vendor-code", a_id.second);
1562 result->createAttribute("flags", (int)a_flags);
1565 // Grouped special case:
1566 if(stackFormat && stackFormat->isGrouped()) {
1567 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) avp(it)->asXML(result);
1572 // Data part literals:
1574 std::string value = getXMLdata(isHex, stackFormat);
1577 result->createAttribute("hex-data", value);
1579 result->createAttribute("data", value);
1580 const char *alias = stackAvp->getAlias(value);
1582 if(alias) result->createAttribute("alias", alias); // additional information
1588 //------------------------------------------------------------------------------
1589 //----------------------------------------------------------- Avp::asXMLString()
1590 //------------------------------------------------------------------------------
1591 std::string Avp::asXMLString() const throw() {
1592 anna::xml::Node root("root");
1593 return anna::xml::Compiler().apply(asXML(&root));