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