1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
16 #include <anna/core/DataBlock.hpp>
17 #include <anna/core/util/Tokenizer.hpp>
18 #include <anna/core/functions.hpp>
19 #include <anna/core/tracing/Logger.hpp>
20 #include <anna/core/tracing/TraceWriter.hpp>
21 #include <anna/core/RuntimeException.hpp>
22 #include <anna/io/Directory.hpp>
23 #include <anna/xml/xml.hpp>
24 #include <anna/diameter/stack/Engine.hpp>
25 #include <anna/diameter/codec/Engine.hpp>
26 #include <anna/diameter/codec/EngineManager.hpp>
27 #include <anna/diameter/codec/Message.hpp>
28 //#include <anna/diameter/codec/functions.hpp> // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
32 using namespace anna::diameter;
34 anna::diameter::codec::Message G_codecMsg;
36 bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) throw() {
38 static char buffer[8192];
39 std::ifstream infile(pathfile.c_str(), std::ifstream::in);
41 if(infile.is_open()) {
43 std::string hexString(buffer, strlen(buffer));
44 // Allow colon separator in hex string: we have to remove them before processing with 'fromHexString':
45 hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
47 std::string msg = "Hex string (remove colons if exists): ";
49 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
51 anna::functions::fromHexString(hexString, db);
61 void _exit(const std::string &message, int resultCode = 1) {
63 std::cerr << message << std::endl << std::endl;
65 std::cout << message << std::endl << std::endl;
70 // Decodes a diameter message coming from a datablock
71 bool decodeDataBlock(const anna::DataBlock &db/*, unsigned int & detectedApplicationId*/) throw() {
74 G_codecMsg.decode(db);
75 } catch(RuntimeException &ex) {
76 std::cerr << ex.asString() << std::endl << std::endl;
77 //_exit(ex.asString());
84 //-------------------------------------------------------------------
85 int main(int argc, char **argv) {
86 std::string exec = argv[0];
87 std::string execBN = exec.substr(exec.find_last_of("/") + 1);
88 std::string filetrace = execBN + ".trace";
89 std::cout << std::endl;
91 //check command line arguments
93 std::string msg = "Usage: "; msg += exec;
94 msg += " <stacks> <working directory> [--hex-only] [--xml-only] [--no-validation] [--ignore-flags] [--debug]\n\n";
95 msg += " stacks: <appid1,dictionary1#appid2,dictionary2#...#appidN,dictionaryN>\n";
96 msg += " This is a list of #-separated stacks defined by a comma-separated pair <application-id,xml dictionary pathfile>\n";
97 msg += " If only one stack is provided, application-id could be omitted and then, all the messages will be decoded with the\n";
98 msg += " dictionary regardless the value of the application-id (the stack will be registered with id=0).\n";
99 msg += " Working directory: Contains 'xml files' (ANNA-Diameter message format) and/or 'hex files' (hexadecimal content, colons allowed).\n";
100 msg += " --hex-only: Only hex files are converted.\n";
101 msg += " --xml-only: Only xml files are converted.\n";
102 msg += " --no-validation: no validation is performed.\n";
103 msg += " --ignore-flags: wrong flags regarding dictionary are ignored in xml representation.\n";
104 msg += " --debug: activates debug level traces (warning by default).\n";
106 msg += " The batch process will translate '.xml' files into '.xml.as.hex', and '.hex' files into '.hex.as.xml'\n";
107 msg += " Take care not to include the dictionary files (which have '.xml' extension) in the working directory, or there will be an exception.\n";
111 // Command-line parameters:
112 std::string stacks = argv[1];
113 std::string wkDir = argv[2];
114 std::string optionals;
116 while(indx < argc) { optionals += " "; optionals += argv[indx]; indx++; }
118 bool no_validation = (optionals.find("--no-validation") != std::string::npos);
119 bool ignore_flags = (optionals.find("--ignore-flags") != std::string::npos);
120 bool debug = (optionals.find("--debug") != std::string::npos);
121 bool hexOnly = (optionals.find("--hex-only") != std::string::npos);
122 bool xmlOnly = (optionals.find("--xml-only") != std::string::npos);
123 if (hexOnly && xmlOnly) _exit("Cannot provide both '--hex-only' and '--xml-only' !!");
124 bool processXml = hexOnly ? false:true;
125 bool processHex = xmlOnly ? false:true;
126 Logger::setLevel(debug ? Logger::Debug:Logger::Warning);
127 Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000));
128 anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
129 anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
130 anna::diameter::codec::Engine *ce;
131 unsigned int appid = 0;
136 anna::Tokenizer stacksTok;
137 stacksTok.apply(stacks, "#");
138 anna::Tokenizer::const_iterator stacks_it, stack_it;
140 for(stacks_it = stacksTok.begin(); stacks_it != stacksTok.end(); stacks_it++) {
141 std::string stack = anna::Tokenizer::data(stacks_it);
142 anna::Tokenizer stackTok;
143 stackTok.apply(stack, ",");
145 if(stackTok.size() == 1) {
146 if(stacksTok.size() != 1)
147 throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION);
148 anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(appid, stack); // the stack is the dictionary
149 ce = new anna::diameter::codec::Engine("CodecEngineForUniqueStackId_0", d);
150 em.registerCodecEngine(0, ce);
154 if(stackTok.size() != 2)
155 throw anna::RuntimeException("Each stack must be in the form '<application-id>,<xml dictionary pathfile>'", ANNA_FILE_LOCATION);
157 stack_it = stackTok.begin();
158 unsigned int stackId = atoll(anna::Tokenizer::data(stack_it));
160 std::string file = anna::Tokenizer::data(stack_it);
161 anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(stackId, file);
162 std::string codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", stackId);
163 ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d);
164 em.registerCodecEngine(stackId, ce);
167 std::cout << "Stacks provided: " << std::endl;
168 std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
169 std::cout << std::endl;
170 std::cout << "Working directory: " << wkDir << std::endl;
171 std::cout << "Validation: " << (!no_validation ? "yes" : "no") << std::endl;
172 std::cout << "Ignore Flags: " << (ignore_flags ? "yes" : "no") << std::endl;
173 std::cout << std::endl;
174 } catch(anna::RuntimeException &ex) {
175 _exit(ex.asString());
178 // Validation kindness
179 for (anna::diameter::codec::appid_codec_engines_it it = em.begin(); it != em.end(); it++) {
181 ce->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire)
182 ce->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports
183 if(no_validation) ce->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
184 if(ignore_flags) ce->ignoreFlagsOnValidation(true);
187 // Auxiliary variables:
188 anna::DataBlock db_aux(true);
189 anna::io::Directory directoryHex, directoryXml; // we separate (although it wouldn't be neccessary using setPattern each time), because we don't
190 // want to process the resulting xml files from hex conversion, only the xml files present at the
191 // beginning in the directory
193 directoryHex.setPattern(".hex$");
194 directoryHex.read(wkDir.c_str(), anna::io::Directory::Mode::FullPath);
195 directoryXml.setPattern(".xml$");
196 directoryXml.read(wkDir.c_str(), anna::io::Directory::Mode::FullPath);
198 // Processing .hex files:
199 bool anyHexConverted = false;
201 for (anna::io::Directory::const_iterator it = directoryHex.begin(); it != directoryHex.end(); it++) {
202 const std::string& entry = anna::io::Directory::data (it);
203 LOGDEBUG(anna::Logger::debug(entry + " is being converted to xml", ANNA_FILE_LOCATION));
205 if(!getDataBlockFromHexFile(entry, db_aux))
206 _exit("Error reading hex file provided");
209 if (decodeDataBlock(db_aux)) {
212 std::string outputFile = entry + ".as.xml";
213 std::ofstream out(outputFile.c_str(), std::ifstream::out);
214 out << G_codecMsg.asXMLString();
217 anyHexConverted = true;
222 // Processing .xml files:
223 bool anyXmlConverted = false;
225 for (anna::io::Directory::const_iterator it = directoryXml.begin(); it != directoryXml.end(); it++) {
226 const std::string& entry = anna::io::Directory::data (it);
227 LOGDEBUG(anna::Logger::debug(entry + " is being converted to hex", ANNA_FILE_LOCATION));
230 G_codecMsg.loadXMLFile(entry);
233 std::string hexString = anna::functions::asHexString(G_codecMsg.code());
234 std::string outputFile = entry + ".as.hex";
235 std::ofstream out(outputFile.c_str(), std::ifstream::out);
236 out.write(hexString.c_str(), hexString.size());
239 anyXmlConverted = true;
244 std::string msg = "Open '"; msg += filetrace; msg += "' in order to see process traces.\n";
245 if (anyHexConverted) msg += "Open '*.hex.as.xml' files to see decoding results.\n";
246 if (anyXmlConverted) msg += "Open '*.xml.as.hex' files to see encoding results.\n";