artdaq  v3_01_00
xmlrpc_commander.cc
1 /* DarkSide 50 DAQ program
2  * This file add the xmlrpc commander as a client to the SC
3  * Author: Alessandro Razeto <Alessandro.Razeto@ge.infn.it>
4  */
5 
6 #pragma GCC diagnostic push
7 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
8 #define _LIBCPP_ENABLE_CXX17_REMOVED_FEATURES 1
9 #include <xmlrpc-c/base.hpp>
10 #include <xmlrpc-c/registry.hpp>
11 #include <xmlrpc-c/server_abyss.hpp>
12 #include <xmlrpc-c/girerr.hpp>
13 #include <xmlrpc-c/client_simple.hpp>
14 #undef _LIBCPP_ENABLE_CXX17_REMOVED_FEATURES
15 #pragma GCC diagnostic pop
16 #include <stdexcept>
17 #include <iostream>
18 #include <limits>
19 #include <memory>
20 #include <cstdint>
21 #define TRACE_NAME "xmlrpc_commander"
22 #include "tracemf.h"
23 
24 #include "artdaq-core/Utilities/ExceptionHandler.hh"
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <errno.h>
28 #include <cstring>
29 #include <exception>
30 
31 #include "canvas/Persistency/Provenance/RunID.h"
32 #include "fhiclcpp/make_ParameterSet.h"
33 
34 #include "artdaq/ExternalComms/xmlrpc_commander.hh"
35 #include "artdaq/DAQdata/Globals.hh"
36  //#include "artdaq/Application/LoadParameterSet.hh"
37 
38 namespace {
39  class env_wrap {
40  public:
41  env_wrap() { xmlrpc_env_init(&this->env_c); };
42  ~env_wrap() { xmlrpc_env_clean(&this->env_c); };
43  xmlrpc_env env_c;
44  };
45 } // namespace
46 static xmlrpc_c::paramList
47 pListFromXmlrpcArray(xmlrpc_value * const arrayP)
48 {
49  env_wrap env;
50  XMLRPC_ASSERT_ARRAY_OK(arrayP);
51  unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP);
52  assert(!env.env_c.fault_occurred);
53  xmlrpc_c::paramList paramList(arraySize);
54  for (unsigned int i = 0; i < arraySize; ++i) {
55  xmlrpc_value * arrayItemP;
56  xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP);
57  assert(!env.env_c.fault_occurred);
58  paramList.add(xmlrpc_c::value(arrayItemP));
59  xmlrpc_DECREF(arrayItemP);
60  }
61  return paramList;
62 }
63 static xmlrpc_value *
64 c_executeMethod(xmlrpc_env * const envP,
65  xmlrpc_value * const paramArrayP,
66  void * const methodPtr,
67  void * const callInfoPtr)
68 {
69  xmlrpc_c::method * const methodP(static_cast<xmlrpc_c::method *>(methodPtr));
70  xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP));
71  xmlrpc_c::callInfo * const callInfoP(static_cast<xmlrpc_c::callInfo *>(callInfoPtr));
72  xmlrpc_value * retval;
73  retval = NULL; // silence used-before-set warning
74  try {
75  xmlrpc_c::value result;
76  try {
77  xmlrpc_c::method2 * const method2P(dynamic_cast<xmlrpc_c::method2 *>(methodP));
78  if (method2P)
79  method2P->execute(paramList, callInfoP, &result);
80  else
81  methodP->execute(paramList, &result);
82  }
83  catch (xmlrpc_c::fault const& fault) {
84  xmlrpc_env_set_fault(envP, fault.getCode(),
85  fault.getDescription().c_str());
86  }
87  if (!envP->fault_occurred) {
88  if (result.isInstantiated())
89  retval = result.cValue();
90  else
91  girerr::throwf("Xmlrpc-c user's xmlrpc_c::method object's "
92  "'execute method' failed to set the RPC result "
93  "value.");
94  }
95  }
96  catch (std::exception const& e) {
97  xmlrpc_faultf(envP, "Unexpected error executing code for "
98  "particular method, detected by Xmlrpc-c "
99  "method registry code. Method did not "
100  "fail; rather, it did not complete at all. %s",
101  e.what());
102  }
103  catch (...) {
104  xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
105  "Unexpected error executing code for "
106  "particular method, detected by Xmlrpc-c "
107  "method registry code. Method did not "
108  "fail; rather, it did not complete at all.");
109  }
110  return retval;
111 }
112 
113 
114 
115 namespace artdaq
116 {
123  std::string exception_msg(const std::runtime_error& er,
124  const std::string& helpText = "execute request")
125  {
126  std::string msg("Exception when trying to ");
127  msg.append(helpText);
128  msg.append(": ");
129  msg.append(er.what()); //std::string(er.what ()).substr (2);
130  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
131  return msg;
132  }
133 
140  std::string exception_msg(const art::Exception& er,
141  const std::string& helpText)
142  {
143  std::string msg("Exception when trying to ");
144  msg.append(helpText);
145  msg.append(": ");
146  msg.append(er.what());
147  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
148  return msg;
149  }
150 
157  std::string exception_msg(const cet::exception& er,
158  const std::string& helpText)
159  {
160  std::string msg("Exception when trying to ");
161  msg.append(helpText);
162  msg.append(": ");
163  msg.append(er.what());
164  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
165  return msg;
166  }
167 
174  std::string exception_msg(const std::string& erText,
175  const std::string& helpText)
176  {
177  std::string msg("Exception when trying to ");
178  msg.append(helpText);
179  msg.append(": ");
180  msg.append(erText);
181  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
182  return msg;
183  }
184 
185 
203  class cmd_ : public xmlrpc_c::method
204  {
205  public:
206 
207  // Can't seem to initialize "_signature" and "_help" in the initialization list...
214  cmd_(xmlrpc_commander& c, const std::string& signature, const std::string& description) : _c(c)
215  {
216  _signature = signature;
217  _help = description;
218  }
219 
225  void execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP) final;
226 
227  protected:
228 
230 
236  virtual bool execute_(const xmlrpc_c::paramList&, xmlrpc_c::value* const retvalP) = 0;
237 
247  template <typename T>
248  T getParam(const xmlrpc_c::paramList& paramList, int index);
249 
273  template <typename T>
274  T getParam(const xmlrpc_c::paramList& paramList, int index, T default_value);
275  };
276 
277  // Users are only allowed to call getParam for predefined types; see
278  // template specializations below this default function
279 
280  template <typename T>
281  T cmd_::getParam(const xmlrpc_c::paramList&, int)
282  {
283  throw cet::exception("cmd_") << "Error in cmd_::getParam(): value type not supported" << std::endl;
284  }
285 
294  template <>
295  uint64_t cmd_::getParam<uint64_t>(const xmlrpc_c::paramList& paramList, int index)
296  {
297  return boost::lexical_cast<uint64_t>(paramList.getInt(index));
298  }
299 
308  template <>
309  std::string cmd_::getParam<std::string>(const xmlrpc_c::paramList& paramList, int index)
310  {
311  return static_cast<std::string>(paramList.getString(index));
312  }
313 
322  template <>
323  art::RunID cmd_::getParam<art::RunID>(const xmlrpc_c::paramList& paramList, int index)
324  {
325  std::string run_number_string = paramList.getString(index);
326  art::RunNumber_t run_number =
327  boost::lexical_cast<art::RunNumber_t>(run_number_string);
328  art::RunID run_id(run_number);
329 
330  return run_id;
331  }
332 
341  template <>
342  fhicl::ParameterSet cmd_::getParam<fhicl::ParameterSet>(const xmlrpc_c::paramList& paramList, int index)
343  {
344  std::string configString = std::string(paramList.getString(index).c_str());
345  TLOG(TLVL_DEBUG) << "Loading Parameter Set from string: " << configString << std::endl;
346  fhicl::ParameterSet pset;
347 
348  try
349  {
350  fhicl::make_ParameterSet(configString, pset);
351  }
352  catch (fhicl::exception e)
353  {
354  if (getenv("FHICL_FILE_PATH") == nullptr)
355  {
356  std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
357  setenv("FHICL_FILE_PATH", ".", 0);
358  }
359  cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH");
360  fhicl::make_ParameterSet(configString, lookup_policy, pset);
361  }
362 
363  TLOG(TLVL_INFO) << "Parameter Set Loaded." << std::endl;
364  return pset;
365  }
366 
367  template <typename T>
368  T cmd_::getParam(const xmlrpc_c::paramList& paramList, int index,
369  T default_value)
370  {
371  T val = default_value;
372 
373  try
374  {
375  val = getParam<T>(paramList, index);
376  }
377  catch (const cet::exception& exception)
378  {
379  throw exception;
380  }
381  catch (...) {}
382 
383  return val;
384  }
385 
386  void cmd_::execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP)
387  {
388  std::unique_lock<std::timed_mutex> lk(_c.mutex_, std::chrono::milliseconds(250));
389  if (lk.owns_lock())
390  {
391  try
392  {
393  // JCF, 9/4/14
394 
395  // Assuming the execute_ function returns true, then if the
396  // retvalP argument was untouched, assign it the string
397  // "Success"
398 
399  // See
400  // http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#isinstantiated
401  // for more on the concept of instantiation in xmlrpc_c::value objects
402 
403  if (execute_(paramList, retvalP))
404  {
405  if (!retvalP->isInstantiated())
406  {
407  *retvalP = xmlrpc_c::value_string("Success");
408  }
409  }
410  else
411  {
412  std::string problemReport = _c._commandable.report("transition_status");
413  *retvalP = xmlrpc_c::value_string(problemReport);
414  }
415  }
416  catch (std::runtime_error& er)
417  {
418  std::string msg = exception_msg(er, _help);
419  *retvalP = xmlrpc_c::value_string(msg);
420  TLOG(TLVL_ERROR) << msg ;
421  }
422  catch (art::Exception& er)
423  {
424  std::string msg = exception_msg(er, _help);
425  *retvalP = xmlrpc_c::value_string(msg);
426  TLOG(TLVL_ERROR) << msg ;
427  }
428  catch (cet::exception& er)
429  {
430  std::string msg = exception_msg(er, _help);
431  *retvalP = xmlrpc_c::value_string(msg);
432  TLOG(TLVL_ERROR) << msg ;
433  }
434  catch (...)
435  {
436  std::string msg = exception_msg("Unknown exception", _help);
437  *retvalP = xmlrpc_c::value_string(msg);
438  TLOG(TLVL_ERROR) << msg ;
439  }
440  }
441  else
442  {
443  *retvalP = xmlrpc_c::value_string("busy");
444  }
445  }
446 
447 
449 
450  // JCF, 9/5/14
451 
452  // The three "init" transitions all take a FHiCL parameter list, and
453  // optionally a timeout and a timestamp; thus we can kill three birds
454  // with one stone in the GENERATE_INIT_TRANSITION macro
455 
456 #define GENERATE_INIT_TRANSITION(NAME, CALL, DESCRIPTION) \
457  \
458  class NAME ## _: public cmd_ { \
459  \
460  public: \
461  \
464  explicit NAME ## _(xmlrpc_commander& c): \
465  cmd_(c, "s:sii", DESCRIPTION) {} \
466  \
467  \
468  static const uint64_t defaultTimeout = 45; \
469  \
470  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
471  \
472  private: \
473  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP ) { \
474  fhicl::ParameterSet ps; \
475  try { \
476  ps = getParam<fhicl::ParameterSet>(paramList, 0); \
477  } catch (...) { \
478  *retvalP = xmlrpc_c::value_string ("The "#NAME" message requires a single argument that is a string containing the initialization ParameterSet"); \
479  return true; \
480  } \
481  \
482  return _c._commandable.CALL(ps, \
483  getParam<uint64_t>(paramList, 1, defaultTimeout), \
484  getParam<uint64_t>(paramList, 2, defaultTimestamp) \
485  ); \
486  } \
487  };
488 
489  GENERATE_INIT_TRANSITION(init, initialize, "initialize the program")
490 
491  GENERATE_INIT_TRANSITION(soft_init, soft_initialize, "initialize software components in the program")
492 
493  GENERATE_INIT_TRANSITION(reinit, reinitialize, "re-initialize the program")
494 
495 #undef GENERATE_INIT_TRANSITION
496 
498 
502  class start_ : public cmd_
503  {
504  public:
509  explicit start_(xmlrpc_commander& c) :
510  cmd_(c, "s:iii", "start the run")
511  {}
512 
514  static const uint64_t defaultTimeout = 45;
516  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max();
517 
518  private:
519 
520  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) override
521  {
522  try
523  {
524  getParam<art::RunID>(paramList, 0);
525  }
526  catch (...)
527  {
528  *retvalP = xmlrpc_c::value_string("The start message requires the run number as an argument.");
529  return true;
530  }
531 
532  return _c._commandable.start(getParam<art::RunID>(paramList, 0),
533  getParam<uint64_t>(paramList, 1, defaultTimeout),
534  getParam<uint64_t>(paramList, 2, defaultTimestamp)
535  );
536  }
537  };
538 
539 
541 
542  // JCF, 9/5/14
543 
544  // "pause", "resume" and "stop" all take an optional timeout and
545  // timestamp parameter, so we can generate them all with the
546  // GENERATE_TIMEOUT_TIMESTAMP_TRANSITION macro
547 
548 #define GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(NAME, CALL, DESCRIPTION, TIMEOUT) \
549  \
550  class NAME ## _: public cmd_ { \
551  \
552 public: \
553  \
555  NAME ## _(xmlrpc_commander& c): \
556  cmd_(c, "s:ii", DESCRIPTION) {} \
557  \
558  \
559  static const uint64_t defaultTimeout = TIMEOUT ; \
560  \
561  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
562  \
563 private: \
564  \
565  bool execute_ (const xmlrpc_c::paramList& paramList , xmlrpc_c::value* const ) { \
566  \
567  return _c._commandable.CALL( getParam<uint64_t>(paramList, 0, defaultTimeout), \
568  getParam<uint64_t>(paramList, 1, defaultTimestamp) \
569  ); \
570  } \
571  };
572 
573  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(pause, pause, "pause the program", 45)
574 
575  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(resume, resume, "resume the program", 45)
576 
577  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(stop, stop, "stop the program", 45)
578 
579 #undef GENERATE_TIMEOUT_TIMESTAMP_TRANSITION
580 
581 
585  class shutdown_ : public cmd_
586  {
587  public:
593  cmd_(c, "s:i", "shutdown the program")
594  {}
595 
597  static const uint64_t defaultTimeout = 45;
598 
599  private:
600 
601  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
602  {
603  auto ret = _c._commandable.shutdown(getParam<uint64_t>(paramList, 0, defaultTimeout));
604 
605 #if 1
606  if (_c.server) _c.server->terminate();
607 #endif
608 
609  return ret;
610  }
611  };
612 
613 
617  class status_ : public cmd_
618  {
619  public:
625  cmd_(c, "s:n", "report the current state")
626  {}
627 
628  private:
629 
630  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
631  {
632  *retvalP = xmlrpc_c::value_string(_c._commandable.status());
633  return true;
634  }
635  };
636 
637 
641  class report_ : public cmd_
642  {
643  public:
649  cmd_(c, "s:s", "report statistics")
650  {}
651 
652  private:
653  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
654  {
655  try
656  {
657  getParam<std::string>(paramList, 0);
658  }
659  catch (...)
660  {
661  *retvalP = xmlrpc_c::value_string("The report message requires a single argument that selects the type of statistics to be reported.");
662  return true;
663  }
664 
665  *retvalP = xmlrpc_c::value_string(_c._commandable.report(getParam<std::string>(paramList, 0)));
666  return true;
667  }
668  };
669 
673  class legal_commands_ : public cmd_
674  {
675  public:
681  cmd_(c, "s:n", "return the currently legal commands")
682  {}
683 
684  private:
685  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
686  {
687  std::vector<std::string> cmdList = _c._commandable.legal_commands();
688  std::string resultString;
689 
690  for (auto& cmd : cmdList)
691  {
692  resultString.append(cmd + " ");
693  if (cmd == "shutdown")
694  {
695  resultString.append(" reset");
696  }
697  }
698  *retvalP = xmlrpc_c::value_string(resultString);
699 
700  return true;
701  }
702  };
703 
707  class register_monitor_ : public cmd_
708  {
709  public:
715  cmd_(c, "s:s", "Get notified of a new monitor")
716  {}
717 
718  private:
719  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
720  {
721  try
722  {
723  getParam<fhicl::ParameterSet>(paramList, 0);
724  }
725  catch (...)
726  {
727  *retvalP = xmlrpc_c::value_string("The register_monitor command expects a string representing the FHiCL definition of a Transfer plugin");
728  return true;
729  }
730 
731  *retvalP = xmlrpc_c::value_string(_c._commandable.register_monitor(getParam<fhicl::ParameterSet>(paramList, 0)));
732  return true;
733  }
734  };
735 
739  class unregister_monitor_ : public cmd_
740  {
741  public:
747  cmd_(c, "s:s", "Remove a monitor")
748  {}
749 
750  private:
751  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
752  {
753  try
754  {
755  getParam<std::string>(paramList, 0);
756  }
757  catch (...)
758  {
759  *retvalP = xmlrpc_c::value_string("The unregister_monitor command expects a string representing the label of the monitor to be removed");
760  return true;
761  }
762 
763  *retvalP = xmlrpc_c::value_string(_c._commandable.unregister_monitor(getParam<std::string>(paramList, 0)));
764  return true;
765  }
766  };
767 
768 
772  class trace_set_ : public cmd_
773  {
774  public:
780  cmd_(c, "s:ssi", "Set TRACE mask")
781  {}
782 
783  private:
784  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
785  {
786  try
787  {
788  getParam<std::string>(paramList, 0);
789  getParam<std::string>(paramList, 1);
790  getParam<uint64_t>(paramList, 2);
791  }
792  catch (...)
793  {
794  *retvalP = xmlrpc_c::value_string("The trace_set command expects a mask type (M, S , or T), a name (ALL for all) and a mask");
795  return true;
796  }
797 
798  return _c._commandable.do_trace_set(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1), getParam<uint64_t>(paramList, 2));
799  }
800  };
801 
805  class trace_get_ : public cmd_
806  {
807  public:
813  cmd_(c, "s:s", "Get TRACE mask")
814  {}
815 
816  private:
817  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
818  {
819  try
820  {
821  getParam<std::string>(paramList, 0);
822  }
823  catch (...)
824  {
825  *retvalP = xmlrpc_c::value_string("The trace_msgfacility_set command expects a name (ALL for all)");
826  return true;
827  }
828 
829  *retvalP = xmlrpc_c::value_string(_c._commandable.do_trace_get(getParam<std::string>(paramList, 0)));
830  return true;
831  }
832  };
833 
837  class meta_command_ : public cmd_
838  {
839  public:
845  cmd_(c, "s:ss", "Run custom command")
846  {}
847 
848  private:
849  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
850  {
851  try
852  {
853  getParam<std::string>(paramList, 0);
854  getParam<std::string>(paramList, 1);
855  }
856  catch (...)
857  {
858  *retvalP = xmlrpc_c::value_string("The meta_command command expects a string command and a string argument");
859  return true;
860  }
861 
862  return _c._commandable.do_meta_command(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1));
863  }
864  };
865 
866  // JCF, 9/4/14
867 
868  // Not sure if anyone was planning to resurrect this code by changing
869  // the preprocessor decision; as such, I'll leave it in for now...
870 
871 #if 0
872  class shutdown_ : public xmlrpc_c::registry::shutdown
873  {
874  public:
875  shutdown_(xmlrpc_c::serverAbyss *server) : _server(server) {}
876 
877  virtual void doit(const std::string& paramString, void*) const
878  {
879  TLOG(TLVL_INFO) << "A shutdown command was sent "
880  << "with parameter "
881  << paramString << "\"" ;
882  _server->terminate();
883  }
884  private:
885  xmlrpc_c::serverAbyss *_server;
886  };
887 #endif
888 
889 
890 
891  xmlrpc_commander::xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable& commandable)
892  : CommanderInterface(ps, commandable)
893  , port_(ps.get<int>("id", 0))
894  , serverUrl_(ps.get<std::string>("server_url", ""))
895  , server(nullptr)
896  {
897  //std::cout << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_ << std::endl;
898  }
899 
901  {
902  //std::cout << "XMLRPC_COMMANDER RUN_SERVER CALLED!" << std::endl;
903  xmlrpc_c::registry registry;
904  struct xmlrpc_method_info3 methodInfo;
905  memset(&methodInfo, 0, sizeof(methodInfo));
906 
907  /*#define register_method(m) \
908  // xmlrpc_c::methodPtr const ptr_ ## m(new m ## _(*this));\
909  registry.addMethod ("daq." #m, ptr_ ## m) */
910 #define register_method(m) register_method2(m,0x400000)
911 
912  xmlrpc_env env; // xmlrpc_env_init(&env);
913  xmlrpc_registry ***c_registryPPP;
914  c_registryPPP = (xmlrpc_registry ***)(((char*)&registry) + sizeof(girmem::autoObject));
915 
916 #define register_method2(m,ss) \
917  xmlrpc_c::method * ptr_ ## m(dynamic_cast<xmlrpc_c::method *>(new m ## _(*this))); \
918  methodInfo.methodName = "daq." #m; \
919  methodInfo.methodFunction = &c_executeMethod; \
920  methodInfo.serverInfo = ptr_ ## m; \
921  methodInfo.stackSize = ss; \
922  methodInfo.signatureString = ptr_ ## m ->signature().c_str(); \
923  methodInfo.help = ptr_ ## m ->help().c_str(); \
924  xmlrpc_env_init(&env); \
925  xmlrpc_registry_add_method3(&env,**c_registryPPP,&methodInfo); \
926  if(env.fault_occurred)throw(girerr::error(env.fault_string)); \
927  xmlrpc_env_clean(&env)
928 
929  register_method2(init, 0x200000);
930  register_method(soft_init);
931  register_method(reinit);
932  register_method(start);
933  register_method(status);
934  register_method(report);
935  register_method(stop);
936  register_method(pause);
937  register_method(resume);
938  register_method(register_monitor);
939  register_method(unregister_monitor);
940  register_method(legal_commands);
941  register_method(trace_set);
942  register_method(trace_get);
943  register_method(meta_command);
944 
945  register_method(shutdown);
946 
947  // alias "daq.reset" to the internal shutdown transition
948  xmlrpc_c::methodPtr const ptr_reset(new shutdown_(*this));
949  registry.addMethod("daq.reset", ptr_reset);
950 
951 #undef register_method
952 
953  // JCF, 6/3/15
954 
955  // In the following code, I configure a socket to have the
956  // SO_REUSEADDR option so that once an artdaq process closes, the
957  // port it was communicating on becomes immediately available
958  // (desirable if, say, the DAQ program is terminated and then
959  // immediately restarted)
960 
961  // Much of the following code is cribbed from
962  // http://fossies.org/linux/freeswitch/libs/xmlrpc-c/src/cpp/test/server_abyss.cpp
963 
964  // Below, "0" is the default protocol (in this case, given the IPv4
965  // Protocol Family (PF_INET) and the SOCK_STREAM communication
966  // method)
967 
968  XMLRPC_SOCKET socket_file_descriptor = socket(PF_INET, SOCK_STREAM, 0);
969 
970  if (socket_file_descriptor < 0)
971  {
972  throw cet::exception("xmlrpc_commander::run") <<
973  "Problem with the socket() call; C-style errno == " <<
974  errno << " (" << strerror(errno) << ")";
975  }
976 
977  int enable = 1;
978  int retval = setsockopt(socket_file_descriptor,
979  SOL_SOCKET, SO_REUSEADDR,
980  &enable, sizeof(int));
981 
982  if (retval < 0)
983  {
984  throw cet::exception("xmlrpc_commander::run") <<
985  "Problem with the call to setsockopt(); C-style errno == " <<
986  errno << " (" << strerror(errno) << ")";
987  }
988 
989  struct sockaddr_in sockAddr;
990 
991  sockAddr.sin_family = AF_INET;
992  sockAddr.sin_port = htons(port_);
993  sockAddr.sin_addr.s_addr = 0;
994 
995  retval = bind(socket_file_descriptor,
996  reinterpret_cast<struct sockaddr*>(&sockAddr),
997  sizeof(sockAddr));
998 
999  if (retval != 0)
1000  {
1001  close(socket_file_descriptor);
1002  throw cet::exception("xmlrpc_commander::run") <<
1003  "Problem with the bind() call; C-style errno == " <<
1004  errno << " (" << strerror(errno) << ")";
1005  }
1006 
1007  server.reset(new xmlrpc_c::serverAbyss(xmlrpc_c::serverAbyss::constrOpt().registryP(&registry).socketFd(socket_file_descriptor)));
1008 
1009 #if 0
1010  xmlrpc_c::serverAbyss::shutdown shutdown_obj(&server);
1011  registry.setShutdown(&shutdown_obj);
1012 #endif
1013 
1014  TLOG(TLVL_DEBUG) << "running server" ;
1015 
1016  // JCF, 6/3/15
1017 
1018  // Use a catch block to clean up (i.e., close the socket). An
1019  // opportunity for RAII, although all control paths are limited to
1020  // this section of the file...
1021 
1022  try
1023  {
1024  server->run();
1025  }
1026  catch (...)
1027  {
1028  TLOG(TLVL_WARNING) << "server threw an exception; closing the socket and rethrowing" ;
1029  close(socket_file_descriptor);
1030  throw;
1031  }
1032 
1033  close(socket_file_descriptor);
1034  TLOG(TLVL_DEBUG) << "server terminated" ;
1035  }
1036  catch (...)
1037  {
1038  throw;
1039  }
1040 
1041 
1042  std::string xmlrpc_commander::send_register_monitor(std::string monitor_fhicl)
1043  {
1044  if (serverUrl_ == "")
1045  {
1046  std::stringstream errmsg;
1047  errmsg << "Problem attempting XML-RPC call: No server URL set!";
1048  ExceptionHandler(ExceptionHandlerRethrow::yes,
1049  errmsg.str());
1050 
1051  }
1052  xmlrpc_c::clientSimple myClient;
1053  xmlrpc_c::value result;
1054 
1055  try
1056  {
1057  myClient.call(serverUrl_, "daq.register_monitor", "s", &result, monitor_fhicl.c_str());
1058  }
1059  catch (...)
1060  {
1061  std::stringstream errmsg;
1062  errmsg << "Problem attempting XML-RPC call on host " << serverUrl_
1063  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1064  ExceptionHandler(ExceptionHandlerRethrow::yes,
1065  errmsg.str());
1066  }
1067 
1068  return xmlrpc_c::value_string(result);
1069  }
1070 
1071  std::string xmlrpc_commander::send_unregister_monitor(std::string monitor_label)
1072  {
1073  if (serverUrl_ == "")
1074  {
1075  std::stringstream errmsg;
1076  errmsg << "Problem attempting XML-RPC call: No server URL set!";
1077  ExceptionHandler(ExceptionHandlerRethrow::yes,
1078  errmsg.str());
1079 
1080  }
1081 
1082  xmlrpc_c::clientSimple myClient;
1083  xmlrpc_c::value result;
1084 
1085  try
1086  {
1087  myClient.call(serverUrl_, "daq.unregister_monitor", "s", &result, monitor_label.c_str());
1088  }
1089  catch (...)
1090  {
1091  std::stringstream errmsg;
1092  errmsg << "Problem attempting to unregister monitor via XML-RPC call on host " << serverUrl_
1093  << "; possible causes are that the monitor label \""
1094  << monitor_label
1095  << "\" is unrecognized by contacted process or process at requested port doesn't exist";
1096  ExceptionHandler(ExceptionHandlerRethrow::no, errmsg.str());
1097  }
1098 
1099  return xmlrpc_c::value_string(result);
1100 
1101  }
1102 } // namespace artdaq
1103 
1104 DEFINE_ARTDAQ_COMMANDER(artdaq::xmlrpc_commander)
This interface defines the functions used to transfer data between artdaq applications.
cmd_(xmlrpc_commander &c, const std::string &signature, const std::string &description)
cmd_ Constructor
static const uint64_t defaultTimeout
std::string send_unregister_monitor(std::string monitor_label) override
Send an unregister_monitor command over XMLRPC
std::string send_register_monitor(std::string monitor_fhicl) override
Send a register_monitor command over XMLRPC
virtual std::string report(std::string const &) const
Default report implementation returns current report_string.
Definition: Commandable.hh:121
Commandable is the base class for all artdaq components which implement the artdaq state machine...
Definition: Commandable.hh:20
legal_commands_(xmlrpc_commander &c)
legal_commands_ Constructor
xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable &commandable)
xmlrpc_commander Constructor
Command class representing a start transition.
status_ Command class
report_ Command class
virtual bool do_trace_set(std::string const &, std::string const &, uint64_t)
Set the given TRACE mask for the given trace name.
Definition: Commandable.cc:453
virtual std::string do_trace_get(std::string const &)
Get the TRACE mask for the given trace name.
Definition: Commandable.cc:424
virtual std::string unregister_monitor(std::string const &)
Perform the unregister_monitor action.
Definition: Commandable.hh:150
meta_command_ Command class
The xmlrpc_commander class serves as the XMLRPC server run in each artdaq application.
static const uint64_t defaultTimestamp
The &quot;cmd_&quot; class serves as the base class for all artdaq&#39;s XML-RPC commands.
trace_set_(xmlrpc_commander &c)
unregister_monitor_ Constructor
shutdown_ Command class
void run_server() override
Run the XMLRPC server.
meta_command_(xmlrpc_commander &c)
meta_command_ Constructor
std::unique_ptr< xmlrpc_c::serverAbyss > server
XMLRPC server.
std::string status() const
Returns the current state of the Commandable.
Definition: Commandable.cc:291
std::string exception_msg(const std::runtime_error &er, const std::string &helpText="execute request")
Write an exception message.
virtual std::string register_monitor(fhicl::ParameterSet const &)
Perform the register_monitor action.
Definition: Commandable.hh:139
register_monitor_ Command class
legal_commands_ Command class
artdaq::Commandable & _commandable
Reference to the Commandable that this Commander Commands.
xmlrpc_commander & _c
The xmlrpc_commander instance that the command will be sent to.
trace_get_ Command class
status_(xmlrpc_commander &c)
status_ Constructor
virtual bool execute_(const xmlrpc_c::paramList &, xmlrpc_c::value *const retvalP)=0
&quot;execute_&quot; is a wrapper function around the call to the commandable object&#39;s function ...
std::timed_mutex mutex_
XMLRPC mutex.
register_monitor_(xmlrpc_commander &c)
register_monitor_ Constructor
static const uint64_t defaultTimeout
unregister_monitor_(xmlrpc_commander &c)
unregister_monitor_ Constructor
void execute(const xmlrpc_c::paramList &paramList, xmlrpc_c::value *const retvalP) final
Execute trhe command with the given parameters.
shutdown_(xmlrpc_commander &c)
shutdown_ Constructor
virtual bool do_meta_command(std::string const &, std::string const &)
Run a module-defined command with the given parameter string.
Definition: Commandable.cc:501
std::vector< std::string > legal_commands() const
Get the legal transition commands from the current state.
Definition: Commandable.cc:304
bool start(art::RunID id, uint64_t timeout, uint64_t timestamp)
Processes the start transition.
Definition: Commandable.cc:59
report_(xmlrpc_commander &c)
report_ Constructor
trace_set_ Command class
start_(xmlrpc_commander &c)
start_ Command (cmd_ derived class) Constructor
trace_get_(xmlrpc_commander &c)
trace_msgfacility_set_ Constructor
unregister_monitor_ Command class
T getParam(const xmlrpc_c::paramList &paramList, int index)
Get a parameter from the parameter list.
bool shutdown(uint64_t timeout)
Processes the shutdown transition.
Definition: Commandable.cc:175