1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
44 #include <anna/core/DataBlock.hpp>
45 #include <anna/core/util/Tokenizer.hpp>
46 #include <anna/core/functions.hpp>
47 #include <anna/core/tracing/Logger.hpp>
48 #include <anna/core/tracing/TraceWriter.hpp>
49 #include <anna/core/RuntimeException.hpp>
50 #include <anna/io/Directory.hpp>
51 #include <anna/xml/xml.hpp>
52 #include <anna/diameter/stack/Engine.hpp>
53 #include <anna/diameter/codec/Engine.hpp>
54 #include <anna/diameter/codec/Message.hpp>
55 //#include <anna/diameter/codec/functions.hpp> // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
59 using namespace anna::diameter;
61 anna::diameter::codec::Message *G_codecMsg;
62 anna::diameter::codec::Engine *G_codecEngine;
64 bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) throw() {
66 static char buffer[8192];
67 std::ifstream infile(pathfile.c_str(), std::ifstream::in);
69 if(infile.is_open()) {
71 std::string hexString(buffer, strlen(buffer));
72 // Allow colon separator in hex string: we have to remove them before processing with 'fromHexString':
73 hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
75 std::string msg = "Hex string (remove colons if exists): ";
77 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
79 anna::functions::fromHexString(hexString, db);
89 void _exit(const std::string &message, int resultCode = 1) {
91 std::cerr << message << std::endl << std::endl;
93 std::cout << message << std::endl << std::endl;
98 // Decodes a diameter message coming from a datablock
99 void decodeDataBlock(const anna::DataBlock &db/*, unsigned int & detectedApplicationId*/) throw() {
101 //detectedApplicationId = anna::diameter::codec::functions::getApplicationId(db);
102 //G_codecEngine->setDictionary(detectedApplicationId); we enabled this feature in the codec engine: selectStackWithApplicationId(true);
103 G_codecMsg->decode(db);
104 } catch(RuntimeException &ex) {
105 _exit(ex.asString());
109 //-------------------------------------------------------------------
110 int main(int argc, char **argv) {
111 std::string exec = argv[0];
112 std::string execBN = exec.substr(exec.find_last_of("/") + 1);
113 std::string filetrace = execBN + ".trace";
114 std::cout << std::endl;
116 //check command line arguments
118 std::string msg = "Usage: "; msg += exec;
119 msg += " <stacks> <working directory> [--hex-only] [--xml-only] [--no-validation] [--ignore-flags] [--debug]\n\n";
120 msg += " stacks: <id1,dictionary1#id2,dictionary2#...#idN,dictionaryN>\n";
121 msg += " This is a list of #-separated stacks defined by a comma-separated pair <application-id,xml dictionary pathfile>\n";
122 msg += " If only one stack is provided, application-id could be omitted and then, all the messages will be decoded with the\n";
123 msg += " dictionary regardless the value of the application-id (the stack will be registered with id=0).\n";
124 msg += " Working directory: Contains 'xml files' (ANNA-Diameter message format) and/or 'hex files' (hexadecimal content, colons allowed).\n";
125 msg += " --hex-only: Only hex files are converted.\n";
126 msg += " --xml-only: Only xml files are converted.\n";
127 msg += " --no-validation: no validation is performed.\n";
128 msg += " --ignore-flags: wrong flags regarding dictionary are ignored in xml representation.\n";
129 msg += " --debug: activates debug level traces (warning by default).\n";
131 msg += " The batch process will translate '.xml' files into '.xml.as.hex', and '.hex' files into '.hex.as.xml'\n";
132 msg += " Take care not to include the dictionary files (which have '.xml' extension) in the working directory, or there will be an exception.\n";
136 // Command-line parameters:
137 std::string stacks = argv[1];
138 std::string wkDir = argv[2];
139 std::string optionals;
141 while(indx < argc) { optionals += " "; optionals += argv[indx]; indx++; }
143 bool no_validation = (optionals.find("--no-validation") != std::string::npos);
144 bool ignore_flags = (optionals.find("--ignore-flags") != std::string::npos);
145 bool debug = (optionals.find("--debug") != std::string::npos);
146 bool hexOnly = (optionals.find("--hex-only") != std::string::npos);
147 bool xmlOnly = (optionals.find("--xml-only") != std::string::npos);
148 if (hexOnly && xmlOnly) _exit("Cannot provide both '--hex-only' and '--xml-only' !!");
149 bool processXml = hexOnly ? false:true;
150 bool processHex = xmlOnly ? false:true;
151 Logger::setLevel(debug ? Logger::Debug:Logger::Warning);
152 Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000));
153 G_codecEngine = new anna::diameter::codec::Engine();
154 G_codecMsg = G_codecEngine->createMessage();
155 anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
158 bool multistack = false;
160 anna::Tokenizer stacksTok;
161 stacksTok.apply(stacks, "#");
162 anna::Tokenizer::const_iterator stacks_it, stack_it;
164 for(stacks_it = stacksTok.begin(); stacks_it != stacksTok.end(); stacks_it++) {
165 std::string stack = anna::Tokenizer::data(stacks_it);
166 anna::Tokenizer stackTok;
167 stackTok.apply(stack, ",");
169 if(stackTok.size() == 1) {
170 if(stacksTok.size() != 1)
171 throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION);
173 anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary
174 G_codecEngine->setDictionary(d);
178 if(stackTok.size() != 2)
179 throw anna::RuntimeException("Each stack must be in the form '<application-id>#<xml dictionary pathfile>'", ANNA_FILE_LOCATION);
182 stack_it = stackTok.begin();
183 unsigned int stackId = atoll(anna::Tokenizer::data(stack_it));
185 std::string file = anna::Tokenizer::data(stack_it);
186 anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file);
189 // Auto stack selection based on Application-ID:
190 if (multistack) G_codecEngine->selectStackWithApplicationId(true);
192 std::cout << "Stacks provided: " << std::endl;
193 std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
194 std::cout << std::endl;
195 std::cout << "Working directory: " << wkDir << std::endl;
196 std::cout << "Validation: " << (!no_validation ? "yes" : "no") << std::endl;
197 std::cout << "Ignore Flags: " << (ignore_flags ? "yes" : "no") << std::endl;
198 std::cout << std::endl;
199 } catch(anna::RuntimeException &ex) {
200 _exit(ex.asString());
203 // Validation kindness
204 G_codecEngine->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire)
205 G_codecEngine->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports
206 if(no_validation) G_codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never);
207 if(ignore_flags) G_codecEngine->ignoreFlagsOnValidation(true);
209 // Auxiliary variables:
210 anna::DataBlock db_aux(true);
211 anna::io::Directory directoryHex, directoryXml; // we separate (although it wouldn't be neccessary using setPattern each time), because we don't
212 // want to process the resulting xml files from hex conversion, only the xml files present at the
213 // beginning in the directory
215 directoryHex.setPattern(".hex$");
216 directoryHex.read(wkDir.c_str(), anna::io::Directory::Mode::FullPath);
217 directoryXml.setPattern(".xml$");
218 directoryXml.read(wkDir.c_str(), anna::io::Directory::Mode::FullPath);
220 // Processing .hex files:
221 bool anyHexConverted = false;
223 for (anna::io::Directory::const_iterator it = directoryHex.begin(); it != directoryHex.end(); it++) {
224 const std::string& entry = anna::io::Directory::data (it);
225 LOGDEBUG(anna::Logger::debug(entry + " is being converted to xml", ANNA_FILE_LOCATION));
227 if(!getDataBlockFromHexFile(entry, db_aux))
228 _exit("Error reading hex file provided");
231 decodeDataBlock(db_aux);
234 std::string outputFile = entry + ".as.xml";
235 std::ofstream out(outputFile.c_str(), std::ifstream::out);
236 out << G_codecMsg->asXMLString();
239 anyHexConverted = true;
243 // Processing .xml files:
244 bool anyXmlConverted = false;
246 for (anna::io::Directory::const_iterator it = directoryXml.begin(); it != directoryXml.end(); it++) {
247 const std::string& entry = anna::io::Directory::data (it);
248 LOGDEBUG(anna::Logger::debug(entry + " is being converted to hex", ANNA_FILE_LOCATION));
251 G_codecMsg->loadXML(entry);
254 std::string hexString = anna::functions::asHexString(G_codecMsg->code());
255 std::string outputFile = entry + ".as.hex";
256 std::ofstream out(outputFile.c_str(), std::ifstream::out);
257 out.write(hexString.c_str(), hexString.size());
260 anyXmlConverted = true;
265 std::string msg = "Open '"; msg += filetrace; msg += "' in order to see process traces.\n";
266 if (anyHexConverted) msg += "Open '*.hex.as.xml' files to see decoding results.\n";
267 if (anyXmlConverted) msg += "Open '*.xml.as.hex' files to see encoding results.\n";