8d8a97d14ef110eb47b2d21e5ca599ca1b6ce529
[anna.git] / example / diameter / launcher / EventOperation.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 // Standard
10 #include <string>
11
12 // Process
13 #include <EventOperation.hpp>
14 #include <Launcher.hpp>
15
16 // Project
17 #include <anna/diameter.comm/OriginHost.hpp>
18
19
20 //// Standard
21 //#include <sstream>      // std::istringstream
22 //#include <iostream>     // std::cout
23 #include <fstream>
24 //#include <math.h> // ceil
25 //#include <climits>
26 #include <unistd.h> // chdir
27 //#include <stdio.h>
28 //
29 //// Project
30 #include <anna/json/functions.hpp>
31 #include <anna/diameter/codec/Message.hpp>
32 //#include <anna/timex/Engine.hpp>
33 //#include <anna/statistics/Engine.hpp>
34 //#include <anna/diameter/codec/functions.hpp>
35 //#include <anna/diameter/codec/Engine.hpp>
36 //#include <anna/diameter/codec/EngineManager.hpp>
37 //#include <anna/http/Transport.hpp>
38 //#include <anna/diameter/stack/Engine.hpp>
39 #include <anna/diameter/helpers/base/functions.hpp>
40 #include <anna/time/functions.hpp>
41 #include <anna/core/functions.hpp>
42 //#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
43 //#include <anna/testing/defines.hpp>
44 #include <anna/xml/xml.hpp>
45 //#include <anna/diameter.comm/OriginHost.hpp>
46 //#include <anna/diameter.comm/OriginHostManager.hpp>
47 #include <anna/diameter.comm/Message.hpp>
48 //
49 //// Process
50 //#include <Launcher.hpp>
51 //#include <Procedure.hpp>
52 //#include <EventOperation.hpp>
53 #include <MyDiameterEngine.hpp>
54 #include <MyLocalServer.hpp>
55 #include <anna/testing/TestManager.hpp>
56 //#include <anna/testing/TestCase.hpp>
57
58
59 /////////////////////
60 // Node management //
61 /////////////////////
62 bool EventOperation::node(std::string &response, const std::string & name) {
63
64   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
65
66   anna::diameter::comm::OriginHost *workingNode;
67   try { workingNode = my_app.getWorkingNode(); } catch(anna::RuntimeException &ex) { ex.trace(); }
68
69   if (name != "") {
70     if (my_app.setWorkingNode(name)) {
71       response = anna::functions::asString("Forced node is now '%s'", name.c_str());
72       my_app.setOperatedHost(my_app.getWorkingNode()); // now is the new one
73     }
74     else {
75       response = anna::functions::asString("Node '%s' invalid. Nothing done", name.c_str());
76     }
77   }
78   else {
79     if (workingNode) {
80       if (a_http) {
81         response = anna::functions::encodeBase64(workingNode->asXMLString());
82       }
83       else {
84         response = workingNode->asXMLString();
85       }
86     }
87     else {
88       response = "Working node is automatic";
89     }
90   }
91   return true; // OK
92 }
93
94 bool EventOperation::node_auto(std::string &response) {
95
96   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
97
98   my_app.setNodeAuto();
99   response = "Working node has been set to automatic";
100
101   return true; // OK
102 }
103
104 ////////////////////////
105 // Parsing operations //
106 ////////////////////////
107 bool EventOperation::code(std::string &response, const std::string & diameterJson) {
108
109   bool success;
110   std::string diameterXml = anna::json::functions::json2xml(diameterJson, success);
111   if (!success) {
112     response += "json to xml failed, unable to encode !";
113     return false;
114   }
115   anna::diameter::codec::Message codecMsg; // auxiliary codec message
116   codecMsg.loadXMLString(diameterXml);
117   response = anna::functions::asHexString(codecMsg.code());
118
119   return true; // OK
120 }
121
122 bool EventOperation::decode(std::string &response, const std::string & diameterHex) {
123
124   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
125
126   anna::DataBlock db_aux(true);
127   anna::functions::fromHexString(diameterHex, db_aux);
128   anna::diameter::codec::Message codecMsg; // auxiliary codec message
129   try {
130     codecMsg.decode(db_aux);
131     std::string xmlString = codecMsg.asXMLString();
132     response = anna::functions::encodeBase64(xmlString);
133   }
134   catch(anna::RuntimeException &ex) { ex.trace(); }
135
136   return true; // OK
137 }
138
139 bool EventOperation::loadmsg(std::string &response, const std::string & diameterJson) {
140
141   bool success;
142   std::string diameterXml = anna::json::functions::json2xml(diameterJson, success);
143   if (!success) {
144     response += "json to xml failed, unable to load message !";
145     return false;
146   }
147   anna::diameter::codec::Message codecMsg; // auxiliary codec message
148   codecMsg.loadXMLString(diameterXml);
149   response = anna::functions::encodeBase64(codecMsg.asXMLString());
150
151   return true; // OK
152 }
153
154 /////////////////
155 // Hot changes //
156 /////////////////
157 bool EventOperation::services(std::string &response, const std::string & servicesJson) {
158
159   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
160
161   bool success;
162   std::string servicesXml = anna::json::functions::json2xml(servicesJson, success);
163   if (!success) {
164     response += "json to xml failed, unable to load services !";
165     return false;
166   }
167
168   try {
169     my_app.loadServicesFromXMLString(servicesXml, true /* bind entities */);
170   }
171   catch(anna::RuntimeException &ex) {
172     ex.trace();
173     response += "loaded services with errors";
174     return false;
175   }
176   response = "loaded services correctly";
177
178   return true; // OK
179 }
180
181 bool EventOperation::diameterServerSessions(std::string &response, int sessions) {
182
183   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
184
185   try {
186     my_app.getOperatedServer()->setMaxConnections(sessions);
187   }
188   catch(anna::RuntimeException &ex) {
189     ex.trace();
190     response += "fail to operate the server";
191     return false;
192   }
193   response = "new sessions successfully established on operated diameter server";
194
195   return true; // OK
196 }
197
198 bool EventOperation::change_dir(std::string &response, const std::string & directory) {
199
200   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
201
202   std::string dir = directory;
203   if (dir == "") dir = my_app.getInitialWorkingDirectory();
204   bool result = (chdir(dir.c_str()) == 0);
205
206   if (result)
207     response = "New execution directory configured: ";
208   else
209     response = "Cannot assign provided execution directory: ";
210
211   response += dir;
212   return result;
213 }
214
215 ////////////////////////////////
216 // Client sessions visibility //
217 ////////////////////////////////
218 bool EventOperation::visibility(std::string &response, const std::string & action, const std::string &addressPort, int socket) {
219
220   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
221
222   response = "";
223
224   if(addressPort != "") {
225     if(socket != -1) {
226       std::string key = addressPort;
227       key += "|";
228       key += anna::functions::asString(socket);
229
230       if(action == "hide") my_app.getOperatedEngine()->findClientSession(key)->hide();
231       if(action == "show") my_app.getOperatedEngine()->findClientSession(key)->show();
232       if(action == "hidden") response = my_app.getOperatedEngine()->findClientSession(key)->hidden() ? "true" : "false";
233       if(action == "shown") response = my_app.getOperatedEngine()->findClientSession(key)->shown() ? "true" : "false";
234     } else {
235       std::string address;
236       int port;
237       anna::functions::getAddressAndPortFromSocketLiteral(addressPort, address, port);
238
239       if(action == "hide") my_app.getOperatedEngine()->findServer(address, port)->hide();
240       if(action == "show") my_app.getOperatedEngine()->findServer(address, port)->show();
241       if(action == "hidden") response = my_app.getOperatedEngine()->findServer(address, port)->hidden() ? "true" : "false";
242       if(action == "shown") response = my_app.getOperatedEngine()->findServer(address, port)->shown() ? "true" : "false";
243     }
244   } else {
245     if(action == "hide") my_app.getOperatedEntity()->hide();
246     if(action == "show") my_app.getOperatedEntity()->show();
247     if(action == "hidden") response = my_app.getOperatedEntity()->hidden() ? "true" : "false";
248     if(action == "shown") response = my_app.getOperatedEntity()->shown() ? "true" : "false";
249   }
250
251   return true; // OK
252 }
253
254
255 ///////////////
256 // Snapshots //
257 ///////////////
258 bool EventOperation::collect(std::string &response) {
259
260   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
261
262   my_app.resetCounters();
263   my_app.resetStatistics();
264   response = "All process counters & statistic information have been reset";
265
266   return true; // OK
267 }
268
269 bool EventOperation::context(std::string &response, const std::string & targetFile) {
270
271   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
272
273   std::string contextFile = (targetFile != "") ? targetFile : anna::functions::asString("/var/tmp/anna.context.%05d", my_app.getPid());
274   my_app.writeContext(contextFile);
275   response = anna::functions::asString("Context dumped on file '%s'", contextFile.c_str());
276
277   return true; // OK
278 }
279
280 bool EventOperation::forceCountersRecord(std::string &response) {
281
282   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
283
284   my_app.forceCountersRecord();
285   response = "Current counters have been dump to disk";
286
287   return true; // OK
288 }
289
290 bool EventOperation::log_statistics_samples(std::string &response, const std::string & list) {
291
292   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
293
294   my_app.logStatisticsSamples(list);
295   response = anna::functions::asString("Log statistics samples for '%s' concepts", list.c_str());
296
297   return true; // OK
298 }
299
300 bool EventOperation::show_oam(std::string &response) {
301
302   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
303
304   anna::xml::Node root("root");
305   response = anna::xml::Compiler().apply(my_app.oamAsXML(&root));
306   if (a_http)
307      response = anna::functions::encodeBase64(response);
308
309   return true; // OK
310 }
311
312 bool EventOperation::show_stats(std::string &response) {
313
314   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
315
316   anna::xml::Node root("root");
317   response = anna::xml::Compiler().apply(my_app.statsAsXML(&root));
318   if (a_http)
319      response = anna::functions::encodeBase64(response);
320
321   return true; // OK
322 }
323
324 /////////////////////
325 // Flow operations //
326 /////////////////////
327 bool EventOperation::sendmsg_hex_2e(std::string &response, const std::string & diameterJson_or_Hex, bool msg_or_hex) {
328
329   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
330   anna::diameter::codec::Message codecMsg; // auxiliary codec message
331   bool success;
332   anna::diameter::comm::Message *msg;
333
334   if(msg_or_hex) {
335     std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_Hex, success);
336     if (!success) {
337       response += "json to xml failed, unable to send message !";
338       return false;
339     }
340     codecMsg.loadXMLString(diameterXml);
341     try {
342       my_app.updateOperatedOriginHostWithMessage(codecMsg);
343       msg = my_app.getOperatedHost()->createCommMessage();
344       msg->clearBody();
345     }
346     catch(anna::RuntimeException &ex) {
347       ex.trace();
348       response += "invalid operated host";
349       return false;
350     }
351     try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
352     msg->setBody(codecMsg.code());
353   } else {
354     // Get DataBlock from hex content:
355     anna::DataBlock db_aux(true);
356     std::string hexString = diameterJson_or_Hex;
357     hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
358     LOGDEBUG(
359         std::string msg = "Hex string (remove colons if exists): ";
360     msg += hexString;
361     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
362     );
363     anna::functions::fromHexString(hexString, db_aux); // could launch exception
364     try {
365       my_app.updateOperatedOriginHostWithMessage(db_aux);
366       msg = my_app.getOperatedHost()->createCommMessage();
367     }
368     catch(anna::RuntimeException &ex) {
369       ex.trace();
370       response += "invalid operated host";
371       return false;
372     }
373     msg->setBody(db_aux);
374     try { if(my_app.getOperatedHost()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); }
375   }
376
377   success = my_app.getOperatedEntity()->send(msg);
378   my_app.getOperatedHost()->releaseCommMessage(msg);
379
380   // Detailed log:
381   if(my_app.getOperatedHost()->logEnabled()) {
382     anna::diameter::comm::Server *usedServer = my_app.getOperatedEntity()->getLastUsedResource();
383     anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL;
384     std::string detail = usedClientSession ? usedClientSession->asString() : "<null client session>"; // shouldn't happen
385     my_app.getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail);
386   }
387
388
389   response = "Operation processed"; // could be failed
390   return success;
391 }
392
393 bool EventOperation::sendmsg_hex_2c(std::string &response, const std::string & diameterJson_or_Hex, bool msg_or_hex) {
394
395   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
396   anna::diameter::codec::Message codecMsg; // auxiliary codec message
397   bool success;
398   anna::diameter::comm::Message *msg;
399
400   if(msg_or_hex) {
401     std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_Hex, success);
402     if (!success) {
403       response += "json to xml failed, unable to send message !";
404       return false;
405     }
406     codecMsg.loadXMLString(diameterXml);
407     try {
408       my_app.updateOperatedOriginHostWithMessage(codecMsg);
409       msg = my_app.getOperatedHost()->createCommMessage();
410       msg->clearBody();
411     }
412     catch(anna::RuntimeException &ex) {
413       ex.trace();
414       response += "invalid operated host";
415       return false;
416     }
417     try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); }  // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher)
418     msg->setBody(codecMsg.code());
419   } else {
420     // Get DataBlock from hex content:
421     anna::DataBlock db_aux(true);
422     std::string hexString = diameterJson_or_Hex;
423     hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
424     LOGDEBUG(
425         std::string msg = "Hex string (remove colons if exists): ";
426     msg += hexString;
427     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
428     );
429     anna::functions::fromHexString(hexString, db_aux); // could launch exception
430     try {
431       my_app.updateOperatedOriginHostWithMessage(db_aux);
432       msg = my_app.getOperatedHost()->createCommMessage();
433     }
434     catch(anna::RuntimeException &ex) {
435       ex.trace();
436       response += "invalid operated host";
437       return false;
438     }
439     msg->setBody(db_aux);
440     try { if(my_app.getOperatedHost()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); }
441   }
442
443   success = my_app.getOperatedServer()->send(msg);
444   my_app.getOperatedHost()->releaseCommMessage(msg);
445
446   // Detailed log:
447   if(my_app.getOperatedHost()->logEnabled()) {
448     anna::diameter::comm::ServerSession *usedServerSession = my_app.getOperatedServer()->getLastUsedResource();
449     std::string detail = usedServerSession ? usedServerSession->asString() : "<null server session>"; // shouldn't happen
450     my_app.getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail);
451   }
452
453
454   response = "Operation processed"; // could be failed
455   return success;
456 }
457
458 bool EventOperation::answermsg_action_2e(std::string &response, const std::string & diameterJson_or_action, bool msg_or_action) {
459
460   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
461   anna::diameter::codec::Message codecMsg; // auxiliary codec message
462   anna::diameter::codec::Message *message;
463   bool success;
464
465   if (msg_or_action) {
466
467     std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_action, success);
468     if (!success) {
469       response += "json to xml failed, unable to send message !";
470       return false;
471     }
472     codecMsg.loadXMLString(diameterXml);
473     try {
474       my_app.updateOperatedOriginHostWithMessage(codecMsg);
475       message = my_app.getOperatedHost()->getCodecEngine()->createMessage(diameterXml, false /* is xml string */); // loads xml again, lesser of two evils
476       LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
477     }
478     catch(anna::RuntimeException &ex) {
479       ex.trace();
480       response += "invalid operated host";
481       return false;
482     }
483
484     if(message->isRequest()) {
485       response += "cannot program diameter requests. Answer type must be provided";
486       return false;
487     }
488
489     int code = message->getId().first;
490     LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
491     response = "Added 'answer to entity' to the FIFO queue corresponding to its message code";
492     my_app.getOperatedEntity()->getReactingAnswers()->addMessage(code, message);
493   }
494   else { // action
495
496     if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout
497       response = anna::functions::encodeBase64(my_app.getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"));
498     } else if (diameterJson_or_action == "rotate") {
499       my_app.getOperatedEntity()->getReactingAnswers()->rotate(true);
500       response = "rotate";
501     } else if (diameterJson_or_action == "exhaust") {
502       my_app.getOperatedEntity()->getReactingAnswers()->rotate(false);
503       response = "exhaust";
504     } else if (diameterJson_or_action == "clear") {
505       my_app.getOperatedEntity()->getReactingAnswers()->clear();
506       response = "clear";
507     } else if (diameterJson_or_action == "dump") {
508       my_app.getOperatedEntity()->getReactingAnswers()->dump("programmed_answer");
509       response = "dump";
510     }
511   }
512
513
514   return true; // OK
515 }
516
517 bool EventOperation::answermsg_action_2c(std::string &response, const std::string & diameterJson_or_action, bool msg_or_action) {
518
519   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
520   anna::diameter::codec::Message codecMsg; // auxiliary codec message
521   anna::diameter::codec::Message *message;
522   bool success;
523
524   if (msg_or_action) {
525
526     std::string diameterXml = anna::json::functions::json2xml(diameterJson_or_action, success);
527     if (!success) {
528       response += "json to xml failed, unable to send message !";
529       return false;
530     }
531     codecMsg.loadXMLString(diameterXml);
532     try {
533       my_app.updateOperatedOriginHostWithMessage(codecMsg);
534       message = my_app.getOperatedHost()->getCodecEngine()->createMessage(diameterXml, false /* is xml string */); // loads xml again, lesser of two evils
535       LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION));
536     }
537     catch(anna::RuntimeException &ex) {
538       ex.trace();
539       response += "invalid operated host";
540       return false;
541     }
542
543     if(message->isRequest()) {
544       response += "cannot program diameter requests. Answer type must be provided";
545       return false;
546     }
547
548     int code = message->getId().first;
549     LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION));
550     my_app.getOperatedServer()->getReactingAnswers()->addMessage(code, message);
551     response = "Added 'answer to client' to the FIFO queue corresponding to its message code";
552   }
553   else { // action
554
555     if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout
556       response = anna::functions::encodeBase64(my_app.getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"));
557     } else if (diameterJson_or_action == "rotate") {
558       my_app.getOperatedServer()->getReactingAnswers()->rotate(true);
559       response = "rotate";
560     } else if (diameterJson_or_action == "exhaust") {
561       my_app.getOperatedServer()->getReactingAnswers()->rotate(false);
562       response = "exhaust";
563     } else if (diameterJson_or_action == "clear") {
564       my_app.getOperatedServer()->getReactingAnswers()->clear();
565       response = "clear";
566     } else if (diameterJson_or_action == "dump") {
567       my_app.getOperatedServer()->getReactingAnswers()->dump("programmed_answer");
568       response = "dump";
569     }
570   }
571
572
573   return true; // OK
574 }
575
576 /////////////////
577 // FSM testing //
578 /////////////////
579 bool EventOperation::test_id__description(std::string &response, unsigned int id, const std::string & description) {
580
581   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
582   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
583
584   try {
585     testManager.getTestCase(id)->setDescription(description); // creates / reuses
586     response = "Done";
587   }
588   catch(anna::RuntimeException &ex) {
589     ex.trace();
590     response += "invalid ip-limit";
591     return false;
592   }
593
594   return true; // OK
595 }
596
597 bool EventOperation::test_id__ip_limit(std::string &response, unsigned int id, int amount) {
598
599   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
600   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
601
602   try {
603     testManager.getTestCase(id)->addIpLimit(amount); // creates / reuses
604     response = "Done";
605   }
606   catch(anna::RuntimeException &ex) {
607     ex.trace();
608     response += "invalid ip-limit";
609     return false;
610   }
611
612   return true; // OK
613 }
614
615 bool EventOperation::test_id__timeout(std::string &response, unsigned int id, int msecs) {
616
617   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
618   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
619
620   try {
621     anna::Millisecond timeout = my_app.checkTimeMeasure("Test case timeout", anna::functions::asString(msecs));
622     testManager.getTestCase(id)->addTimeout(timeout); // creates / reuses
623     response = "Done";
624   }
625   catch(anna::RuntimeException &ex) {
626     ex.trace();
627     response += "invalid timeout";
628     return false;
629   }
630
631   return true; // OK
632 }
633
634 bool EventOperation::test_id__sendmsg2e_2c(std::string &response, unsigned int id, bool _2e_or_2c, const std::string & diameterJson, int stepNumber) {
635
636   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
637   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
638
639   bool success;
640   std::string diameterXml = anna::json::functions::json2xml(diameterJson, success);
641   if (!success) {
642     response += "json to xml failed, unable to load message !";
643     return false;
644   }
645   anna::diameter::codec::Message codecMsg; // auxiliary codec message
646   codecMsg.loadXMLString(diameterXml);
647
648   LOGWARNING(
649      if (!codecMsg.isRequest() && (stepNumber == -1))
650       anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION);
651   );
652
653   try {
654     my_app.updateOperatedOriginHostWithMessage(codecMsg);
655     if (_2e_or_2c)
656       testManager.getTestCase(id)->addSendDiameterXml2e(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses
657     else
658       testManager.getTestCase(id)->addSendDiameterXml2c(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses
659
660     response = "Done";
661   }
662   catch(anna::RuntimeException &ex) {
663     ex.trace();
664     response += "failed";
665     return false;
666   }
667
668   return true; // OK
669 }
670
671 bool EventOperation::test_id__delay(std::string &response, unsigned int id, int msecs) {
672
673   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
674   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
675
676   try {
677     anna::Millisecond delay = ((msecs == 0 /* special case */) ? (anna::Millisecond)0 : my_app.checkTimeMeasure("Test case delay step", anna::functions::asString(msecs)));
678     testManager.getTestCase(id)->addDelay(delay); // creates / reuses
679     response = "Done";
680   }
681   catch(anna::RuntimeException &ex) {
682     ex.trace();
683     response += "invalid delay";
684     return false;
685   }
686
687   return true; // OK
688 }
689
690 bool EventOperation::test_id__sh_command(std::string &response, unsigned int id, const std::string & script) {
691
692   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
693   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
694
695   try {
696     testManager.getTestCase(id)->addCommand(script); // creates / reuses
697     response = "Done";
698   }
699   catch(anna::RuntimeException &ex) {
700     ex.trace();
701     response += "failed";
702     return false;
703   }
704
705   return true; // OK
706 }
707
708 bool EventOperation::test_id__waitfefc_hex(std::string &response, unsigned int id, bool fe_or_fc, const std::string & hex, bool strict) {
709
710   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
711   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
712
713   // Get DataBlock from hex content:
714   anna::DataBlock db_aux(true);
715   std::string hexString = hex;
716   hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end());
717   LOGDEBUG(
718       std::string msg = "Hex string (remove colons if exists): ";
719   msg += hexString;
720   anna::Logger::debug(msg, ANNA_FILE_LOCATION);
721   );
722
723   std::string regexp;
724   try {
725     anna::functions::fromHexString(hexString, db_aux); // could launch exception
726     regexp = anna::functions::asHexString(db_aux);
727   }
728   catch(anna::RuntimeException &ex) {
729     ex.trace();
730     response += "failed";
731     return false;
732   }
733
734   // optional 'full':
735   if(!strict) {
736     //// If request, we will ignore sequence data:
737     //if (anna::diameter::codec::functions::requestBit(db_aux))
738     regexp.replace (24, 16, "[0-9A-Fa-f]{16}");
739
740     regexp.insert(0, "^");
741     regexp += "$";
742   }
743
744   try {
745     testManager.getTestCase(id)->addWaitDiameterRegexpHex(fe_or_fc, regexp);
746     response = "Done";
747   }
748   catch(anna::RuntimeException &ex) {
749     ex.trace();
750     response += "failed";
751     return false;
752   }
753
754   return true; // OK
755 }
756
757 bool EventOperation::test_id__waitfefc_msg(std::string &response, unsigned int id, bool fe_or_fc, const std::string & diameterJson, bool strict) {
758
759   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
760   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
761
762   bool success;
763   std::string diameterXml = anna::json::functions::json2xml(diameterJson, success);
764   if (!success) {
765     response += "json to xml failed, unable to load message !";
766     return false;
767   }
768
769   try {
770     anna::diameter::codec::Message codecMsg; // auxiliary codec message
771     codecMsg.loadXMLString(diameterXml);
772     std::string regexp = codecMsg.asXMLString(true /* normalization */);
773
774     // Now we must insert regular expressions in hop-by-hop, end-to-end and Origin-State-Id:
775
776     // optional 'full':
777     if(!strict) {
778       std::string::size_type pos, pos_1, pos_2;
779
780       pos = regexp.find("end-to-end-id=", 0u);
781       pos = regexp.find("\"", pos);
782       pos_1 = pos;
783       pos = regexp.find("\"", pos+1);
784       pos_2 = pos;
785       regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
786
787       pos = regexp.find("hop-by-hop-id=", 0u);
788       pos = regexp.find("\"", pos);
789       pos_1 = pos;
790       pos = regexp.find("\"", pos+1);
791       pos_2 = pos;
792       regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
793
794       // For this representation: <avp name="Origin-State-Id" data="1428633668"/>
795       //pos = regexp.find("Origin-State-Id", 0u);
796       //pos = regexp.find("\"", pos);
797       //pos = regexp.find("\"", pos+1);
798       //pos_1 = pos;
799       //pos = regexp.find("\"", pos+1);
800       //pos_2 = pos;
801       //regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
802       // But we have this one: <avp data="1428633668" name="Origin-State-Id"/>
803       pos = regexp.find("Origin-State-Id", 0u);
804       pos = regexp.rfind("\"", pos);
805       pos = regexp.rfind("\"", pos-1);
806       pos = regexp.rfind("\"", pos-1);
807       pos_1 = pos;
808       pos = regexp.find("\"", pos+1);
809       pos_2 = pos;
810       regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+");
811
812       //regexp.insert(0, "^");
813       //regexp += "$";
814     }
815
816     testManager.getTestCase(id)->addWaitDiameterRegexpXml(fe_or_fc, regexp);
817     response = "Done";
818   }
819   catch(anna::RuntimeException &ex) {
820     ex.trace();
821     response += "failed";
822     return false;
823   }
824
825   return true; // OK
826 }
827
828 bool EventOperation::test_id__waitfefc(std::string &response, unsigned int id, bool fe_or_fc,
829                          const std::string & code,
830                          const std::string & bitR,
831                          const std::string & hopByHop,
832                          const std::string & applicationId,
833                          const std::string & sessionId,
834                          const std::string & resultCode,
835                          const std::string & msisdn,
836                          const std::string & imsi,
837                          const std::string & serviceContextId) {
838
839   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
840   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
841
842   try { // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
843     testManager.getTestCase(id)->addWaitDiameter(fe_or_fc, code, bitR, hopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId);
844     response = "Done";
845   }
846   catch(anna::RuntimeException &ex) {
847     ex.trace();
848     response += "failed";
849     return false;
850   }
851
852   return true; // OK
853 }
854
855 /////////////////////////
856 // Testcases execution //
857 /////////////////////////
858 bool EventOperation::test__ttps(std::string &response, int amount) {
859
860   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
861   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
862
863   bool success = testManager.configureTTPS(amount);
864   if (success) {
865     response = "Assigned new test launch rate to ";
866     response += anna::functions::asString(amount);
867     response += " events per second";
868   }
869   else {
870     response += "unable to configure the test rate provided";
871   }
872
873   return success; // OK
874 }
875
876 bool EventOperation::test__next(std::string &response, int syncAmount) {
877
878   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
879   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
880
881   if (syncAmount < 1) {
882     response += "the parameter 'sync-amount' must be a positive integer value";
883     return false;
884   }
885
886   bool success = testManager.execTestCases(syncAmount);
887
888   response = (success ? "P" : "Not completely p" /* completed cycle and no repeats, rare case */);
889   response += "rocessed ";
890   response += anna::functions::asString(syncAmount);
891   response += ((syncAmount > 1) ? " test cases synchronously" : " test case");
892
893   return success;
894 }
895
896 bool EventOperation::test__ip_limit(std::string &response, int amount) {
897
898   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
899   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
900
901   if (amount > -2) {
902     testManager.setInProgressLimit(amount);
903     response = "New in-progress limit: ";
904     response += (amount != -1) ? anna::functions::asString(amount) : "<no limit>";
905   }
906   else {
907     response = "In-progress limit amount: ";
908     int limit = testManager.getInProgressLimit();
909     response += (limit != -1) ? anna::functions::asString(limit) : "<no limit>";
910     response += "; currently there are ";
911     response += anna::functions::asString(testManager.getInProgressCount());
912     response += " test cases running";
913   }
914
915   return true; // OK
916 }
917
918 bool EventOperation::test__goto(std::string &response, int id) {
919
920   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
921   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
922
923   bool success = testManager.gotoTestCase(id);
924
925   if (success) {
926     response = "Position updated for id provided (";
927   }
928   else {
929     response += "cannot found test id (";
930   }
931   response += anna::functions::asString(id);
932   response += ")";
933
934   return success;
935 }
936
937 bool EventOperation::test__run(std::string &response, int id) {
938
939   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
940   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
941
942   bool success = testManager.runTestCase(id);
943
944   if (success) {
945     response = "Test executed for id provided (";
946   }
947   else {
948     response += "cannot found test id (";
949   }
950   response += anna::functions::asString(id);
951   response += ")";
952
953   return success;
954 }
955
956 bool EventOperation::test__look(std::string &response, int id) {
957
958   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
959   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
960
961   anna::testing::TestCase *testCase = testManager.findTestCase(id);
962   if (!testCase) {
963     if (id == -1) {
964        response += "no current test case detected (testing started ?)";
965     }
966     else {
967       response += "cannot found test id (";
968       response += anna::functions::asString(id);
969       response += ")";
970     }
971
972     return false;
973   }
974
975   if (a_http)
976     response = anna::functions::encodeBase64(testCase->asXMLString());
977   else
978     response = testCase->asXMLString();
979
980   return true; // OK
981 }
982
983 bool EventOperation::test__state(std::string &response, int id) {
984
985   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
986   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
987
988   anna::testing::TestCase *testCase = testManager.findTestCase(id);
989   if (!testCase) {
990     if (id == -1) {
991        response += "no current test case detected (testing started ?)";
992     }
993     else {
994       response += "cannot found test id (";
995       response += anna::functions::asString(id);
996       response += ")";
997     }
998
999     return false;
1000   }
1001
1002   response = anna::testing::TestCase::asText(testCase->getState());
1003   return testCase->isSuccess();
1004 }
1005
1006 bool EventOperation::test__interact(std::string &response, int amount, unsigned int id) {
1007
1008   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1009   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1010
1011   if (amount < -1) {
1012     response += "interactive amount must be -1 (to disable interactive mode) or a positive number.";
1013     return false;
1014   }
1015
1016   anna::testing::TestCase *testCase = testManager.findTestCase(id);
1017   if (testCase) {
1018     if (amount == -1) {
1019       testCase->makeInteractive(false);
1020       response = "Interactive mode disabled";
1021     }
1022     else {
1023       testCase->addInteractiveAmount(amount);
1024       response = "Added interactive amount of ";
1025       response += anna::functions::asString(amount);
1026       response += " units";
1027       if (amount == 0) response += " (0: freezing a non-interactive testcase, no effect on already interactive)";
1028     }
1029     response += " for test case id ";
1030     response += anna::functions::asString(id);
1031   }
1032   else {
1033     response += "cannot found test id (";
1034     response += anna::functions::asString(id);
1035     response += ")";
1036     return false;
1037   }
1038
1039   return true; // OK
1040 }
1041
1042 bool EventOperation::test__reset(std::string &response, bool soft_hard, int id) {
1043
1044   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1045   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1046
1047   anna::testing::TestCase *testCase = ((id != -1) ? testManager.findTestCase(id) : NULL);
1048   if (testCase) {
1049     bool done = testCase->reset(!soft_hard);
1050     response = "Test ";
1051     response += (soft_hard ? "soft":"hard");
1052     response += " reset for id ";
1053     response += anna::functions::asString(id);
1054     response += done ? ": done": ": not done";
1055   }
1056   else {
1057     if (id == -1) {
1058       bool anyReset = testManager.resetPool(!soft_hard);
1059       response = (soft_hard ? "Soft":"Hard");
1060       response += " reset have been sent to all programmed tests: "; response += anyReset ? "some/all have been reset" : "nothing was reset";
1061     }
1062     else {
1063       response += "cannot found test id (";
1064       response += anna::functions::asString(id);
1065       response += ")";
1066       return false;
1067     }
1068   }
1069
1070   return true; // OK
1071 }
1072
1073 bool EventOperation::test__repeats(std::string &response, int amount) {
1074
1075   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1076   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1077
1078   if (amount < 0) amount = -1;
1079   testManager.setPoolRepeats(amount);
1080   std::string nolimit = (amount != -1) ? "":" [no limit]";
1081   response = anna::functions::asString("Pool repeats: %d%s (current cycle: %d)", amount, nolimit.c_str(), testManager.getPoolCycle());
1082
1083   return true; // OK
1084 }
1085
1086 bool EventOperation::test__auto_reset(std::string &response, bool soft_hard) {
1087
1088   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1089   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1090
1091   testManager.setAutoResetHard(!soft_hard);
1092   response = anna::functions::asString("Auto-reset configured to '%s'", (soft_hard ? "soft":"hard"));
1093
1094   return true; // OK
1095 }
1096
1097 bool EventOperation::test__initialized(std::string &response) {
1098
1099   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1100   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1101
1102   response = anna::functions::asString("%lu", testManager.getInitializedCount());
1103
1104   return true; // OK
1105 }
1106
1107 bool EventOperation::test__finished(std::string &response) {
1108
1109   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1110   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1111
1112   response = anna::functions::asString("%lu", testManager.getFinishedCount());
1113
1114   return true; // OK
1115 }
1116
1117 bool EventOperation::test__clear(std::string &response) {
1118
1119   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1120   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1121
1122   return testManager.clearPool(response);
1123 }
1124
1125 bool EventOperation::test__junit(std::string &response, const std::string & targetFile) {
1126
1127   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1128   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1129
1130   std::ofstream out;
1131   out.open(targetFile.c_str());
1132
1133   if(out.is_open() == false) {
1134     response += "error opening '";
1135     response += targetFile;
1136     response += "'";
1137     return false;
1138   }
1139
1140   out << testManager.junitAsXMLString() << std::endl;
1141   out.close();
1142
1143   response = "Junit report written on '";
1144   response += targetFile;
1145   response += "'";
1146
1147   return true; // OK
1148 }
1149
1150 bool EventOperation::test__summary_counts(std::string &response) {
1151
1152   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1153   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1154
1155   response = anna::functions::encodeBase64(testManager.summaryCounts());
1156
1157   return true; // OK
1158 }
1159
1160 bool EventOperation::test__summary_states(std::string &response) {
1161
1162   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1163   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1164
1165   response = anna::functions::encodeBase64(testManager.summaryStates());
1166
1167   return true; // OK
1168 }
1169
1170 bool EventOperation::test__summary(std::string &response) {
1171
1172   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1173   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1174
1175   response = anna::functions::encodeBase64(testManager.asXMLString());
1176
1177   return true; // OK
1178 }
1179
1180 bool EventOperation::test__report(std::string &response, const std::string & state, bool enable) {
1181
1182   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1183   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1184
1185   std::string _state = state;
1186
1187   if(_state == "initialized")
1188     testManager.setDumpInitializedReports(enable);
1189   else if(_state == "in-progress")
1190     testManager.setDumpInProgressReports(enable);
1191   else if(_state == "failed")
1192     testManager.setDumpFailedReports(enable);
1193   else if(_state == "success")
1194     testManager.setDumpSuccessReports(enable);
1195   else if(_state == "all") {
1196     _state = "any";
1197     testManager.setDumpAllReports(enable);
1198   }
1199   else if(_state == "none") {
1200     enable = !enable;
1201     _state = "any";
1202     testManager.setDumpAllReports(enable);
1203   }
1204   else {
1205     response += "invalid state (allowed: initialized|in-progress|failed|success|[all]|none)";
1206     return false;
1207   }
1208
1209   response = (enable ? "Report enabled " : "Report disabled ");
1210   response += "for tests in '";
1211   response += _state;
1212   response += "' state";
1213
1214   return true; // OK
1215 }
1216
1217 bool EventOperation::test__report_hex(std::string &response, bool enable) {
1218
1219   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1220   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1221
1222   testManager.setDumpHex(enable);
1223   response = (testManager.getDumpHex() ? "Report includes hexadecimal messages" : "Report excludes hexadecimal messages");
1224
1225   return true; // OK
1226 }
1227
1228 bool EventOperation::test__dump_stdout(std::string &response, bool enable) {
1229
1230   Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
1231   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
1232
1233   testManager.setDumpStdout(enable);
1234   response = (testManager.getDumpStdout() ? "Test manager dumps progress into stdout" : "Test manager does not dump progress into stdout");
1235
1236   return true; // OK
1237 }
1238