Fix enum bug (was on dictionary even when no data). PcapDecoder can load multiple...
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Mon, 6 Apr 2015 14:41:00 +0000 (16:41 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Mon, 6 Apr 2015 14:41:00 +0000 (16:41 +0200)
example/diameter/pcapDecoder/main.cpp
include/anna/diameter/stack/Engine.hpp
source/diameter/stack/Avp.cpp
source/diameter/stack/Engine.cpp

index 80278e4..d296a40 100644 (file)
@@ -55,6 +55,9 @@
 #include <anna/diameter/stack/Engine.hpp>
 #include <anna/diameter/codec/Engine.hpp>
 #include <anna/diameter/codec/Message.hpp>
+//#include <anna/diameter/defines.hpp> // typedef unsigned int ApplicationId;
+#include <anna/diameter/codec/functions.hpp> // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
+
 
 using namespace anna;
 using namespace anna::diameter;
@@ -147,6 +150,7 @@ typedef std::map < int /* frame */, Payload > payloads_t;
 typedef std::map < int /* frame */, Payload >::const_iterator payloads_it;
 payloads_t G_payloads;
 anna::diameter::codec::Message G_codecMsg;
+anna::diameter::codec::Engine *G_codecEngine;
 
 // Sniffing structures ////////////////////////////////////////////////////////////////////////////////////
 
@@ -323,6 +327,17 @@ void _exit(const std::string &message, int resultCode = 1) {
   exit(resultCode);
 }
 
+// Decodes a diameter message coming from a datablock
+void decodeDataBlock(const anna::DataBlock &db, unsigned int & detectedApplicationId) throw() {
+  try {
+    detectedApplicationId = anna::diameter::codec::functions::getApplicationId(db);
+    G_codecEngine->setDictionary(detectedApplicationId);
+    G_codecMsg.decode(db);
+  } catch(RuntimeException &ex) {
+    _exit(ex.asString());
+  }
+}
+
 
 //-------------------------------------------------------------------
 int main(int argc, char **argv) {
@@ -334,88 +349,94 @@ int main(int argc, char **argv) {
   //check command line arguments
   if(argc < 3) {
     std::string msg = "Usage: "; msg += exec;
-    msg += " <dictionaries> <input file> [--non-strict-validation]\n\n";
-    msg += "       dictionaries:            list of comma-separated xml dictionaries (one or more can be provided).\n";
+    msg += " <stacks> <input file> [--no-validation] [--ignore-flags]\n\n";
+    msg += "       stacks:                  <id1#dictionary1,id2#dictionary2,...,idN#dictionaryN>\n";
+    msg += "                                This is a list of comma-separated stacks defined by a #-separated pair <application-id#xml dictionary pathfile>\n";
+    msg += "                                If only one stack is provided, application-id could be omitted and then, all the messages will be decoded with the\n";
+    msg += "                                dictionary regardless the value of the application-id (the stack will be registered with id=0).\n";
     msg += "       Input file:              normally a pcap file, but hexadecimal content (colons allowed) can also be decoded (use '.hex' extension).\n";
-    msg += "       --non-strict-validation: no validation is performed, and wrong flags regarding dictionary are ignored in xml representation.";
+    msg += "       --no-validation:         no validation is performed.\n";
+    msg += "       --ignore-flags:          wrong flags regarding dictionary are ignored in xml representation.";
     _exit(msg);
   }
 
   // Command-line parameters:
-  std::string dictionaries = argv[1];
+  std::string stacks = argv[1];
   std::string inputFile = argv[2];
   bool isHex = (inputFile.substr(inputFile.find_last_of(".") + 1) == "hex");
   std::string outputFile = inputFile; // extension will be added later
-  std::string optional = argv[3] ? argv[3] : "";
-  bool non_strict_validation = ((argc == 4) && (optional == "--non-strict-validation"));
-  std::cout << "Dictionary(ies) provided: " << dictionaries << std::endl;
-  std::cout << "Input file provided:      " << inputFile << std::endl;
-  std::cout << "Validation kindness:      " << (non_strict_validation ? "non strict" : "strict") << std::endl;
-  // Logger and engines:
+  std::string optionals;
+  int indx = 3;
+
+  while(indx < argc) { optionals += " "; optionals += argv[indx]; indx++; }
+
+  bool no_validation = (optionals.find("--no-validation") != std::string::npos);
+  bool ignore_flags = (optionals.find("--ignore-flags") != std::string::npos);
   Logger::setLevel(Logger::Debug);
   Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000));
-  anna::diameter::codec::Engine *codecEngine =
-    new anna::diameter::codec::Engine();
+  G_codecEngine = new anna::diameter::codec::Engine();
   anna::diameter::stack::Engine &stackEngine =
     anna::diameter::stack::Engine::instantiate();
 
+  // Register stacks:
   try {
-    anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(
-        0 /* stack id */);
-    // Analyze comma-separated list:
-    anna::Tokenizer lst;
-    lst.apply(dictionaries, ",");
-
-    if(lst.size() >= 1) {  // always true (at least one, because -dictionary is mandatory)
-      anna::Tokenizer::const_iterator tok_min(lst.begin());
-      anna::Tokenizer::const_iterator tok_max(lst.end());
-      anna::Tokenizer::const_iterator tok_iter;
-      std::string pathFile;
-      d->allowUpdates();
-
-      for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
-        pathFile = anna::Tokenizer::data(tok_iter);
-        d->load(pathFile);
+    anna::Tokenizer stacksTok;
+    stacksTok.apply(stacks, ",");
+    anna::Tokenizer::const_iterator stacks_it, stack_it;
+
+    for(stacks_it = stacksTok.begin(); stacks_it != stacksTok.end(); stacks_it++) {
+      std::string stack = anna::Tokenizer::data(stacks_it);
+      anna::Tokenizer stackTok;
+      stackTok.apply(stack, "#");
+
+      if(stackTok.size() == 1) {
+        if(stacksTok.size() != 1)
+          throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION);
+
+        anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary
+        G_codecEngine->setDictionary(d);
+        break;
       }
-    }
 
-    codecEngine->setDictionary(d);
-    //LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
-
-    if(lst.size() > 1) {
-      std::string all_in_one = "./dictionary-all-in-one.xml";
-      std::ofstream out(all_in_one, std::ifstream::out);
-      std::string buffer = d->asXMLString();
-      out.write(buffer.c_str(), buffer.size());
-      out.close();
-      std::cout << "Written accumulated '" << all_in_one
-                << "' (provide it next time to be more comfortable)." << std::endl;
+      if(stackTok.size() != 2)
+        throw anna::RuntimeException("Each stack must be in the form '<application-id>#<xml dictionary pathfile>'", ANNA_FILE_LOCATION);
+
+      stack_it = stackTok.begin();
+      unsigned int stackId = atoll(anna::Tokenizer::data(stack_it));
+      stack_it++;
+      std::string file = anna::Tokenizer::data(stack_it);
+      anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file);
     }
+
+    std::cout << "Stacks provided:          " << std::endl;
+    std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
+    std::cout << std::endl;
+    std::cout << "Input file provided:      " << inputFile << std::endl;
+    std::cout << "Validation:               " << (!no_validation ? "yes" : "no") << std::endl;
+    std::cout << "Ignore Flags:             " << (ignore_flags ? "yes" : "no") << std::endl;
+    std::cout << std::endl;
   } catch(anna::RuntimeException &ex) {
     _exit(ex.asString());
   }
 
-  if(non_strict_validation) {
-    codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
-    codecEngine->ignoreFlagsOnValidation(true);
-  }
+  // Validation kindness
+  if(no_validation) G_codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
+
+  if(ignore_flags) G_codecEngine->ignoreFlagsOnValidation(true);
 
   // Tracing:
   //if (cl.exists("trace"))
   //   anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace")));
   // Check hex content input file (look extension):
   anna::DataBlock db_aux(true);
+  unsigned int detectedApplicationId;
 
   if(isHex) {
     if(!getDataBlockFromHexFile(inputFile, db_aux))
       _exit("Error reading hex file provided");
 
-    try {
-      G_codecMsg.decode(db_aux);
-    } catch(RuntimeException &ex) {
-      _exit(ex.asString());
-    }
-
+    // Decode datablock:
+    decodeDataBlock(db_aux, detectedApplicationId);
     // Open output file:
     outputFile += ".as.xml";
     std::ofstream out(outputFile, std::ifstream::out);
@@ -467,21 +488,19 @@ int main(int argc, char **argv) {
     out
         << "==================================================================================================="
         << std::endl;
-    out << "Date:           " << ts_str << std::endl;
-    out << "Timestamp:      " << std::to_string(ts) << "."
+    out << "Date:            " << ts_str << std::endl;
+    out << "Timestamp:       " << std::to_string(ts) << "."
         << std::to_string(tsu) << std::endl;
-    out << "Origin IP:      " << (it->second).getSourceIP() << std::endl;
-    out << "Destination IP: " << (it->second).getDestinationIP() << std::endl;
-    out << std::endl;
+    out << "Origin IP:       " << (it->second).getSourceIP() << std::endl;
+    out << "Destination IP:  " << (it->second).getDestinationIP() << std::endl;
     // decode hex string:
     anna::functions::fromHexString((it->second).getDataAsHex(), db_aux);
-
-    try {
-      G_codecMsg.decode(db_aux);
-    } catch(RuntimeException &ex) {
-      _exit(ex.asString());
-    }
-
+    // Decode datablock:
+    decodeDataBlock(db_aux, detectedApplicationId);
+    // Stack identification:
+    //out << "Application Id:  " << detectedApplicationId << std::endl;
+    out << "Dictionary used: " << G_codecEngine->getDictionary()->getName() << std::endl;
+    out << std::endl;
     out << G_codecMsg.asXMLString();
   }
 
index ca3f758..5dcb440 100644 (file)
@@ -71,7 +71,7 @@ class Engine : public anna::Singleton <Engine> {
 
 public:
 
-  typedef std::map<int, Dictionary*> stack_container;
+  typedef std::map<unsigned int, Dictionary*> stack_container;
   typedef stack_container::const_iterator const_stack_iterator;
   typedef stack_container::iterator stack_iterator;
 
@@ -84,7 +84,7 @@ public:
   * @param stackId Stack identifier.
   * @return Dictionary reference, NULL if no stack found
   */
-  const Dictionary * getDictionary(int stackId) const throw();
+  const Dictionary * getDictionary(unsigned int stackId) const throw();
 
   /** Beginning stack iterator */
   const_stack_iterator stack_begin() const throw() { return a_stacks.begin(); }
@@ -104,9 +104,11 @@ public:
   /**
   * Class string representation
   *
+  * @param all Complete engine information versus only stacks list with its ids and dictionary names
+  *
   * @return String with class content
   */
-  std::string asString(void) const throw();
+  std::string asString(bool all = true) const throw();
 
   // set
 
@@ -143,7 +145,7 @@ public:
   *
   * @return Dictionary registered. When exception happen, dictionary can be accessed by #getDictionary
   */
-  Dictionary * createDictionary(int stackId, const std::string & xmlPathFile = "") throw(anna::RuntimeException);
+  Dictionary * createDictionary(unsigned int stackId, const std::string & xmlPathFile = "") throw(anna::RuntimeException);
 
   /**
   * Register a externally created Dictionary or a derived class from Dictionary
@@ -154,7 +156,7 @@ public:
   *
   * @return Dictionary registered. When exception happen, dictionary can be accessed by #getDictionary
   */
-  Dictionary * registerDictionary(int stackId, Dictionary *dictionary) throw(anna::RuntimeException);
+  Dictionary * registerDictionary(unsigned int stackId, Dictionary *dictionary) throw(anna::RuntimeException);
 
   /**
   * Loads an XML dictionary document over the diameter stack identifiers (one or more stack id's).
@@ -164,7 +166,7 @@ public:
   * @param stacks Stacks identifiers over which the dictionary will be load.
   * @param xmlPathFile Path file to the xml document which represents the diameter dictionary.
   */
-  void loadDictionary(const std::vector<int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException);
+  void loadDictionary(const std::vector<unsigned int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException);
 
   /**
   * Loads an XML dictionary document over all the diameter engine registered stacks. When more than one stack id is
@@ -185,7 +187,7 @@ public:
   *
   * @param stackId Stack identifier for created dictionary
   */
-  void removeStack(int stackId) throw();
+  void removeStack(unsigned int stackId) throw();
 
 private:
 
index d3d971d..252e816 100644 (file)
@@ -294,7 +294,9 @@ anna::xml::Node* anna::diameter::stack::Avp::asXML(anna::xml::Node* parent) cons
     single->createAttribute("format-name", a_formatName);
 
     if(format->isEnumerated()) {
-      single->createAttribute("enum", getEnums());
+      std::string enums = getEnums();
+
+      if(enums != "") single->createAttribute("enum", enums);
     }
 
     if(hasAliases()) {
index 07daa79..bb46cbe 100644 (file)
@@ -163,7 +163,7 @@ anna::diameter::stack::Engine::Engine(void) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------ Engine::getDictionary()
 //------------------------------------------------------------------------------
-const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(int stackId) const throw() {
+const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(unsigned int stackId) const throw() {
   const Dictionary * result = NULL;
   const_stack_iterator it = a_stacks.find(stackId);
 
@@ -176,12 +176,12 @@ const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDict
 //------------------------------------------------------------------------------
 //----------------------------------------------------------- Engine::asString()
 //------------------------------------------------------------------------------
-std::string anna::diameter::stack::Engine::asString(void) const throw() {
+std::string anna::diameter::stack::Engine::asString(bool all) const throw() {
   std::string trace;
-  int stackId;
+  unsigned int stackId;
 
   if(isEmpty()) {
-    trace = "No diameter dictionaries found";
+    trace = "No diameter stacks found";
   } else {
     int numberOfStacks = stack_size();
     trace = ((numberOfStacks > 1) ? "Multi-stack " : "Mono-stack ");
@@ -194,7 +194,11 @@ std::string anna::diameter::stack::Engine::asString(void) const throw() {
       std::string title = "Diameter stack id = ";
       title += anna::functions::asString((*it).first);
       trace += anna::functions::highlightJustify(title);
-      trace += (*it).second->asString(); trace += "\n";
+
+      if(all) trace += (*it).second->asString();
+      else trace += (*it).second->getName();
+
+      trace += "\n";
     }
   }
 
@@ -206,7 +210,7 @@ std::string anna::diameter::stack::Engine::asString(void) const throw() {
 //------------------------------------------------------------------------------
 //------------------------------------------------- Engine::registerDictionary()
 //------------------------------------------------------------------------------
-anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDictionary(int stackId, Dictionary *dictionary) throw(anna::RuntimeException) {
+anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDictionary(unsigned int stackId, Dictionary *dictionary) throw(anna::RuntimeException) {
   Dictionary * result = const_cast<Dictionary *>(getDictionary(stackId));
 
   if(!dictionary)
@@ -227,7 +231,7 @@ anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDicti
 //------------------------------------------------------------------------------
 //--------------------------------------------------- Engine::createDictionary()
 //------------------------------------------------------------------------------
-anna::diameter::stack::Dictionary *  anna::diameter::stack::Engine::createDictionary(int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) {
+anna::diameter::stack::Dictionary *  anna::diameter::stack::Engine::createDictionary(unsigned int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) {
   Dictionary * result = const_cast<Dictionary *>(getDictionary(stackId));
 
   if(result)  // if exists, launch exception
@@ -249,8 +253,8 @@ anna::diameter::stack::Dictionary *  anna::diameter::stack::Engine::createDictio
 }
 
 
-void anna::diameter::stack::Engine::loadDictionary(const std::vector<int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) {
-  std::vector<int>::const_iterator it;
+void anna::diameter::stack::Engine::loadDictionary(const std::vector<unsigned int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) {
+  std::vector<unsigned int>::const_iterator it;
   Dictionary *d;
 
   if(xmlPathFile == "")
@@ -289,7 +293,7 @@ void anna::diameter::stack::Engine::loadDictionary(const std::string & xmlPathFi
 //------------------------------------------------------------------------------
 //-------------------------------------------------------- Engine::removeStack()
 //------------------------------------------------------------------------------
-void anna::diameter::stack::Engine::removeStack(int stackId) throw() {
+void anna::diameter::stack::Engine::removeStack(unsigned int stackId) throw() {
   stack_iterator it = a_stacks.find(stackId);
 
   if(it != stack_end()) {  // if exists, clear