# Check Failed-AVP & Subscription-Id within:
CHECKPATTERN <avp name="Result-Code" data="5004" alias="DIAMETER_INVALID_AVP_VALUE"/>
-CHECKPATTERN <avp name="Failed-AVP">( *)<avp name="Media-Component-Description"
-
-# TODO: check that the complete hierarchy to Flow-Status (the real bad avp)
+CHECKPATTERN <avp name="Failed-AVP">( *)<avp name="Media-Component-Description">( *)<avp name="Media-Sub-Component">( *)<avp name="Flow-Status" data="0" alias="ENABLED-UPLINK"/>
#include <anna/config/defines.hpp>
#include <anna/diameter/defines.hpp>
#include <anna/diameter/codec/basetypes/basetypes.hpp>
+#include <anna/diameter/codec/functions.hpp>
#include <anna/diameter/stack/Avp.hpp>
#include <anna/core/RuntimeException.hpp>
static Avp * addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id, Engine *engine) throw();
static bool removeAvp(avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine) throw();
static void fix(avp_container &avps, find_container &finds, int &insertionPositionForChilds, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd) throw();
- static bool 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); // validates mandatory/fixed and cardinality
+ static bool validLevel(const avp_container &avps, anna::diameter::stack::const_avprule_iterator ruleBegin, anna::diameter::stack::const_avprule_iterator ruleEnd, Engine * engine, const anna::diameter::codec::parent_t & parent, Message *answer) throw(anna::RuntimeException); // validates mandatory/fixed and cardinality
static const Avp* getAvp(const avp_container &avps, find_container &finds, AvpId id, int ocurrence, Engine *engine, anna::Exception::Mode::_v emode) throw(anna::RuntimeException);
static int countAvp(const avp_container &avps, AvpId id) throw();
static const Avp* firstAvp(const avp_container &avps, AvpId id) throw();
/**
Validates an Avp regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
- @param parentDescription Parent description. Internally used for alarms and tracing
+ @param parent Parent description. Internally used for alarms, tracing and Failed-AVP construction
@param answer Answer could be modified with any validation problem during requests validation
@return Boolean indicating validation result
*/
- bool valid(const std::string & parentDescription, Message *answer) const throw(anna::RuntimeException);
+ bool valid(const anna::diameter::codec::parent_t & parent, Message *answer) const throw(anna::RuntimeException);
/**
Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
depending on validation depth (codec::Engine::ValidationDepth).
@param db Buffer data block processed
+ @param parent Parent description. Internally used for alarms, tracing and Failed-AVP construction
@param answer Answer built for request decoding/validation
*/
- void decode(const anna::DataBlock &db, Message *answer) throw(anna::RuntimeException);
+ void decode(const anna::DataBlock &db, const anna::diameter::codec::parent_t & parent, Message *answer) throw(anna::RuntimeException);
/////////////////////////////////////////////
@param buffer Avp data part start pointer
@param size Avp data part size
+ @param parent Parent description. Internally used for alarms, tracing and Failed-AVP construction
@param answer Answer built for request decoding/validation
*/
- void decodeDataPart(const char * buffer, int size, Message *answer) throw(anna::RuntimeException);
+ void decodeDataPart(const char * buffer, int size, const anna::diameter::codec::parent_t & parent, Message *answer) throw(anna::RuntimeException);
public:
Default implementation launch alarm and counter indicating the anomaly but don't launch exception (traces at warning level).
Relay and Redirect agents could reimplement this method to avoid oam management (another way is avoid alarm/counter registration on
these applications). Result-Code DIAMETER_AVP_UNSUPPORTED will be stored for possible answer message.
-
- @param answer Answer built for request decoding/validation
*/
- virtual void unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException);
+ virtual void unknownAvpWithMandatoryBit() const throw(anna::RuntimeException);
friend class Message;
bool flagsOK(int &rc) const throw(); // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary.
int addChild(Avp *avp) throw() { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); }
const anna::diameter::stack::Command *getStackCommand(CommandId id) const throw(anna::RuntimeException);
- Avp * addTheFailedAVP() throw(); // returns the Failed-AVP if exists, creates it when missing. The method could be named 'addFailedAVP'
- // but we consider this better because only one instance (as RFC 6733 says in section 7.5) will be
- // added by internal procedures (although, the application could obviously add more).
+
+ void setFailedAvp(const parent_t &parent, AvpId wrong) throw(anna::RuntimeException);
+ // During message decoding and validation, the first wrong avp is stored and all the tracking is managed to find out its
+ // nested path for the case of grouped avps with wrong avps inside. Remember the RFC 6733, section 7.5:
+ //
+ // In the case where the offending AVP is embedded within a Grouped AVP,
+ // the Failed-AVP MAY contain the grouped AVP, which in turn contains
+ // the single offending AVP. The same method MAY be employed if the
+ // grouped AVP itself is embedded in yet another grouped AVP and so on.
+ // In this case, the Failed-AVP MAY contain the grouped AVP hierarchy up
+ // to the single offending AVP. This enables the recipient to detect
+ // the location of the offending AVP when embedded in a group.
+ //
+ // The first wrong avp found will set the final result code, as the RFC recommends:
+ //
+ // The value of the Result-Code AVP will provide information on the reason
+ // for the Failed-AVP AVP. A Diameter answer message SHOULD contain an
+ // instance of the Failed-AVP AVP that corresponds to the error
+ // indicated by the Result-Code AVP. For practical purposes, this
+ // Failed-AVP would typically refer to the first AVP processing error
+ // that a Diameter node encounters.
+ //
+ // The message keeps the list (reverse order) of avps hierarchy (in case of grouping) for the final Failed-AVP construction,
+ // which is done at the end of decoding or validation, and only the first wrong avp is stored with its corresponding path.
+
protected:
Result-Code and/or Failed-AVP AVPs if proceed, but be aware of DIAMETER_COMMAND_UNSUPPORTED Result-Code, because becomes impossible
to fix (Session-Id SHOULD appear immediately following the Diameter header, and #fix do this manually even if no information about
the command structure is known, but perhaps another fixed AVPs could not comply... use #getResultCode to find out this situation before
- using #setStandardToAnswer).
+ using #setStandardToAnswer). Anyway, application could add another Failed-AVP content no detected internally, for example:
+ DIAMETER_CONTRADICTING_AVPS or DIAMETER_INVALID_AVP_BIT_COMBO). Also, application could add more Failed-AVP avps with other
+ wrong avps, or accumulate wrong avps inside the one and only Failed-AVP managed by the stack. The standard is open to add multiple
+ avps inside Failed-AVP or multiple Failed-AVP avps with single or multiple avps inside. This depends on application criteria regarding
+ other nodes. However, internally the Anna::diameter stack only provides one Failed-AVP with the first wrong avp found, as RFC 6733 says
+ in section 7.5.
If application decoding and/or validation operations are ok, user may search for other problems and put the appropiate Result-Code.
For example, DIAMETER_TOO_BUSY (3004) depends on congestion issues at business layer and cannot be decided with the only message
int getResultCode() const throw();
- /**
- Adds the wrong AVP within the Failed-AVP over an answer message (for requests, do nothing).
- If Failed-AVP AVP doesn't exists, is added and then filled (added within) with the value provided (empty AVP id representantion).
- If Failed-AVP AVP already exists, is probably filled by a previous found error, but anyway this is verified and if empty then is
- filled (added within) with the value provided (empty AVP id representantion).
-
- This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application
- could call this for set another Failed-AVP content no detected by these methods, for example: DIAMETER_CONTRADICTING_AVPS or
- DIAMETER_INVALID_AVP_BIT_COMBO). Also, application could add more Failed-AVP avps with other wrong avps, or accumulate wrong
- avps inside the one and only Failed-AVP managed by the stack (see section 7.5 of RFC 6733).
-
- @param id Avp identifier as pair (code,vendor-id).
-
- @return Pointer to the new AVP added within Failed-AVP, to make easy data-part access if needed.
- */
- Avp * setFailedAvp(AvpId id) throw(anna::RuntimeException);
-
- /**
- Same as #setFailedAvp(AvpId id) but providing an avp pointer with the needed information
-
- @param avp Pointer to the added wrong avp
-
- @return Pointer to the new AVP added within Failed-AVP, to make easy data-part access if needed.
- */
- Avp * setFailedAvp(Avp *avp) throw(anna::RuntimeException);
-
-
-
/**
Adds an avp child providing its identifier and reserve internal memory it.
// STL
#include <string>
+#include <vector>
+
//------------------------------------------------------------------------------
//---------------------------------------------------------------------- #define
namespace codec {
+// Used for alarms, tracing and Failed-AVP construction:
+typedef struct parent {
+
+ // Used on decoding:
+ anna::diameter::CommandId MessageId;
+ std::string MessageName;
+
+ std::vector<anna::diameter::AvpId> AvpsId;
+ std::vector<std::string> AvpsName;
+
+ void setMessage(const anna::diameter::CommandId & mid, const char *mname = NULL /* well known in validation */) throw();
+ void addAvp(const anna::diameter::AvpId & aid, const char *aname = NULL /* well known in validation */) throw();
+ std::string asString() const throw();
+
+} parent_t;
+
+
+
+
struct functions {
// getters & helpers
static bool isAnswer(const CommandId & cid) throw() { return (!isRequest(cid)); }
static bool isAnswer(const anna::DataBlock & db) throw(anna::RuntimeException) { return (!isRequest(db)); }
+
/**
* Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context.
*
//------------------------------------------------------------------------------
//-------------------------------------------- Avp::unknownAvpWithMandatoryBit()
//------------------------------------------------------------------------------
-void Avp::unknownAvpWithMandatoryBit(Message *answer) const throw(anna::RuntimeException) {
+void Avp::unknownAvpWithMandatoryBit() const throw(anna::RuntimeException) {
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);
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->setFailedAvp((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) throw(anna::RuntimeException) {
// OAM
OamModule &oamModule = OamModule::instantiate();
// Dictionary stack avp and format:
if(answer) {
answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
- //answer->setFailedAvp(a_id);
+ 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);
Avp* avp;
anna::DataBlock db;
+ // Me as parent:
+ parent_t me = parent;
+ me.addAvp(a_id);
+
while(avpPos < size) {
try {
avp = getEngine()->allocateAvp();
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;
//------------------------------------------------------------------------------
//---------------------------------------------------------------- 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) throw(anna::RuntimeException) {
// OAM
OamModule &oamModule = OamModule::instantiate();
// 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);
if(answer) {
answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_LENGTH);
- //answer->setFailedAvp(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->setFailedAvp((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);
//------------------------------------------------------------------------------
//------------------------------------------------------------ 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) throw(anna::RuntimeException) {
bool result = true;
// OAM
OamModule &oamModule = OamModule::instantiate();
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->setFailedAvp((*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
}
// 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) {
if(answer) {
answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_MISSING_AVP);
- answer->setFailedAvp(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->setFailedAvp((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())));
}
}
// 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->setFailedAvp((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
// We wouldn't know where are these disregarded, but...
if(answer) {
answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_AVP_NOT_ALLOWED);
- answer->setFailedAvp((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;
//------------------------------------------------------------------------------
//----------------------------------------------------------------- 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 throw(anna::RuntimeException) {
// 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
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->setFailedAvp((Avp*)this); // RFC 6733 says nothing about Failed-AVP in this case...
+ answer->setFailedAvp(parent, a_id); // 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())));
}
//////////////////////
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->setFailedAvp((Avp*)this);
+ answer->setFailedAvp(parent, a_id);
}
- 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()));
}
}
// STL
#include <string>
+#include <vector>
using namespace anna;
Avp* avp;
anna::DataBlock db_aux;
+ // Parent information:
+ parent_t parent;
+ parent.setMessage(a_id);
+
+
while(avpPos < dataBytes) {
try {
avp = getEngine()->allocateAvp();
db_aux.assign(startData + avpPos, dataBytes - avpPos /* is valid to pass total length (indeed i don't know the real avp length) because it will be limited and this has deep copy disabled (no memory is reserved) */);
- avp -> decode(db_aux, answer);
+ avp -> decode(db_aux, parent, answer);
} catch(anna::RuntimeException &ex) {
- if(answer) {
- //answer->setResultCode(helpers::base::AVPVALUES__Result_Code::DIAMETER_INVALID_AVP_VALUE); // unspecified error ...
- answer->setFailedAvp(avp->getId());
- }
getEngine()->releaseAvp(avp);
LOGWARNING(
anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION);
}
-//------------------------------------------------------------------------------
-//--------------------------------------------------- Message::addTheFailedAVP()
-//------------------------------------------------------------------------------
-Avp * Message::addTheFailedAVP() throw() {
- Avp *result = getAvp(helpers::base::AVPID__Failed_AVP, 1, anna::Exception::Mode::Ignore);
-
- // Section 7.5 RFC 6733: A Diameter message SHOULD contain one Failed-AVP AVP
- if(!result) result = addAvp(helpers::base::AVPID__Failed_AVP);
-
- return result;
-}
-
-
//------------------------------------------------------------------------------
//------------------------------------------------------ Message::setFailedAvp()
//------------------------------------------------------------------------------
-Avp * Message::setFailedAvp(AvpId id) throw(anna::RuntimeException) {
+void Message::setFailedAvp(const parent_t &parent, AvpId wrong) throw(anna::RuntimeException) {
- if(isRequest()) return NULL;
+ if(isRequest()) return;
// RFC 6733:
//
// Probably the RFC wants to give freedom to the application layer, but it is recommended to
// have only one child (wrong avp) inside a unique message Failed-AVP to ease the Result-Code
// correspondence. Anyway, this behaviour could be easily opened commenting condition block (*).
- Avp *theFailedAvp = addTheFailedAVP();
- LOGDEBUG(
- std::string msg = "Adding wrong avp ";
- msg += anna::diameter::functions::avpIdAsPairString(id);
- msg += " within the message Failed-AVP ...";
- anna::Logger::debug(msg, ANNA_FILE_LOCATION);
- );
-
- if (theFailedAvp->countChilds()) { // (*)
- LOGDEBUG(anna::Logger::debug("Discarding wrong avp. A previous wrong avp was already added into the Failed-AVP. RFC 6733 Section 7.5 recommends to store only the first.", ANNA_FILE_LOCATION));
- return NULL;
+ Avp *theFailedAvp = getAvp(helpers::base::AVPID__Failed_AVP, 1, anna::Exception::Mode::Ignore);
+ if (theFailedAvp) {
+ LOGDEBUG(anna::Logger::debug("Failed-AVP has already been added. RFC 6733 Section 7.5 recommends to store only the first error found", ANNA_FILE_LOCATION));
+ return;
}
- return (theFailedAvp->addAvp(id));
-}
-
-
-//------------------------------------------------------------------------------
-//------------------------------------------------------ Message::setFailedAvp()
-//------------------------------------------------------------------------------
-Avp * Message::setFailedAvp(Avp *avp) throw(anna::RuntimeException) {
-
- if(!avp || isRequest()) return NULL;
+ // Section 7.5 RFC 6733: A Diameter message SHOULD contain one Failed-AVP AVP
+ theFailedAvp = addAvp(helpers::base::AVPID__Failed_AVP);
+ Avp *leaf = theFailedAvp;
- Avp *theFailedAvp = addTheFailedAVP();
LOGDEBUG(
- std::string msg = "Adding wrong avp ";
- msg += anna::diameter::functions::avpIdAsPairString(avp->getId());
- msg += " within the message Failed-AVP ...";
+ std::string msg = "Adding to Failed-AVP, the wrong avp ";
+ msg += anna::diameter::functions::avpIdAsPairString(wrong);
+ msg += " found inside ";
+ msg += parent.asString();
+
anna::Logger::debug(msg, ANNA_FILE_LOCATION);
);
- if (theFailedAvp->countChilds()) { // (*)
- LOGDEBUG(anna::Logger::debug("Discarding wrong avp. A previous wrong avp was already added into the Failed-AVP. RFC 6733 Section 7.5 recommends to store only the first.", ANNA_FILE_LOCATION));
- return NULL;
- }
+ std::vector<AvpId>::const_iterator it;
+ for(it = parent.AvpsId.begin(); it != parent.AvpsId.end(); it++)
+ leaf = leaf->addAvp(*it);
- return (theFailedAvp->addAvp(avp));
+ leaf->addAvp(wrong);
}
OamModule &oamModule = OamModule::instantiate();
// Dictionary stack command:
const stack::Command *stackCommand = getStackCommand();
- std::string me;
// Only build answer for a request:
Message *answer = isRequest() ? ptrAnswer : NULL;
if(!stackCommand) {
// OAM
- me = anna::diameter::functions::commandIdAsPairString(a_id);
+ std::string me = anna::diameter::functions::commandIdAsPairString(a_id);
oamModule.activateAlarm(OamModule::Alarm::MessageValidation__UnknownOperation__s__UnableToValidate, STRING_WITH_QUOTATION_MARKS__C_STR(me));
oamModule.count(OamModule::Counter::MessageValidation__UnknownOperationUnableToValidate);
return false;
}
- me = stackCommand->getName();
+ // Parent information:
+ parent_t me;
+ me.setMessage(a_id, stackCommand->getName().c_str());
+
//////////////////////////////
// Flags coherence checking //
//////////////////////////////
if(!result) {
// OAM & Depth management
- oamModule.activateAlarm(OamModule::Alarm::MessageValidation__Operation__s__HaveIncoherentFlags__d__, STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags);
+ oamModule.activateAlarm(OamModule::Alarm::MessageValidation__Operation__s__HaveIncoherentFlags__d__, STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags);
oamModule.count(OamModule::Counter::MessageValidation__OperationHaveIncoherentFlags);
if(answer) answer->setResultCode(rc);
- getEngine()->validationAnomaly(anna::functions::asString("Operation %s have incoherent flags (%d)", STRING_WITH_QUOTATION_MARKS__C_STR(me), (int)a_flags));
+ getEngine()->validationAnomaly(anna::functions::asString("Operation %s have incoherent flags (%d)", STRING_WITH_QUOTATION_MARKS__C_STR(me.asString()), (int)a_flags));
}
////////////////////
using namespace anna::diameter::codec;
+
+
+// Parent struct helper /////////////////////////////////////////////////////////////////////////////
+void parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) throw() {
+ MessageId = mid;
+ if (mname) {
+ MessageName = mname;
+ }
+ else {
+ MessageName = "Message";
+ MessageName += anna::diameter::functions::commandIdAsPairString(mid);
+ }
+}
+
+void parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) throw() {
+ AvpsId.push_back(aid);
+ std::string name;
+ if (aname) {
+ name = aname;
+ }
+ else {
+ name = "Avp";
+ name += anna::diameter::functions::avpIdAsPairString(aid);
+ }
+ AvpsName.push_back(name);
+}
+
+std::string parent::asString() const throw() { // "<command><avp 1>-><avp 2>->...-><avp N>"
+ std::string result = MessageName;
+ for (std::vector<std::string>::const_iterator it = AvpsName.begin(); it != AvpsName.end(); it++) {
+ result += "->";
+ result += (*it);
+ }
+
+ return result;
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
// getters
anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) {
if(db.getSize() < Message::HeaderLength)