Improve flags uncertainty. Warning when provided with name attribute
[anna.git] / source / diameter / codec / Avp.cpp
index 79b04b0..be51349 100644 (file)
@@ -59,7 +59,6 @@ Avp::Avp(Engine *engine) : a_engine(engine) {
   initialize();
 }
 
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------- Avp::Avp()
 //------------------------------------------------------------------------------
@@ -68,7 +67,6 @@ Avp::Avp(AvpId id, Engine *engine) : a_engine(engine) {
   setId(id);
 }
 
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------ Avp::~Avp()
 //------------------------------------------------------------------------------
@@ -76,13 +74,24 @@ Avp::~Avp() {
   clear();
 }
 
+//------------------------------------------------------------------------------
+//------------------------------------------------------------- Avp::setEngine()
+//------------------------------------------------------------------------------
+void Avp::setEngine(Engine *engine) throw() {
+  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) {
   if(!a_engine)
-    throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION);
+    throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION);
 
   return a_engine;
 }
@@ -187,6 +196,17 @@ Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id
 }
 
 
+//------------------------------------------------------------------------------
+//---------------------------------------------------------------- Avp::addAvp()
+//------------------------------------------------------------------------------
+Avp * Avp::addAvp(Avp * avp) throw(anna::RuntimeException) {
+  if(!avp) return NULL;
+  if (avp->getEngine() != getEngine()) return NULL;
+  addChild(avp);
+  return avp;
+}
+
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------- Avp::removeAvp()
 //------------------------------------------------------------------------------
@@ -408,7 +428,9 @@ bool Avp::flagsOK() const throw() {
   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;
   };
 
@@ -433,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;
   }
 
@@ -442,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;
   }
 
@@ -1227,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
@@ -1334,20 +1374,28 @@ void Avp::fromXML(const anna::xml::Node* avpNode) throw(anna::RuntimeException)
 
   // Check attributes exclusiveness
   if(name) {  // compact mode
-    bool allowFlagsField = ( stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::may || stackAvp->getVbit() == anna::diameter::stack::Avp::FlagRule::shouldnot
+
+    if(code || vendorCode) {
+      std::string msg = "Error processing avp <name '"; msg += name->getValue();
+      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(code || (flags && !allowFlagsField) || vendorCode) {
-      std::string msg = "Error processing avp <name '"; msg += name->getValue();
-      if (flags) msg += "'>: avp attributes <'code' + 'flags' + 'vendorCode'> are not allowed if <'name'> is provided (also flags is not permitted: no may, no shouldnot)";
-      else msg += "'>: avp attributes <'code' + 'vendorCode'> are not allowed if <'name'> is provided";
-      throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+    if(flags && !flagsUncertainty) {
+      std::string msg = "Be careful processing avp <name '"; msg += name->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 && allowFlagsField) {
+    //if (flags && flagsUncertainty) {
+    if (flags) {
       // Flags check
       int i_aux = flags->getIntegerValue();