X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdiameter%2Fcodec%2FAvp.cpp;h=14d5aa701e00f019470308cbc431f899a82bcf98;hb=5a6cba5fde2b2f538a7515f8293cc0a8d9589dfa;hp=19a07806cf3e0ca6d1c7d3d8dce7ed19433c9e72;hpb=5256cb543a9d35b610df19bd227cde977186aef0;p=anna.git diff --git a/source/diameter/codec/Avp.cpp b/source/diameter/codec/Avp.cpp index 19a0780..14d5aa7 100644 --- a/source/diameter/codec/Avp.cpp +++ b/source/diameter/codec/Avp.cpp @@ -1,37 +1,9 @@ -// ANNA - Anna is Not Nothingness Anymore -// -// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo -// -// http://redmine.teslayout.com/projects/anna-suite -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: eduardo.ramos.testillano@gmail.com -// cisco.tierra@gmail.com +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // // Local @@ -50,6 +22,7 @@ #include #include #include +#include #include #include @@ -82,20 +55,18 @@ const U8 Avp::PBitMask(0x20); //------------------------------------------------------------------------------ //------------------------------------------------------------------- Avp::Avp() //------------------------------------------------------------------------------ -Avp::Avp() { +Avp::Avp(Engine *engine) : a_engine(engine) { initialize(); } - //------------------------------------------------------------------------------ //------------------------------------------------------------------- Avp::Avp() //------------------------------------------------------------------------------ -Avp::Avp(AvpId id) { +Avp::Avp(AvpId id, Engine *engine) : a_engine(engine) { initialize(); setId(id); } - //------------------------------------------------------------------------------ //------------------------------------------------------------------ Avp::~Avp() //------------------------------------------------------------------------------ @@ -103,20 +74,33 @@ Avp::~Avp() { clear(); } +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::setEngine() +//------------------------------------------------------------------------------ +void Avp::setEngine(Engine *engine) { + if (a_engine && engine != a_engine) { + LOGWARNING(anna::Logger::warning("Ignored: it is not a good practice to change the codec engine once assigned. Clear the avp first to set the engine again.", ANNA_FILE_LOCATION)); + return; + } + + a_engine = engine; +} //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::getEngine() //------------------------------------------------------------------------------ -Engine * Avp::getEngine() const throw(anna::RuntimeException) { - return a_engine ? a_engine : (a_engine = anna::functions::component (ANNA_FILE_LOCATION)); +Engine * Avp::getEngine() const noexcept(false) { + if(!a_engine) + throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION); + + return a_engine; } //------------------------------------------------------------------------------ //------------------------------------------------------------ Avp::initialize() //------------------------------------------------------------------------------ -void Avp::initialize() throw() { - a_engine = NULL; +void Avp::initialize() { a_id = helpers::AVPID__AVP; // (0,0) a_flags = 0x00; a_insertionPositionForChilds = 0; @@ -148,7 +132,7 @@ void Avp::initialize() throw() { //------------------------------------------------------------------------------ //----------------------------------------------------------------- Avp::clear() //------------------------------------------------------------------------------ -void Avp::clear() throw(anna::RuntimeException) { +void Avp::clear() noexcept(false) { delete a_OctetString; delete a_Integer32; delete a_Integer64; @@ -183,7 +167,7 @@ void Avp::clear() throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //-------------------------------------------------------------- Avp::avp_find() //------------------------------------------------------------------------------ -avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) throw() { +avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) { int match = 0; Avp *aux; @@ -204,18 +188,29 @@ avp_iterator Avp::avp_find(avp_container &avps, AvpId id, unsigned int position) //------------------------------------------------------------------------------ //---------------------------------------------------------------- Avp::addAvp() //------------------------------------------------------------------------------ -Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw() { - Avp * result = engine->allocateAvp(); +Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) { + Avp * result = engine->createAvp(NULL); result->setId(id); addChild(avps, insertionPositionForChilds, result); return result; } +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::addAvp() +//------------------------------------------------------------------------------ +Avp * Avp::addAvp(Avp * avp) noexcept(false) { + if(!avp) return NULL; + if (avp->getEngine() != getEngine()) return NULL; + addChild(avp); + return avp; +} + + //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::removeAvp() //------------------------------------------------------------------------------ -bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw() { +bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) { bool removed = false; bool do_remove = true; int position = ocurrence; @@ -268,7 +263,7 @@ bool Avp::removeAvp(avp_container &avps, find_container &finds, AvpId id, int oc //------------------------------------------------------------------------------ //-------------------------------------------------------------- Avp::countAvp() //------------------------------------------------------------------------------ -int Avp::countAvp(const avp_container &avps, AvpId id) throw() { +int Avp::countAvp(const avp_container &avps, AvpId id) { int result = 0; const_avp_iterator it; @@ -281,7 +276,7 @@ int Avp::countAvp(const avp_container &avps, AvpId id) throw() { //------------------------------------------------------------------------------ //-------------------------------------------------------------- Avp::firstAvp() //------------------------------------------------------------------------------ -const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() { +const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) { const_avp_iterator it = avp_find(avps, id, 1); if(it != avps.end()) @@ -294,7 +289,7 @@ const Avp* Avp::firstAvp(const avp_container &avps, AvpId id) throw() { //------------------------------------------------------------------------------ //----------------------------------------------------------- Avp::countChilds() //------------------------------------------------------------------------------ -int Avp::countChilds(const avp_container &avps) throw() { +int Avp::countChilds(const avp_container &avps) { return avps.size(); } @@ -302,7 +297,7 @@ int Avp::countChilds(const avp_container &avps) throw() { //------------------------------------------------------------------------------ //---------------------------------------------------------------- Avp::getAvp() //------------------------------------------------------------------------------ -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) { +const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) noexcept(false) { if(ocurrence == 0) { LOGDEBUG(anna::Logger::debug("Ocurrence number zero has no sense. NULL returned.", ANNA_FILE_LOCATION)); return NULL; @@ -391,7 +386,7 @@ const Avp *Avp::getAvp(const avp_container &avps, find_container &finds, AvpId i //------------------------------------------------------------------------------ //--------------------------------------------------------------- Avp::_getAvp() //------------------------------------------------------------------------------ -const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) { +const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode) const noexcept(false) { // Dictionary stack avp and format (this): const stack::Avp *stackAvp = getStackAvp(); const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; @@ -406,7 +401,7 @@ const Avp *Avp::_getAvp(AvpId id, int ocurrence, anna::Exception::Mode::_v emode //------------------------------------------------------------------------------ //---------------------------------------------------------- Avp::assertFormat() //------------------------------------------------------------------------------ -void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeException) { +void Avp::assertFormat(const std::string &name) const noexcept(false) { // Dictionary stack avp and format: const stack::Avp *stackAvp = getStackAvp(); const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; @@ -428,12 +423,14 @@ void Avp::assertFormat(const std::string &name) const throw(anna::RuntimeExcepti //------------------------------------------------------------------------------ //--------------------------------------------------------------- Avp::flagsOK() //------------------------------------------------------------------------------ -bool Avp::flagsOK() const throw() { +bool Avp::flagsOK() const { // Dictionary stack avp: const stack::Avp *stackAvp = getStackAvp(); if(!stackAvp) { - anna::Logger::error("Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok", ANNA_FILE_LOCATION); + std::string msg = "Impossible to decide if flags are correct because stack avp is not identified. Assume flags ok for Avp "; + msg += anna::diameter::functions::avpIdAsPairString(a_id); + anna::Logger::error(msg, ANNA_FILE_LOCATION); return true; }; @@ -458,7 +455,9 @@ bool Avp::flagsOK() const throw() { // V-bit if((Vnone && Mnone && Pnone && vendorBit()) || (Vmust && !vendorBit()) || (Vmustnot && vendorBit())) { - anna::Logger::error("Vendor Bit (V) incoherence found", ANNA_FILE_LOCATION); + std::string msg = "Vendor Bit (V) incoherence found for Avp "; + msg += stackAvp->getName(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); return false; } @@ -467,19 +466,25 @@ bool Avp::flagsOK() const throw() { // M-bit if((Mmust && !mandatoryBit()) || (Mmustnot && mandatoryBit())) { - anna::Logger::error("Mandatory Bit (M) incoherence found", ANNA_FILE_LOCATION); + std::string msg = "Mandatory Bit (M) incoherence found for Avp "; + msg += stackAvp->getName(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); return false; } // P-bit if((Pmust && !encryptionBit()) || (Pmustnot && encryptionBit())) { - anna::Logger::error("Encryption Bit (P) incoherence found", ANNA_FILE_LOCATION); + std::string msg = "Encryption Bit (P) incoherence found for Avp "; + msg += stackAvp->getName(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); return false; } // Reserved bits if((a_flags & 0x1f) != 0x00) { - 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); + std::string msg = "Any (or more than one) of the reserved avp flags bit has been activated. Reserved bits must be null. Avp is "; + msg += stackAvp->getName(); + anna::Logger::error(msg, ANNA_FILE_LOCATION); return false; } @@ -490,7 +495,7 @@ bool Avp::flagsOK() const throw() { //------------------------------------------------------------------------------ //----------------------------------------------------------------- Avp::setId() //------------------------------------------------------------------------------ -void Avp::setId(AvpId id) throw(anna::RuntimeException) { +void Avp::setId(AvpId id) noexcept(false) { // Generic AVP assignment has no sense if(id == helpers::AVPID__AVP) return; @@ -552,7 +557,7 @@ void Avp::setId(AvpId id) throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //----------------------------------------------------------------- Avp::setId() //------------------------------------------------------------------------------ -void Avp::setId(const char *name) throw(anna::RuntimeException) { +void Avp::setId(const char *name) noexcept(false) { setId(getEngine()->avpIdForName(name)); } @@ -560,7 +565,7 @@ void Avp::setId(const char *name) throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //---------------------------------------------------------------- Avp::addAvp() //------------------------------------------------------------------------------ -Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) { +Avp * Avp::addAvp(const char *name) noexcept(false) { return addAvp(getEngine()->avpIdForName(name)); } @@ -568,7 +573,7 @@ Avp * Avp::addAvp(const char *name) throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::removeAvp() //------------------------------------------------------------------------------ -bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeException) { +bool Avp::removeAvp(const char *name, int ocurrence) noexcept(false) { return removeAvp(getEngine()->avpIdForName(name), ocurrence); } @@ -576,7 +581,7 @@ bool Avp::removeAvp(const char *name, int ocurrence) throw(anna::RuntimeExceptio //------------------------------------------------------------------------------ //--------------------------------------------------------------- Avp::_getAvp() //------------------------------------------------------------------------------ -const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException) { +const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const noexcept(false) { return getAvp(getEngine()->avpIdForName(name), ocurrence, emode); } @@ -584,14 +589,14 @@ const Avp *Avp::_getAvp(const char *name, int ocurrence, anna::Exception::Mode:: //------------------------------------------------------------------------------ //-------------------------------------------------------------- Avp::countAvp() //------------------------------------------------------------------------------ -int Avp::countAvp(const char *name) const throw(anna::RuntimeException) { +int Avp::countAvp(const char *name) const noexcept(false) { return countAvp(getEngine()->avpIdForName(name)); } //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::getLength() //------------------------------------------------------------------------------ -U24 Avp::getLength() const throw() { +U24 Avp::getLength() const { U24 result; // Avp format: const stack::Avp *stackAvp = getStackAvp(); @@ -632,7 +637,7 @@ U24 Avp::getLength() const throw() { //------------------------------------------------------------------------------ //-------------------------------------------- Avp::unknownAvpWithMandatoryBit() //------------------------------------------------------------------------------ -void Avp::unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException) { +void Avp::unknownAvpWithMandatoryBit() const noexcept(false) { OamModule &oamModule = OamModule::instantiate(); const char *c_aid = STRING_WITH_QUOTATION_MARKS__C_STR(anna::diameter::functions::avpIdAsPairString(a_id)); oamModule.activateAlarm(OamModule::Alarm::AvpDecode__UnknownAvp__s__WithMandatoryBit, c_aid); @@ -641,17 +646,12 @@ void Avp::unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeE std::string msg = anna::functions::asString("Detected unknown Avp %s with mandatory bit activated", c_aid); anna::Logger::warning(msg, ANNA_FILE_LOCATION); ); - - if(answer) { - answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED); - answer->setNewFailedAvp((Avp*)this); - } } //------------------------------------------------------------------------------ //-------------------------------------------------------- Avp::decodeDataPart() //------------------------------------------------------------------------------ -void Avp::decodeDataPart(const char * buffer, int size, Message *answer) throw(anna::RuntimeException) { +void Avp::decodeDataPart(const char * buffer, int size, const parent_t & parent, Message *answer) noexcept(false) { // OAM OamModule &oamModule = OamModule::instantiate(); // Dictionary stack avp and format: @@ -679,18 +679,27 @@ void Avp::decodeDataPart(const char * buffer, int size, Message *answer) throw(a if((size % 4) != 0) { oamModule.activateAlarm(OamModule::Alarm::AvpDecode__IncorrectLength); oamModule.count(OamModule::Counter::AvpDecode__IncorrectLength); + + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH); + answer->setFailedAvp(parent, a_id); + } + throw anna::RuntimeException("Avp format error, the avp length is incorrect (must be multiple of 4 on grouped type)", ANNA_FILE_LOCATION); } int avpPos = 0; Avp* avp; anna::DataBlock db; + // Me as parent: + parent_t me = parent; + me.addAvp(a_id); while(avpPos < size) { try { - avp = getEngine()->allocateAvp(); + avp = getEngine()->createAvp(NULL); 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) */); - avp -> decode(db, answer); + avp -> decode(db, me, answer); } catch(anna::RuntimeException &ex) { getEngine()->releaseAvp(avp); throw; @@ -717,14 +726,14 @@ void Avp::decodeDataPart(const char * buffer, int size, Message *answer) throw(a //------------------------------------------------------------------------------ //---------------------------------------------------------------- Avp::decode() //------------------------------------------------------------------------------ -void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::RuntimeException) { +void Avp::decode(const anna::DataBlock &db, const parent_t & parent, Message *answer) noexcept(false) { // OAM OamModule &oamModule = OamModule::instantiate(); if(db.getSize() < HeaderLengthVinactive) { oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); - // DIAMETER_INVALID_AVP_LENGTH; // no podré construir un avp fiable, así que no registro el result-code + // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code throw anna::RuntimeException("Not enough bytes to cover avp header length", ANNA_FILE_LOCATION); } @@ -752,7 +761,7 @@ void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::Runtime if(db.getSize() < HeaderLengthVactive) { oamModule.activateAlarm(OamModule::Alarm::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); oamModule.count(OamModule::Counter::AvpDecode__NotEnoughBytesToCoverAvpHeaderLength); - // DIAMETER_INVALID_AVP_LENGTH; // no podré construir un avp fiable, así que no registro el result-code + // DIAMETER_INVALID_AVP_LENGTH; // no podr� construir un avp fiable, as� que no registro el result-code throw anna::RuntimeException(anna::functions::asString("Not enough bytes to cover avp header length (avp code = %u)", code), ANNA_FILE_LOCATION); } @@ -779,7 +788,14 @@ void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::Runtime // 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 // a Diameter client, server, proxy, or translation agent and either the AVP or its value is unrecognized, the message MUST be rejected. // Diameter Relay and redirect agents MUST NOT reject messages with unrecognized AVPs. - if(!getStackAvp() && mandatoryBit()) unknownAvpWithMandatoryBit(answer); + if(!getStackAvp() && mandatoryBit()) { + if(answer) { + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_UNSUPPORTED); + answer->setFailedAvp(parent, a_id); + } + + unknownAvpWithMandatoryBit(); + } // Avp Length U24 length = DECODE3BYTES_INDX_VALUETYPE(buffer, 5, U24); @@ -794,21 +810,21 @@ void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::Runtime if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH); - answer->setNewFailedAvp(a_id); + answer->setFailedAvp(parent, a_id); } throw anna::RuntimeException(anna::functions::asString("Avp format error, the avp length is incorrect (avp code = %u)", code), ANNA_FILE_LOCATION); } try { - decodeDataPart(buffer + startDataPos, dataBytes, answer); + decodeDataPart(buffer + startDataPos, dataBytes, parent, answer); } catch(anna::RuntimeException &ex) { oamModule.activateAlarm(OamModule::Alarm::AvpDecode__DataPartInconsistence); oamModule.count(OamModule::Counter::AvpDecode__DataPartInconsistence); if(answer) { - answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); // unspecified error ... - answer->setNewFailedAvp((Avp*)this); + answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); + answer->setFailedAvp(parent, a_id); } throw anna::RuntimeException(anna::functions::asString("Internal Avp decoding error (avp code = %u): %s", code, ex.getText().c_str()), ANNA_FILE_LOCATION); @@ -819,7 +835,7 @@ void Avp::decode(const anna::DataBlock &db, Message *answer) throw(anna::Runtime //------------------------------------------------------------------------------ //----------------------------------------------------------- Avp::getStackAvp() //------------------------------------------------------------------------------ -const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) throw() { +const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) { const stack::Dictionary * dictionary = engine->getDictionary(); return (dictionary ? (dictionary->getAvp(id)) : NULL); } @@ -828,7 +844,7 @@ const anna::diameter::stack::Avp *Avp::getStackAvp(AvpId id, Engine *engine) thr //------------------------------------------------------------------------------ //------------------------------------------------------------------- Avp::fix() //------------------------------------------------------------------------------ -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() { +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) { // Exit cases if(avps.size() == 0) return; // empty content, nothing to fix @@ -874,7 +890,7 @@ void Avp::fix(avp_container &avps, find_container &finds, int &insertionPosition //------------------------------------------------------------------------------ //------------------------------------------------------------------- Avp::fix() //------------------------------------------------------------------------------ -void Avp::fix() throw() { +void Avp::fix() { // Dictionary stack avp: const stack::Avp *stackAvp = getStackAvp(); const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; @@ -885,7 +901,7 @@ void Avp::fix() throw() { } if(!stackFormat || !stackFormat->isGrouped()) { - //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing fix.", ANNA_FILE_LOCATION)); + //LOGDEBUG(anna::Logger::debug("Avp is not grouped. Nothing to fix.", ANNA_FILE_LOCATION)); return; } @@ -896,7 +912,7 @@ void Avp::fix() throw() { //------------------------------------------------------------------------------ //------------------------------------------------------------ Avp::validLevel() //------------------------------------------------------------------------------ -bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const std::string & parentDescription, Message *answer) throw(anna::RuntimeException) { +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) noexcept(false) { bool result = true; // OAM OamModule &oamModule = OamModule::instantiate(); @@ -934,15 +950,15 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp if(!okFixed) { result = false; // OAM & Depth management - oamModule.activateAlarm(OamModule::Alarm::LevelValidation__MissingFixedRule__s__Inside__s__, STRING_WITH_QUOTATION_MARKS__C_STR((*rule_it).second.asString(false /*ommit dots & pair*/))); + 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())); oamModule.count(OamModule::Counter::LevelValidation__MissingFixedRule); if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP); - answer->setNewFailedAvp((*rule_it).second.getId()); + answer->setFailedAvp(parent, (*rule_it).second.getId()); } - 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(parentDescription))); + 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()))); } } else break; // finish fixed } @@ -965,7 +981,7 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp // Failed rule %s for cardinality (found %d items) result = false; // OAM & Depth management - 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(parentDescription)); + 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())); oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinality); if(amount < min) { @@ -973,18 +989,18 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP); - answer->setNewFailedAvp(id); + answer->setFailedAvp(parent, id); } } else { oamModule.count(OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded); if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_OCCURS_TOO_MANY_TIMES); - answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); + answer->setFailedAvp(parent, id); } } - 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(parentDescription))); + 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()))); } } @@ -1025,15 +1041,15 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp // Failed Generic AVP rule %s for cardinality (found %d disregarded items inside %s) result = false; // OAM & Depth management - 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(parentDescription)); + 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())); oamModule.count(OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem); if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED); - //answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); // NO SENSE... what to put ? + answer->setFailedAvp(parent, id); // NO SENSE... what to put ? } - 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(parentDescription))); + 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()))); } } else if(disregardeds) { // When Generic AVP missing, no disregarded Avps are allowed // Found %d disregarded items inside %s and Generic AVP was not specified @@ -1051,15 +1067,15 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp // We wouldn't know where are these disregarded, but... if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED); - answer->setNewFailedAvp((Avp*)firstAvp(avps, id) /* first instance */); + answer->setFailedAvp(parent, id); } } s_disregardeds.erase(s_disregardeds.size() - 2, 2); // remove last ', ' // OAM & Depth management - oamModule.activateAlarm(OamModule::Alarm::LevelValidation__FoundDisregardedItemsInside__s__AndGenericAVPWasNotSpecified__s__, STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds)); + 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)); oamModule.count(OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified); - engine->validationAnomaly(anna::functions::asString("Found disregarded items inside %s and Generic AVP was not specified: %s", STRING_WITH_QUOTATION_MARKS__C_STR(parentDescription), STRING_WITH_QUOTATION_MARKS__C_STR(s_disregardeds))); + 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))); } return result; @@ -1069,20 +1085,21 @@ bool Avp::validLevel(const avp_container &avps, anna::diameter::stack::const_avp //------------------------------------------------------------------------------ //----------------------------------------------------------------- Avp::valid() //------------------------------------------------------------------------------ -bool Avp::valid(const std::string & parentDescription, Message *answer) const throw(anna::RuntimeException) { +bool Avp::valid(const parent_t & parent, Message *answer) const noexcept(false) { // OAM OamModule &oamModule = OamModule::instantiate(); // Dictionary stack avp: const stack::Avp *stackAvp = getStackAvp(); const stack::Format *stackFormat = stackAvp ? (stackAvp->getFormat()) : NULL /*Unknown*/; - std::string me; if(!stackAvp) { // No dictionary avp reference found. Cannot validate return true; // perhaps a unknown Avp } - me = parentDescription + "->" + stackAvp->getName(); + // Me as parent: + parent_t me = parent; + me.addAvp(a_id, stackAvp->getName().c_str()); if(!stackFormat) { // No format avp reference found. Cannot validate @@ -1096,15 +1113,15 @@ bool Avp::valid(const std::string & parentDescription, Message *answer) const th if(!result) { // OAM & Depth management - oamModule.activateAlarm(OamModule::Alarm::AvpValidation__Avp__s__Flags__d__DoesNotFulfillTheDefinedFlagRules__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription())); + 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())); oamModule.count(OamModule::Counter::AvpValidation__AvpFlagsDoesNotFulfillTheDefinedFlagRules); if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_BITS); - //answer->setNewFailedAvp((Avp*)this); RFC 6733 says nothing about Failed-AVP in this case... + answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); // RFC 6733 says nothing about Failed-AVP in this case... } - 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), (int)a_flags, STRING_WITH_QUOTATION_MARKS__C_STR(stackAvp->getFlagRulesDescription()))); + 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()))); } ////////////////////// @@ -1114,15 +1131,15 @@ bool Avp::valid(const std::string & parentDescription, Message *answer) const th if(!stackAvp->allowEnum(a_Enumerated->getValue())) { result = false; // OAM & Depth management - oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me), a_Enumerated->getValue(), stackAvp->getEnums()); + oamModule.activateAlarm(OamModule::Alarm::AvpValidation__EnumeratedAvp__s__WithValue__d__DoesNotComplyRestriction__s__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums()); oamModule.count(OamModule::Counter::AvpValidation__EnumeratedAvpWithValueDoesNotComplyRestriction); if(answer) { answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); - answer->setNewFailedAvp((Avp*)this); + answer->setFailedAvp(parent, a_id, stackAvp->getName().c_str()); } - getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me), a_Enumerated->getValue(), stackAvp->getEnums())); + getEngine()->validationAnomaly(anna::functions::asString("Enumerated AVP %s with value %d does not comply to restriction: %s", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), a_Enumerated->getValue(), stackAvp->getEnums())); } } @@ -1146,7 +1163,7 @@ bool Avp::valid(const std::string & parentDescription, Message *answer) const th //------------------------------------------------------------------------------ //------------------------------------------------------------------ Avp::code() //------------------------------------------------------------------------------ -void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) { +void Avp::code(char* buffer, int &size) const noexcept(false) { // Code buffer[0] = (S8)(a_id.first >> 24); buffer[1] = (S8)(a_id.first >> 16); @@ -1225,7 +1242,7 @@ void Avp::code(char* buffer, int &size) const throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //------------------------------------------------------------ Avp::getXMLdata() //------------------------------------------------------------------------------ -std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const throw() { +std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) const { std::string result = ""; isHex = false; // Unknown @@ -1240,7 +1257,17 @@ std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) cons if(!stackFormat) { isHex = true; - return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad + // Tricky situation: if you change the dictionary dynamically, and a previous formatted avp + // becomes unknown (the change consists in remove Avps basically), then this would get a core + // dump: a_Unknown = NULL. We are not going to protect that situation because it represents a + // implementation fault, and there are many points which could have similar bad behaviour + // (those where we access directly the a_Unknown pointer). + // The best way to afford this is ... TODO: + // Freeze dictionary after use from any resource (avp, message), setting a flag which deny + // any modification in such dictionary. The best way to do this is on engine configuration + // for Avp o Message, where we could invoke something like getEngine()->getDictionary()->freeze() + + return a_Unknown->asHexString(); // asHexString for OctetString cannot launch exception } // Special case for Address: could launch exception if not printable @@ -1299,10 +1326,20 @@ std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) cons } +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::decode() +//------------------------------------------------------------------------------ +void Avp::decode(const anna::DataBlock &db) noexcept(false) { + parent_t parent; + parent.setMessage(CommandId(0, false), "No-Parent"); + decode(db, parent, NULL); +} + + //------------------------------------------------------------------------------ //--------------------------------------------------------------- Avp::fromXML() //------------------------------------------------------------------------------ -void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) { +void Avp::fromXML(const anna::xml::Node* avpNode) noexcept(false) { // const anna::xml::Attribute *name, *code, *vendorCode, *flags, *data, *hexData; name = avpNode->getAttribute("name", false /* no exception */); @@ -1337,13 +1374,41 @@ void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) // Check attributes exclusiveness if(name) { // compact mode - if(code || flags || vendorCode) { + + if(code || vendorCode) { std::string msg = "Error processing avp getValue(); - msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided"; + msg += "'>: avp attributes <'code' + 'vendorCode'> are not allowed if <'name'> is provided"; throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } + // flags uncertainty: + bool flagsUncertainty = ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot + || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot + /* umm, perhaps we could omit for bit P, whic is deprecated ... */ + /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ ); + if(flags && !flagsUncertainty) { + std::string msg = "Be careful processing avp getValue(); + msg += "'> together with avp 'flags' attribute, because may/shouldnot uncertainty was not specified"; + LOGINFORMATION(Logger::information(msg, ANNA_FILE_LOCATION)); + } + setId(stackAvp->getId()); + + //if (flags && flagsUncertainty) { + if (flags) { + // Flags check + int i_aux = flags->getIntegerValue(); + + if(i_aux < 0 || i_aux > 256) { + std::string msg = "Error processing avp getValue(); + msg += "': out of range [0,256]"; + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + a_flags = i_aux; + } + + } else { if(!code || !flags || !vendorCode) { std::string s_code = code ? code->getValue() : "?"; @@ -1360,9 +1425,11 @@ void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) int i_aux = code->getIntegerValue(); if(i_aux < 0) { - std::string msg = "Error processing avp getValue(); - msg += "': negative values are not allowed"; - throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + LOGWARNING( + std::string msg = "Error processing avp getValue(); + msg += "': negative value read from xml"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); } U24 u_code = i_aux; @@ -1488,7 +1555,7 @@ void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) } try { - avp = getEngine()->allocateAvp(); + avp = getEngine()->createAvp(NULL); avp -> fromXML(*it); } catch(anna::RuntimeException &ex) { getEngine()->releaseAvp(avp); @@ -1532,7 +1599,7 @@ void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException) //------------------------------------------------------------------------------ //----------------------------------------------------------------- Avp::asXML() //------------------------------------------------------------------------------ -anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() { +anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const { // anna::xml::Node* result = parent->createChild("avp"); // Dictionary stack avp and format: @@ -1542,6 +1609,12 @@ anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() { if(compactMode) { result->createAttribute("name", stackAvp->getName()); + // If may or shouldnot is present in AVP definition, we have to show flags to avoid uncertainty + if ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot + || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getMbit() == anna::diameter::stack::Avp::FlagRule::shouldnot + /* umm, perhaps we could omit for bit P, whic is deprecated ... */ + /* || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getPbit() == anna::diameter::stack::Avp::FlagRule::shouldnot*/ ) + result->createAttribute("flags", (int)a_flags); } else { result->createAttribute("code", a_id.first); result->createAttribute("vendor-code", a_id.second); @@ -1571,11 +1644,28 @@ anna::xml::Node* Avp::asXML(anna::xml::Node* parent) const throw() { return result; } + //------------------------------------------------------------------------------ //----------------------------------------------------------- Avp::asXMLString() //------------------------------------------------------------------------------ -std::string Avp::asXMLString() const throw() { +std::string Avp::asXMLString(bool normalize) const { anna::xml::Node root("root"); - return anna::xml::Compiler().apply(asXML(&root)); + + anna::xml::Compiler::Mode::_v mode = normalize ? anna::xml::Compiler::Mode::Sort : anna::xml::Compiler::Mode::Visual; + std::string result = anna::xml::Compiler().apply(asXML(&root), mode); + + if (normalize) + result.erase(std::remove(result.begin(), result.end(), '\n'), result.end()); + + return result; +} + + +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::isLike() +//------------------------------------------------------------------------------ +bool Avp::isLike(const std::string &pattern) const { + anna::RegularExpression re(pattern); + return re.isLike(asXMLString(true /* normalize by mean sorting attribute names and removing new lines */)); }