artdaq  v3_02_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  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as uint64_t.";
298  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
299  return boost::lexical_cast<uint64_t>(paramList.getString(index));
300  }
301 
310  template <>
311  std::string cmd_::getParam<std::string>(const xmlrpc_c::paramList& paramList, int index)
312  {
313  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as string.";
314  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
315  return static_cast<std::string>(paramList.getString(index));
316  }
317 
326  template <>
327  art::RunID cmd_::getParam<art::RunID>(const xmlrpc_c::paramList& paramList, int index)
328  {
329  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as Run Number.";
330  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
331  std::string run_number_string = paramList.getString(index);
332  art::RunNumber_t run_number =
333  boost::lexical_cast<art::RunNumber_t>(run_number_string);
334  art::RunID run_id(run_number);
335 
336  return run_id;
337  }
338 
347  template <>
348  fhicl::ParameterSet cmd_::getParam<fhicl::ParameterSet>(const xmlrpc_c::paramList& paramList, int index)
349  {
350  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as ParameterSet.";
351  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
352  std::string configString = std::string(paramList.getString(index).c_str());
353  TLOG(TLVL_DEBUG) << "Loading Parameter Set from string: " << configString << std::endl;
354  fhicl::ParameterSet pset;
355 
356  try
357  {
358  fhicl::make_ParameterSet(configString, pset);
359  }
360  catch (fhicl::exception e)
361  {
362  if (getenv("FHICL_FILE_PATH") == nullptr)
363  {
364  std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
365  setenv("FHICL_FILE_PATH", ".", 0);
366  }
367  cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH");
368  fhicl::make_ParameterSet(configString, lookup_policy, pset);
369  }
370 
371  TLOG(TLVL_INFO) << "Parameter Set Loaded." << std::endl;
372  return pset;
373  }
374 
375  template <typename T>
376  T cmd_::getParam(const xmlrpc_c::paramList& paramList, int index,
377  T default_value)
378  {
379  T val = default_value;
380 
381  try
382  {
383  val = getParam<T>(paramList, index);
384  }
385  catch (const cet::exception& exception)
386  {
387  throw exception;
388  }
389  catch (...) {}
390 
391  return val;
392  }
393 
394  void cmd_::execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP)
395  {
396  std::unique_lock<std::timed_mutex> lk(_c.mutex_, std::chrono::milliseconds(250));
397  if (lk.owns_lock())
398  {
399  try
400  {
401  // JCF, 9/4/14
402 
403  // Assuming the execute_ function returns true, then if the
404  // retvalP argument was untouched, assign it the string
405  // "Success"
406 
407  // See
408  // http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#isinstantiated
409  // for more on the concept of instantiation in xmlrpc_c::value objects
410 
411  if (execute_(paramList, retvalP))
412  {
413  if (!retvalP->isInstantiated())
414  {
415  *retvalP = xmlrpc_c::value_string("Success");
416  }
417  }
418  else
419  {
420  std::string problemReport = _c._commandable.report("transition_status");
421  *retvalP = xmlrpc_c::value_string(problemReport);
422  }
423  }
424  catch (std::runtime_error& er)
425  {
426  std::string msg = exception_msg(er, _help);
427  *retvalP = xmlrpc_c::value_string(msg);
428  TLOG(TLVL_ERROR) << msg ;
429  }
430  catch (art::Exception& er)
431  {
432  std::string msg = exception_msg(er, _help);
433  *retvalP = xmlrpc_c::value_string(msg);
434  TLOG(TLVL_ERROR) << msg ;
435  }
436  catch (cet::exception& er)
437  {
438  std::string msg = exception_msg(er, _help);
439  *retvalP = xmlrpc_c::value_string(msg);
440  TLOG(TLVL_ERROR) << msg ;
441  }
442  catch (...)
443  {
444  std::string msg = exception_msg("Unknown exception", _help);
445  *retvalP = xmlrpc_c::value_string(msg);
446  TLOG(TLVL_ERROR) << msg ;
447  }
448  }
449  else
450  {
451  *retvalP = xmlrpc_c::value_string("busy");
452  }
453  }
454 
455 
457 
458  // JCF, 9/5/14
459 
460  // The three "init" transitions all take a FHiCL parameter list, and
461  // optionally a timeout and a timestamp; thus we can kill three birds
462  // with one stone in the GENERATE_INIT_TRANSITION macro
463 
464 #define GENERATE_INIT_TRANSITION(NAME, CALL, DESCRIPTION) \
465  \
466  class NAME ## _: public cmd_ { \
467  \
468  public: \
469  \
472  explicit NAME ## _(xmlrpc_commander& c): \
473  cmd_(c, "s:sii", DESCRIPTION) {} \
474  \
475  \
476  static const uint64_t defaultTimeout = 45; \
477  \
478  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
479  \
480  private: \
481  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP ) { \
482  fhicl::ParameterSet ps; \
483  try { \
484  ps = getParam<fhicl::ParameterSet>(paramList, 0); \
485  } catch (...) { \
486  *retvalP = xmlrpc_c::value_string ("The "#NAME" message requires a single argument that is a string containing the initialization ParameterSet"); \
487  return true; \
488  } \
489  \
490  return _c._commandable.CALL(ps, \
491  getParam<uint64_t>(paramList, 1, defaultTimeout), \
492  getParam<uint64_t>(paramList, 2, defaultTimestamp) \
493  ); \
494  } \
495  };
496 
497  GENERATE_INIT_TRANSITION(init, initialize, "initialize the program")
498 
499  GENERATE_INIT_TRANSITION(soft_init, soft_initialize, "initialize software components in the program")
500 
501  GENERATE_INIT_TRANSITION(reinit, reinitialize, "re-initialize the program")
502 
503 #undef GENERATE_INIT_TRANSITION
504 
506 
510  class start_ : public cmd_
511  {
512  public:
517  explicit start_(xmlrpc_commander& c) :
518  cmd_(c, "s:iii", "start the run")
519  {}
520 
522  static const uint64_t defaultTimeout = 45;
524  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max();
525 
526  private:
527 
528  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) override
529  {
530  try
531  {
532  getParam<art::RunID>(paramList, 0);
533  }
534  catch (...)
535  {
536  *retvalP = xmlrpc_c::value_string("The start message requires the run number as an argument.");
537  return true;
538  }
539 
540  return _c._commandable.start(getParam<art::RunID>(paramList, 0),
541  getParam<uint64_t>(paramList, 1, defaultTimeout),
542  getParam<uint64_t>(paramList, 2, defaultTimestamp)
543  );
544  }
545  };
546 
547 
549 
550  // JCF, 9/5/14
551 
552  // "pause", "resume" and "stop" all take an optional timeout and
553  // timestamp parameter, so we can generate them all with the
554  // GENERATE_TIMEOUT_TIMESTAMP_TRANSITION macro
555 
556 #define GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(NAME, CALL, DESCRIPTION, TIMEOUT) \
557  \
558  class NAME ## _: public cmd_ { \
559  \
560 public: \
561  \
563  NAME ## _(xmlrpc_commander& c): \
564  cmd_(c, "s:ii", DESCRIPTION) {} \
565  \
566  \
567  static const uint64_t defaultTimeout = TIMEOUT ; \
568  \
569  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
570  \
571 private: \
572  \
573  bool execute_ (const xmlrpc_c::paramList& paramList , xmlrpc_c::value* const ) { \
574  \
575  return _c._commandable.CALL( getParam<uint64_t>(paramList, 0, defaultTimeout), \
576  getParam<uint64_t>(paramList, 1, defaultTimestamp) \
577  ); \
578  } \
579  };
580 
581  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(pause, pause, "pause the program", 45)
582 
583  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(resume, resume, "resume the program", 45)
584 
585  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(stop, stop, "stop the program", 45)
586 
587 #undef GENERATE_TIMEOUT_TIMESTAMP_TRANSITION
588 
589 
593  class shutdown_ : public cmd_
594  {
595  public:
601  cmd_(c, "s:i", "shutdown the program")
602  {}
603 
605  static const uint64_t defaultTimeout = 45;
606 
607  private:
608 
609  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
610  {
611  auto ret = _c._commandable.shutdown(getParam<uint64_t>(paramList, 0, defaultTimeout));
612 
613 #if 1
614  if (_c.server) _c.server->terminate();
615 #endif
616 
617  return ret;
618  }
619  };
620 
621 
625  class status_ : public cmd_
626  {
627  public:
633  cmd_(c, "s:n", "report the current state")
634  {}
635 
636  private:
637 
638  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
639  {
640  *retvalP = xmlrpc_c::value_string(_c._commandable.status());
641  return true;
642  }
643  };
644 
645 
649  class report_ : public cmd_
650  {
651  public:
657  cmd_(c, "s:s", "report statistics")
658  {}
659 
660  private:
661  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
662  {
663  try
664  {
665  getParam<std::string>(paramList, 0);
666  }
667  catch (...)
668  {
669  *retvalP = xmlrpc_c::value_string("The report message requires a single argument that selects the type of statistics to be reported.");
670  return true;
671  }
672 
673  *retvalP = xmlrpc_c::value_string(_c._commandable.report(getParam<std::string>(paramList, 0)));
674  return true;
675  }
676  };
677 
681  class legal_commands_ : public cmd_
682  {
683  public:
689  cmd_(c, "s:n", "return the currently legal commands")
690  {}
691 
692  private:
693  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
694  {
695  std::vector<std::string> cmdList = _c._commandable.legal_commands();
696  std::string resultString;
697 
698  for (auto& cmd : cmdList)
699  {
700  resultString.append(cmd + " ");
701  if (cmd == "shutdown")
702  {
703  resultString.append(" reset");
704  }
705  }
706  *retvalP = xmlrpc_c::value_string(resultString);
707 
708  return true;
709  }
710  };
711 
715  class register_monitor_ : public cmd_
716  {
717  public:
723  cmd_(c, "s:s", "Get notified of a new monitor")
724  {}
725 
726  private:
727  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
728  {
729  try
730  {
731  getParam<fhicl::ParameterSet>(paramList, 0);
732  }
733  catch (...)
734  {
735  *retvalP = xmlrpc_c::value_string("The register_monitor command expects a string representing the FHiCL definition of a Transfer plugin");
736  return true;
737  }
738 
739  *retvalP = xmlrpc_c::value_string(_c._commandable.register_monitor(getParam<fhicl::ParameterSet>(paramList, 0)));
740  return true;
741  }
742  };
743 
747  class unregister_monitor_ : public cmd_
748  {
749  public:
755  cmd_(c, "s:s", "Remove a monitor")
756  {}
757 
758  private:
759  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
760  {
761  try
762  {
763  getParam<std::string>(paramList, 0);
764  }
765  catch (...)
766  {
767  *retvalP = xmlrpc_c::value_string("The unregister_monitor command expects a string representing the label of the monitor to be removed");
768  return true;
769  }
770 
771  *retvalP = xmlrpc_c::value_string(_c._commandable.unregister_monitor(getParam<std::string>(paramList, 0)));
772  return true;
773  }
774  };
775 
776 
780  class trace_set_ : public cmd_
781  {
782  public:
788  cmd_(c, "s:ssi", "Set TRACE mask")
789  {}
790 
791  private:
792  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
793  {
794  try
795  {
796  getParam<std::string>(paramList, 0);
797  getParam<std::string>(paramList, 1);
798  getParam<uint64_t>(paramList, 2);
799  }
800  catch (...)
801  {
802  *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");
803  return true;
804  }
805 
806  return _c._commandable.do_trace_set(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1), getParam<uint64_t>(paramList, 2));
807  }
808  };
809 
813  class trace_get_ : public cmd_
814  {
815  public:
821  cmd_(c, "s:s", "Get TRACE mask")
822  {}
823 
824  private:
825  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
826  {
827  try
828  {
829  getParam<std::string>(paramList, 0);
830  }
831  catch (...)
832  {
833  *retvalP = xmlrpc_c::value_string("The trace_msgfacility_set command expects a name (ALL for all)");
834  return true;
835  }
836 
837  *retvalP = xmlrpc_c::value_string(_c._commandable.do_trace_get(getParam<std::string>(paramList, 0)));
838  return true;
839  }
840  };
841 
845  class meta_command_ : public cmd_
846  {
847  public:
853  cmd_(c, "s:ss", "Run custom command")
854  {}
855 
856  private:
857  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
858  {
859  try
860  {
861  getParam<std::string>(paramList, 0);
862  getParam<std::string>(paramList, 1);
863  }
864  catch (...)
865  {
866  *retvalP = xmlrpc_c::value_string("The meta_command command expects a string command and a string argument");
867  return true;
868  }
869 
870  return _c._commandable.do_meta_command(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1));
871  }
872  };
873 
877  class rollover_subrun_ : public cmd_
878  {
879  public:
885  cmd_(c, "s:i", "create a new subrun")
886  {}
887 
889  static const uint64_t defaultSequenceID = 0xFFFFFFFFFFFFFFFF;
890 
891  private:
892 
893  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
894  {
895  auto ret = _c._commandable.do_rollover_subrun(getParam<uint64_t>(paramList, 0, defaultSequenceID));
896  return ret;
897  }
898  };
899 
900  // JCF, 9/4/14
901 
902  // Not sure if anyone was planning to resurrect this code by changing
903  // the preprocessor decision; as such, I'll leave it in for now...
904 
905 #if 0
906  class shutdown_ : public xmlrpc_c::registry::shutdown
907  {
908  public:
909  shutdown_(xmlrpc_c::serverAbyss *server) : _server(server) {}
910 
911  virtual void doit(const std::string& paramString, void*) const
912  {
913  TLOG(TLVL_INFO) << "A shutdown command was sent "
914  << "with parameter "
915  << paramString << "\"" ;
916  _server->terminate();
917  }
918  private:
919  xmlrpc_c::serverAbyss *_server;
920  };
921 #endif
922 
923 
924 
925  xmlrpc_commander::xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable& commandable)
926  : CommanderInterface(ps, commandable)
927  , port_(ps.get<int>("id", 0))
928  , serverUrl_(ps.get<std::string>("server_url", ""))
929  , server(nullptr)
930  {
931  //std::cout << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_ << std::endl;
932  }
933 
935  {
936  //std::cout << "XMLRPC_COMMANDER RUN_SERVER CALLED!" << std::endl;
937  xmlrpc_c::registry registry;
938  struct xmlrpc_method_info3 methodInfo;
939  memset(&methodInfo, 0, sizeof(methodInfo));
940 
941  /*#define register_method(m) \
942  // xmlrpc_c::methodPtr const ptr_ ## m(new m ## _(*this));\
943  registry.addMethod ("daq." #m, ptr_ ## m) */
944 #define register_method(m) register_method2(m,0x400000)
945 
946  xmlrpc_env env; // xmlrpc_env_init(&env);
947  xmlrpc_registry ***c_registryPPP;
948  c_registryPPP = (xmlrpc_registry ***)(((char*)&registry) + sizeof(girmem::autoObject));
949 
950 #define register_method2(m,ss) \
951  xmlrpc_c::method * ptr_ ## m(dynamic_cast<xmlrpc_c::method *>(new m ## _(*this))); \
952  methodInfo.methodName = "daq." #m; \
953  methodInfo.methodFunction = &c_executeMethod; \
954  methodInfo.serverInfo = ptr_ ## m; \
955  methodInfo.stackSize = ss; \
956  methodInfo.signatureString = ptr_ ## m ->signature().c_str(); \
957  methodInfo.help = ptr_ ## m ->help().c_str(); \
958  xmlrpc_env_init(&env); \
959  xmlrpc_registry_add_method3(&env,**c_registryPPP,&methodInfo); \
960  if(env.fault_occurred)throw(girerr::error(env.fault_string)); \
961  xmlrpc_env_clean(&env)
962 
963  register_method2(init, 0x200000);
964  register_method(soft_init);
965  register_method(reinit);
966  register_method(start);
967  register_method(status);
968  register_method(report);
969  register_method(stop);
970  register_method(pause);
971  register_method(resume);
972  register_method(register_monitor);
973  register_method(unregister_monitor);
974  register_method(legal_commands);
975  register_method(trace_set);
976  register_method(trace_get);
977  register_method(meta_command);
978  register_method(rollover_subrun);
979 
980  register_method(shutdown);
981 
982  // alias "daq.reset" to the internal shutdown transition
983  xmlrpc_c::methodPtr const ptr_reset(new shutdown_(*this));
984  registry.addMethod("daq.reset", ptr_reset);
985 
986 #undef register_method
987 
988  // JCF, 6/3/15
989 
990  // In the following code, I configure a socket to have the
991  // SO_REUSEADDR option so that once an artdaq process closes, the
992  // port it was communicating on becomes immediately available
993  // (desirable if, say, the DAQ program is terminated and then
994  // immediately restarted)
995 
996  // Much of the following code is cribbed from
997  // http://fossies.org/linux/freeswitch/libs/xmlrpc-c/src/cpp/test/server_abyss.cpp
998 
999  // Below, "0" is the default protocol (in this case, given the IPv4
1000  // Protocol Family (PF_INET) and the SOCK_STREAM communication
1001  // method)
1002 
1003  XMLRPC_SOCKET socket_file_descriptor = socket(PF_INET, SOCK_STREAM, 0);
1004 
1005  if (socket_file_descriptor < 0)
1006  {
1007  throw cet::exception("xmlrpc_commander::run") <<
1008  "Problem with the socket() call; C-style errno == " <<
1009  errno << " (" << strerror(errno) << ")";
1010  }
1011 
1012  int enable = 1;
1013  int retval = setsockopt(socket_file_descriptor,
1014  SOL_SOCKET, SO_REUSEADDR,
1015  &enable, sizeof(int));
1016 
1017  if (retval < 0)
1018  {
1019  throw cet::exception("xmlrpc_commander::run") <<
1020  "Problem with the call to setsockopt(); C-style errno == " <<
1021  errno << " (" << strerror(errno) << ")";
1022  }
1023 
1024  struct sockaddr_in sockAddr;
1025 
1026  sockAddr.sin_family = AF_INET;
1027  sockAddr.sin_port = htons(port_);
1028  sockAddr.sin_addr.s_addr = 0;
1029 
1030  retval = bind(socket_file_descriptor,
1031  reinterpret_cast<struct sockaddr*>(&sockAddr),
1032  sizeof(sockAddr));
1033 
1034  if (retval != 0)
1035  {
1036  close(socket_file_descriptor);
1037  throw cet::exception("xmlrpc_commander::run") <<
1038  "Problem with the bind() call; C-style errno == " <<
1039  errno << " (" << strerror(errno) << ")";
1040  }
1041 
1042  server.reset(new xmlrpc_c::serverAbyss(xmlrpc_c::serverAbyss::constrOpt().registryP(&registry).socketFd(socket_file_descriptor)));
1043 
1044 #if 0
1045  xmlrpc_c::serverAbyss::shutdown shutdown_obj(&server);
1046  registry.setShutdown(&shutdown_obj);
1047 #endif
1048 
1049  TLOG(TLVL_DEBUG) << "running server" ;
1050 
1051  // JCF, 6/3/15
1052 
1053  // Use a catch block to clean up (i.e., close the socket). An
1054  // opportunity for RAII, although all control paths are limited to
1055  // this section of the file...
1056 
1057  try
1058  {
1059  server->run();
1060  }
1061  catch (...)
1062  {
1063  TLOG(TLVL_WARNING) << "server threw an exception; closing the socket and rethrowing" ;
1064  close(socket_file_descriptor);
1065  throw;
1066  }
1067 
1068  close(socket_file_descriptor);
1069  TLOG(TLVL_DEBUG) << "server terminated" ;
1070  }
1071  catch (...)
1072  {
1073  throw;
1074  }
1075 
1076 
1077  std::string xmlrpc_commander::send_register_monitor(std::string monitor_fhicl)
1078  {
1079  if (serverUrl_ == "")
1080  {
1081  std::stringstream errmsg;
1082  errmsg << "Problem attempting XML-RPC call: No server URL set!";
1083  ExceptionHandler(ExceptionHandlerRethrow::yes,
1084  errmsg.str());
1085 
1086  }
1087  xmlrpc_c::clientSimple myClient;
1088  xmlrpc_c::value result;
1089 
1090  try
1091  {
1092  myClient.call(serverUrl_, "daq.register_monitor", "s", &result, monitor_fhicl.c_str());
1093  }
1094  catch (...)
1095  {
1096  std::stringstream errmsg;
1097  errmsg << "Problem attempting XML-RPC call on host " << serverUrl_
1098  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1099  ExceptionHandler(ExceptionHandlerRethrow::yes,
1100  errmsg.str());
1101  }
1102 
1103  return xmlrpc_c::value_string(result);
1104  }
1105 
1106  std::string xmlrpc_commander::send_unregister_monitor(std::string monitor_label)
1107  {
1108  if (serverUrl_ == "")
1109  {
1110  std::stringstream errmsg;
1111  errmsg << "Problem attempting XML-RPC call: No server URL set!";
1112  ExceptionHandler(ExceptionHandlerRethrow::yes,
1113  errmsg.str());
1114 
1115  }
1116 
1117  xmlrpc_c::clientSimple myClient;
1118  xmlrpc_c::value result;
1119 
1120  try
1121  {
1122  myClient.call(serverUrl_, "daq.unregister_monitor", "s", &result, monitor_label.c_str());
1123  }
1124  catch (...)
1125  {
1126  std::stringstream errmsg;
1127  errmsg << "Problem attempting to unregister monitor via XML-RPC call on host " << serverUrl_
1128  << "; possible causes are that the monitor label \""
1129  << monitor_label
1130  << "\" is unrecognized by contacted process or process at requested port doesn't exist";
1131  ExceptionHandler(ExceptionHandlerRethrow::no, errmsg.str());
1132  }
1133 
1134  return xmlrpc_c::value_string(result);
1135 
1136  }
1137 } // namespace artdaq
1138 
1139 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.
rollover_subrun_(xmlrpc_commander &c)
shutdown_ Constructor
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:434
virtual std::string do_trace_get(std::string const &)
Get the TRACE mask for the given trace name.
Definition: Commandable.cc:405
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:272
std::string exception_msg(const std::runtime_error &er, const std::string &helpText="execute request")
Write an exception message.
static const uint64_t defaultSequenceID
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:484
virtual bool do_rollover_subrun(uint64_t eventNum)
Perform the rollover_subrun transition.
Definition: Commandable.cc:490
std::vector< std::string > legal_commands() const
Get the legal transition commands from the current state.
Definition: Commandable.cc:285
rollover_subrun_ Command class
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:166