artdaq  v3_04_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 (app_name + "_xmlrpc_commander").c_str()
22 #include "artdaq/DAQdata/Globals.hh"
23 #include "tracemf.h"
24 
25 #include "artdaq-core/Utilities/ExceptionHandler.hh"
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <errno.h>
29 #include <cstring>
30 #include <exception>
31 
32 #include "canvas/Persistency/Provenance/RunID.h"
33 #include "fhiclcpp/make_ParameterSet.h"
34 
35 #include "artdaq/ExternalComms/xmlrpc_commander.hh"
36  //#include "artdaq/Application/LoadParameterSet.hh"
37 
38 namespace {
42  class env_wrap {
43  public:
44  env_wrap() { xmlrpc_env_init(&this->env_c); };
45  ~env_wrap() { xmlrpc_env_clean(&this->env_c); };
46  xmlrpc_env env_c;
47  };
48 } // namespace
49 static xmlrpc_c::paramList
50 pListFromXmlrpcArray(xmlrpc_value * const arrayP)
51 {
52  env_wrap env;
53  XMLRPC_ASSERT_ARRAY_OK(arrayP);
54  unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP);
55  assert(!env.env_c.fault_occurred);
56  xmlrpc_c::paramList paramList(arraySize);
57  for (unsigned int i = 0; i < arraySize; ++i) {
58  xmlrpc_value * arrayItemP;
59  xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP);
60  assert(!env.env_c.fault_occurred);
61  paramList.add(xmlrpc_c::value(arrayItemP));
62  xmlrpc_DECREF(arrayItemP);
63  }
64  return paramList;
65 }
66 static xmlrpc_value *
67 c_executeMethod(xmlrpc_env * const envP,
68  xmlrpc_value * const paramArrayP,
69  void * const methodPtr,
70  void * const callInfoPtr)
71 {
72  xmlrpc_c::method * const methodP(static_cast<xmlrpc_c::method *>(methodPtr));
73  xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP));
74  xmlrpc_c::callInfo * const callInfoP(static_cast<xmlrpc_c::callInfo *>(callInfoPtr));
75  xmlrpc_value * retval;
76  retval = NULL; // silence used-before-set warning
77  try {
78  xmlrpc_c::value result;
79  try {
80  xmlrpc_c::method2 * const method2P(dynamic_cast<xmlrpc_c::method2 *>(methodP));
81  if (method2P)
82  method2P->execute(paramList, callInfoP, &result);
83  else
84  methodP->execute(paramList, &result);
85  }
86  catch (xmlrpc_c::fault const& fault) {
87  xmlrpc_env_set_fault(envP, fault.getCode(),
88  fault.getDescription().c_str());
89  }
90  if (!envP->fault_occurred) {
91  if (result.isInstantiated())
92  retval = result.cValue();
93  else
94  girerr::throwf("Xmlrpc-c user's xmlrpc_c::method object's "
95  "'execute method' failed to set the RPC result "
96  "value.");
97  }
98  }
99  catch (std::exception const& e) {
100  xmlrpc_faultf(envP, "Unexpected error executing code for "
101  "particular method, detected by Xmlrpc-c "
102  "method registry code. Method did not "
103  "fail; rather, it did not complete at all. %s",
104  e.what());
105  }
106  catch (...) {
107  xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
108  "Unexpected error executing code for "
109  "particular method, detected by Xmlrpc-c "
110  "method registry code. Method did not "
111  "fail; rather, it did not complete at all.");
112  }
113  return retval;
114 }
115 
116 
117 
118 namespace artdaq
119 {
126  std::string exception_msg(const std::runtime_error& er,
127  const std::string& helpText = "execute request")
128  {
129  std::string msg("Exception when trying to ");
130  msg.append(helpText);
131  msg.append(": ");
132  msg.append(er.what()); //std::string(er.what ()).substr (2);
133  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
134  return msg;
135  }
136 
143  std::string exception_msg(const art::Exception& er,
144  const std::string& helpText)
145  {
146  std::string msg("Exception when trying to ");
147  msg.append(helpText);
148  msg.append(": ");
149  msg.append(er.what());
150  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
151  return msg;
152  }
153 
160  std::string exception_msg(const cet::exception& er,
161  const std::string& helpText)
162  {
163  std::string msg("Exception when trying to ");
164  msg.append(helpText);
165  msg.append(": ");
166  msg.append(er.what());
167  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
168  return msg;
169  }
170 
177  std::string exception_msg(const std::string& erText,
178  const std::string& helpText)
179  {
180  std::string msg("Exception when trying to ");
181  msg.append(helpText);
182  msg.append(": ");
183  msg.append(erText);
184  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
185  return msg;
186  }
187 
188 
206  class cmd_ : public xmlrpc_c::method
207  {
208  public:
209 
210  // Can't seem to initialize "_signature" and "_help" in the initialization list...
217  cmd_(xmlrpc_commander& c, const std::string& signature, const std::string& description) : _c(c)
218  {
219  _signature = signature;
220  _help = description;
221  }
222 
228  void execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP) final;
229 
230  protected:
231 
233 
239  virtual bool execute_(const xmlrpc_c::paramList&, xmlrpc_c::value* const retvalP) = 0;
240 
250  template <typename T>
251  T getParam(const xmlrpc_c::paramList& paramList, int index);
252 
276  template <typename T>
277  T getParam(const xmlrpc_c::paramList& paramList, int index, T default_value);
278  };
279 
280  // Users are only allowed to call getParam for predefined types; see
281  // template specializations below this default function
282 
283  template <typename T>
284  T cmd_::getParam(const xmlrpc_c::paramList&, int)
285  {
286  throw cet::exception("cmd_") << "Error in cmd_::getParam(): value type not supported" << std::endl;
287  }
288 
297  template <>
298  uint64_t cmd_::getParam<uint64_t>(const xmlrpc_c::paramList& paramList, int index)
299  {
300  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as uint64_t.";
301  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
302  return boost::lexical_cast<uint64_t>(paramList.getString(index));
303  }
304 
313  template <>
314  std::string cmd_::getParam<std::string>(const xmlrpc_c::paramList& paramList, int index)
315  {
316  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as string.";
317  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
318  return static_cast<std::string>(paramList.getString(index));
319  }
320 
329  template <>
330  art::RunID cmd_::getParam<art::RunID>(const xmlrpc_c::paramList& paramList, int index)
331  {
332  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as Run Number.";
333  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
334  std::string run_number_string = paramList.getString(index);
335  art::RunNumber_t run_number =
336  boost::lexical_cast<art::RunNumber_t>(run_number_string);
337  art::RunID run_id(run_number);
338 
339  return run_id;
340  }
341 
350  template <>
351  fhicl::ParameterSet cmd_::getParam<fhicl::ParameterSet>(const xmlrpc_c::paramList& paramList, int index)
352  {
353  TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as ParameterSet.";
354  TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index);
355  std::string configString = std::string(paramList.getString(index).c_str());
356  TLOG(TLVL_DEBUG) << "Loading Parameter Set from string: " << configString << std::endl;
357  fhicl::ParameterSet pset;
358 
359  try
360  {
361  fhicl::make_ParameterSet(configString, pset);
362  }
363  catch (fhicl::exception e)
364  {
365  if (getenv("FHICL_FILE_PATH") == nullptr)
366  {
367  std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
368  setenv("FHICL_FILE_PATH", ".", 0);
369  }
370  cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH");
371  fhicl::make_ParameterSet(configString, lookup_policy, pset);
372  }
373 
374  TLOG(TLVL_INFO) << "Parameter Set Loaded." << std::endl;
375  return pset;
376  }
377 
378  template <typename T>
379  T cmd_::getParam(const xmlrpc_c::paramList& paramList, int index,
380  T default_value)
381  {
382  T val = default_value;
383 
384  try
385  {
386  val = getParam<T>(paramList, index);
387  }
388  catch (const cet::exception& exception)
389  {
390  throw exception;
391  }
392  catch (...) {}
393 
394  return val;
395  }
396 
397  void cmd_::execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP)
398  {
399  std::unique_lock<std::timed_mutex> lk(_c.mutex_, std::chrono::milliseconds(250));
400  if (lk.owns_lock())
401  {
402  try
403  {
404  // JCF, 9/4/14
405 
406  // Assuming the execute_ function returns true, then if the
407  // retvalP argument was untouched, assign it the string
408  // "Success"
409 
410  // See
411  // http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#isinstantiated
412  // for more on the concept of instantiation in xmlrpc_c::value objects
413 
414  if (execute_(paramList, retvalP))
415  {
416  if (!retvalP->isInstantiated())
417  {
418  *retvalP = xmlrpc_c::value_string("Success");
419  }
420  }
421  else
422  {
423  std::string problemReport = _c._commandable.report("transition_status");
424  *retvalP = xmlrpc_c::value_string(problemReport);
425  }
426  }
427  catch (std::runtime_error& er)
428  {
429  std::string msg = exception_msg(er, _help);
430  *retvalP = xmlrpc_c::value_string(msg);
431  TLOG(TLVL_ERROR) << msg;
432  }
433  catch (art::Exception& er)
434  {
435  std::string msg = exception_msg(er, _help);
436  *retvalP = xmlrpc_c::value_string(msg);
437  TLOG(TLVL_ERROR) << msg;
438  }
439  catch (cet::exception& er)
440  {
441  std::string msg = exception_msg(er, _help);
442  *retvalP = xmlrpc_c::value_string(msg);
443  TLOG(TLVL_ERROR) << msg;
444  }
445  catch (...)
446  {
447  std::string msg = exception_msg("Unknown exception", _help);
448  *retvalP = xmlrpc_c::value_string(msg);
449  TLOG(TLVL_ERROR) << msg;
450  }
451  }
452  else
453  {
454  *retvalP = xmlrpc_c::value_string("busy");
455  }
456  }
457 
458 
460 
461  // JCF, 9/5/14
462 
463  // The three "init" transitions all take a FHiCL parameter list, and
464  // optionally a timeout and a timestamp; thus we can kill three birds
465  // with one stone in the GENERATE_INIT_TRANSITION macro
466 
467 #define GENERATE_INIT_TRANSITION(NAME, CALL, DESCRIPTION) \
468  \
469  class NAME ## _: public cmd_ { \
470  \
471  public: \
472  \
475  explicit NAME ## _(xmlrpc_commander& c): \
476  cmd_(c, "s:sii", DESCRIPTION) {} \
477  \
478  \
479  static const uint64_t defaultTimeout = 45; \
480  \
481  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
482  \
483  private: \
484  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP ) { \
485  fhicl::ParameterSet ps; \
486  try { \
487  ps = getParam<fhicl::ParameterSet>(paramList, 0); \
488  } catch (...) { \
489  *retvalP = xmlrpc_c::value_string ("The "#NAME" message requires a single argument that is a string containing the initialization ParameterSet"); \
490  return true; \
491  } \
492  \
493  return _c._commandable.CALL(ps, \
494  getParam<uint64_t>(paramList, 1, defaultTimeout), \
495  getParam<uint64_t>(paramList, 2, defaultTimestamp) \
496  ); \
497  } \
498  };
499 
500  GENERATE_INIT_TRANSITION(init, initialize, "initialize the program")
501 
502  GENERATE_INIT_TRANSITION(soft_init, soft_initialize, "initialize software components in the program")
503 
504  GENERATE_INIT_TRANSITION(reinit, reinitialize, "re-initialize the program")
505 
506 #undef GENERATE_INIT_TRANSITION
507 
509 
513  class start_ : public cmd_
514  {
515  public:
520  explicit start_(xmlrpc_commander& c) :
521  cmd_(c, "s:iii", "start the run")
522  {}
523 
525  static const uint64_t defaultTimeout = 45;
527  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max();
528 
529  private:
530 
531  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) override
532  {
533  try
534  {
535  getParam<art::RunID>(paramList, 0);
536  }
537  catch (...)
538  {
539  *retvalP = xmlrpc_c::value_string("The start message requires the run number as an argument.");
540  return true;
541  }
542 
543  return _c._commandable.start(getParam<art::RunID>(paramList, 0),
544  getParam<uint64_t>(paramList, 1, defaultTimeout),
545  getParam<uint64_t>(paramList, 2, defaultTimestamp)
546  );
547  }
548  };
549 
550 
552 
553  // JCF, 9/5/14
554 
555  // "pause", "resume" and "stop" all take an optional timeout and
556  // timestamp parameter, so we can generate them all with the
557  // GENERATE_TIMEOUT_TIMESTAMP_TRANSITION macro
558 
559 #define GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(NAME, CALL, DESCRIPTION, TIMEOUT) \
560  \
561  class NAME ## _: public cmd_ { \
562  \
563 public: \
564  \
566  NAME ## _(xmlrpc_commander& c): \
567  cmd_(c, "s:ii", DESCRIPTION) {} \
568  \
569  \
570  static const uint64_t defaultTimeout = TIMEOUT ; \
571  \
572  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
573  \
574 private: \
575  \
576  bool execute_ (const xmlrpc_c::paramList& paramList , xmlrpc_c::value* const ) { \
577  \
578  return _c._commandable.CALL( getParam<uint64_t>(paramList, 0, defaultTimeout), \
579  getParam<uint64_t>(paramList, 1, defaultTimestamp) \
580  ); \
581  } \
582  };
583 
584  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(pause, pause, "pause the program", 45)
585 
586  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(resume, resume, "resume the program", 45)
587 
588  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(stop, stop, "stop the program", 45)
589 
590 #undef GENERATE_TIMEOUT_TIMESTAMP_TRANSITION
591 
592 
596  class shutdown_ : public cmd_
597  {
598  public:
604  cmd_(c, "s:i", "shutdown the program")
605  {}
606 
608  static const uint64_t defaultTimeout = 45;
609 
610  private:
611 
612  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
613  {
614  auto ret = _c._commandable.shutdown(getParam<uint64_t>(paramList, 0, defaultTimeout));
615 
616 #if 1
617  if (_c.server) _c.server->terminate();
618 #endif
619 
620  return ret;
621  }
622  };
623 
624 
628  class status_ : public cmd_
629  {
630  public:
636  cmd_(c, "s:n", "report the current state")
637  {}
638 
639  private:
640 
641  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
642  {
643  *retvalP = xmlrpc_c::value_string(_c._commandable.status());
644  return true;
645  }
646  };
647 
648 
652  class report_ : public cmd_
653  {
654  public:
660  cmd_(c, "s:s", "report statistics")
661  {}
662 
663  private:
664  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
665  {
666  try
667  {
668  getParam<std::string>(paramList, 0);
669  }
670  catch (...)
671  {
672  *retvalP = xmlrpc_c::value_string("The report message requires a single argument that selects the type of statistics to be reported.");
673  return true;
674  }
675 
676  *retvalP = xmlrpc_c::value_string(_c._commandable.report(getParam<std::string>(paramList, 0)));
677  return true;
678  }
679  };
680 
684  class legal_commands_ : public cmd_
685  {
686  public:
692  cmd_(c, "s:n", "return the currently legal commands")
693  {}
694 
695  private:
696  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
697  {
698  std::vector<std::string> cmdList = _c._commandable.legal_commands();
699  std::string resultString;
700 
701  for (auto& cmd : cmdList)
702  {
703  resultString.append(cmd + " ");
704  if (cmd == "shutdown")
705  {
706  resultString.append(" reset");
707  }
708  }
709  *retvalP = xmlrpc_c::value_string(resultString);
710 
711  return true;
712  }
713  };
714 
718  class register_monitor_ : public cmd_
719  {
720  public:
726  cmd_(c, "s:s", "Get notified of a new monitor")
727  {}
728 
729  private:
730  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
731  {
732  try
733  {
734  getParam<fhicl::ParameterSet>(paramList, 0);
735  }
736  catch (...)
737  {
738  *retvalP = xmlrpc_c::value_string("The register_monitor command expects a string representing the FHiCL definition of a Transfer plugin");
739  return true;
740  }
741 
742  *retvalP = xmlrpc_c::value_string(_c._commandable.register_monitor(getParam<fhicl::ParameterSet>(paramList, 0)));
743  return true;
744  }
745  };
746 
750  class unregister_monitor_ : public cmd_
751  {
752  public:
758  cmd_(c, "s:s", "Remove a monitor")
759  {}
760 
761  private:
762  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
763  {
764  try
765  {
766  getParam<std::string>(paramList, 0);
767  }
768  catch (...)
769  {
770  *retvalP = xmlrpc_c::value_string("The unregister_monitor command expects a string representing the label of the monitor to be removed");
771  return true;
772  }
773 
774  *retvalP = xmlrpc_c::value_string(_c._commandable.unregister_monitor(getParam<std::string>(paramList, 0)));
775  return true;
776  }
777  };
778 
779 
783  class trace_set_ : public cmd_
784  {
785  public:
791  cmd_(c, "s:ssi", "Set TRACE mask")
792  {}
793 
794  private:
795  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
796  {
797  try
798  {
799  getParam<std::string>(paramList, 0);
800  getParam<std::string>(paramList, 1);
801  getParam<uint64_t>(paramList, 2);
802  }
803  catch (...)
804  {
805  *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");
806  return true;
807  }
808 
809  return _c._commandable.do_trace_set(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1), getParam<uint64_t>(paramList, 2));
810  }
811  };
812 
816  class trace_get_ : public cmd_
817  {
818  public:
824  cmd_(c, "s:s", "Get TRACE mask")
825  {}
826 
827  private:
828  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
829  {
830  try
831  {
832  getParam<std::string>(paramList, 0);
833  }
834  catch (...)
835  {
836  *retvalP = xmlrpc_c::value_string("The trace_msgfacility_set command expects a name (ALL for all)");
837  return true;
838  }
839 
840  *retvalP = xmlrpc_c::value_string(_c._commandable.do_trace_get(getParam<std::string>(paramList, 0)));
841  return true;
842  }
843  };
844 
848  class meta_command_ : public cmd_
849  {
850  public:
856  cmd_(c, "s:ss", "Run custom command")
857  {}
858 
859  private:
860  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
861  {
862  try
863  {
864  getParam<std::string>(paramList, 0);
865  getParam<std::string>(paramList, 1);
866  }
867  catch (...)
868  {
869  *retvalP = xmlrpc_c::value_string("The meta_command command expects a string command and a string argument");
870  return true;
871  }
872 
873  return _c._commandable.do_meta_command(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1));
874  }
875  };
876 
880  class rollover_subrun_ : public cmd_
881  {
882  public:
888  cmd_(c, "s:ii", "create a new subrun")
889  {}
890 
892  static const uint64_t defaultSequenceID = 0xFFFFFFFFFFFFFFFF;
893  static const uint32_t defaultSubrunNumber = 1;
894 
895  private:
896 
897  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
898  {
899  auto ret = _c._commandable.do_rollover_subrun(getParam<uint64_t>(paramList, 0, defaultSequenceID), getParam<uint32_t>(paramList, 1, defaultSubrunNumber));
900  return ret;
901  }
902  };
903 
908  {
909  public:
915  cmd_(c, "s:ss", "Add an entry to the configuration archive list")
916  {}
917 
918  private:
919  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
920  {
921  try
922  {
923  getParam<std::string>(paramList, 0);
924  getParam<std::string>(paramList, 1);
925  }
926  catch (...)
927  {
928  *retvalP = xmlrpc_c::value_string("The add_config_archive_entry command expects a string key and a string value");
929  return true;
930  }
931 
932  return _c._commandable.do_add_config_archive_entry(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1));
933  }
934  };
935 
940  {
941  public:
947  cmd_(c, "s:n", "Clear the configuration archive list")
948  {}
949 
950  private:
951  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const)
952  {
954  }
955  };
956 
957  // JCF, 9/4/14
958 
959  // Not sure if anyone was planning to resurrect this code by changing
960  // the preprocessor decision; as such, I'll leave it in for now...
961 
962 #if 0
963  class shutdown_ : public xmlrpc_c::registry::shutdown
964  {
965  public:
966  shutdown_(xmlrpc_c::serverAbyss *server) : _server(server) {}
967 
968  virtual void doit(const std::string& paramString, void*) const
969  {
970  TLOG(TLVL_INFO) << "A shutdown command was sent "
971  << "with parameter "
972  << paramString << "\"";
973  _server->terminate();
974  }
975  private:
976  xmlrpc_c::serverAbyss *_server;
977  };
978 #endif
979 
980 
981 
982  xmlrpc_commander::xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable& commandable)
983  : CommanderInterface(ps, commandable)
984  , port_(ps.get<int>("id", 0))
985  , serverUrl_(ps.get<std::string>("server_url", ""))
986  , server(nullptr)
987  {
988  TLOG(TLVL_INFO) << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_;
989  if (serverUrl_.find("http") == std::string::npos)
990  {
991  serverUrl_ = "http://" + serverUrl_;
992  }
993  if (serverUrl_.find(std::to_string(port_)) == std::string::npos && serverUrl_.find(':', 7) == std::string::npos)
994  {
995  serverUrl_ = serverUrl_ + ":" + std::to_string(port_);
996  }
997  if (serverUrl_.find("RPC2") == std::string::npos)
998  {
999  serverUrl_ = serverUrl_ + "/RPC2";
1000  }
1001  TLOG(TLVL_INFO) << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_;
1002 
1003  }
1004 
1006  {
1007  //std::cout << "XMLRPC_COMMANDER RUN_SERVER CALLED!" << std::endl;
1008  xmlrpc_c::registry registry;
1009  struct xmlrpc_method_info3 methodInfo;
1010  memset(&methodInfo, 0, sizeof(methodInfo));
1011 
1012  /*#define register_method(m) \
1013  // xmlrpc_c::methodPtr const ptr_ ## m(new m ## _(*this));\
1014  registry.addMethod ("daq." #m, ptr_ ## m) */
1015 #define register_method(m) register_method2(m,0x400000)
1016 
1017  xmlrpc_env env; // xmlrpc_env_init(&env);
1018  xmlrpc_registry ***c_registryPPP;
1019  c_registryPPP = (xmlrpc_registry ***)(((char*)&registry) + sizeof(girmem::autoObject));
1020 
1021 #define register_method2(m,ss) \
1022  xmlrpc_c::method* ptr_ ## m(dynamic_cast<xmlrpc_c::method*>(new m ## _(*this))); \
1023  std::string m##signature = ptr_ ## m->signature(), m##help = ptr_ ## m->help(); \
1024  methodInfo.methodName = "daq." #m; \
1025  methodInfo.methodFunction = &c_executeMethod; \
1026  methodInfo.serverInfo = ptr_ ## m; \
1027  methodInfo.stackSize = ss; \
1028  methodInfo.signatureString = &m##signature[0]; \
1029  methodInfo.help = &m##help[0]; \
1030  xmlrpc_env_init(&env); \
1031  xmlrpc_registry_add_method3(&env,**c_registryPPP,&methodInfo); \
1032  if(env.fault_occurred)throw(girerr::error(env.fault_string)); \
1033  xmlrpc_env_clean(&env)
1034 
1035  register_method2(init, 0x200000);
1036  register_method(soft_init);
1037  register_method(reinit);
1038  register_method(start);
1039  register_method(status);
1040  register_method(report);
1041  register_method(stop);
1042  register_method(pause);
1043  register_method(resume);
1044  register_method(register_monitor);
1045  register_method(unregister_monitor);
1046  register_method(legal_commands);
1047  register_method(trace_set);
1048  register_method(trace_get);
1049  register_method(meta_command);
1050  register_method(rollover_subrun);
1051  register_method(add_config_archive_entry);
1052  register_method(clear_config_archive);
1053 
1054  register_method(shutdown);
1055 
1056  // alias "daq.reset" to the internal shutdown transition
1057  xmlrpc_c::methodPtr const ptr_reset(new shutdown_(*this));
1058  registry.addMethod("daq.reset", ptr_reset);
1059 
1060 #undef register_method
1061 
1062  // JCF, 6/3/15
1063 
1064  // In the following code, I configure a socket to have the
1065  // SO_REUSEADDR option so that once an artdaq process closes, the
1066  // port it was communicating on becomes immediately available
1067  // (desirable if, say, the DAQ program is terminated and then
1068  // immediately restarted)
1069 
1070  // Much of the following code is cribbed from
1071  // http://fossies.org/linux/freeswitch/libs/xmlrpc-c/src/cpp/test/server_abyss.cpp
1072 
1073  // Below, "0" is the default protocol (in this case, given the IPv4
1074  // Protocol Family (PF_INET) and the SOCK_STREAM communication
1075  // method)
1076 
1077  XMLRPC_SOCKET socket_file_descriptor = socket(PF_INET, SOCK_STREAM, 0);
1078 
1079  if (socket_file_descriptor < 0)
1080  {
1081  throw cet::exception("xmlrpc_commander::run") <<
1082  "Problem with the socket() call; C-style errno == " <<
1083  errno << " (" << strerror(errno) << ")";
1084  }
1085 
1086  int enable = 1;
1087  int retval = setsockopt(socket_file_descriptor,
1088  SOL_SOCKET, SO_REUSEADDR,
1089  &enable, sizeof(int));
1090 
1091  if (retval < 0)
1092  {
1093  throw cet::exception("xmlrpc_commander::run") <<
1094  "Problem with the call to setsockopt(); C-style errno == " <<
1095  errno << " (" << strerror(errno) << ")";
1096  }
1097 
1098  struct sockaddr_in sockAddr;
1099 
1100  sockAddr.sin_family = AF_INET;
1101  sockAddr.sin_port = htons(port_);
1102  sockAddr.sin_addr.s_addr = 0;
1103 
1104  retval = bind(socket_file_descriptor,
1105  reinterpret_cast<struct sockaddr*>(&sockAddr),
1106  sizeof(sockAddr));
1107 
1108  if (retval != 0)
1109  {
1110  close(socket_file_descriptor);
1111  throw cet::exception("xmlrpc_commander::run") <<
1112  "Problem with the bind() call; C-style errno == " <<
1113  errno << " (" << strerror(errno) << ")";
1114  }
1115 
1116  server.reset(new xmlrpc_c::serverAbyss(xmlrpc_c::serverAbyss::constrOpt().registryP(&registry).socketFd(socket_file_descriptor)));
1117 
1118 #if 0
1119  xmlrpc_c::serverAbyss::shutdown shutdown_obj(&server);
1120  registry.setShutdown(&shutdown_obj);
1121 #endif
1122 
1123  TLOG(TLVL_DEBUG) << "running server";
1124 
1125  // JCF, 6/3/15
1126 
1127  // Use a catch block to clean up (i.e., close the socket). An
1128  // opportunity for RAII, although all control paths are limited to
1129  // this section of the file...
1130 
1131  try
1132  {
1133  running_ = true;
1134  server->run();
1135  running_ = false;
1136  }
1137  catch (...)
1138  {
1139  TLOG(TLVL_WARNING) << "server threw an exception; closing the socket and rethrowing";
1140  running_ = false;
1141  close(socket_file_descriptor);
1142  throw;
1143  }
1144 
1145  close(socket_file_descriptor);
1146  TLOG(TLVL_DEBUG) << "server terminated";
1147  }
1148  catch (...)
1149  {
1150  throw;
1151  }
1152 
1153  std::string xmlrpc_commander::send_command_(std::string command)
1154  {
1155  if (serverUrl_ == "")
1156  {
1157  std::stringstream errmsg;
1158  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1159  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1160 
1161  }
1162  xmlrpc_c::clientSimple myClient;
1163  xmlrpc_c::value result;
1164 
1165  try
1166  {
1167  myClient.call(serverUrl_, "daq." + command, "", &result);
1168  }
1169  catch (...)
1170  {
1171  std::stringstream errmsg;
1172  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1173  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1174  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1175  }
1176 
1177  return xmlrpc_c::value_string(result);
1178  }
1179 
1180  std::string xmlrpc_commander::send_command_(std::string command, std::string arg)
1181  {
1182  if (serverUrl_ == "")
1183  {
1184  std::stringstream errmsg;
1185  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1186  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1187 
1188  }
1189  xmlrpc_c::clientSimple myClient;
1190  xmlrpc_c::value result;
1191 
1192  try
1193  {
1194  myClient.call(serverUrl_, "daq." + command, "s", &result, arg.c_str());
1195  }
1196  catch (...)
1197  {
1198  std::stringstream errmsg;
1199  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1200  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1201  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1202  }
1203 
1204  return xmlrpc_c::value_string(result);
1205  }
1206 
1207  std::string xmlrpc_commander::send_command_(std::string command, fhicl::ParameterSet pset, uint64_t timestamp, uint64_t timeout)
1208  {
1209  if (serverUrl_ == "")
1210  {
1211  std::stringstream errmsg;
1212  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1213  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1214 
1215  }
1216  xmlrpc_c::clientSimple myClient;
1217  xmlrpc_c::value result;
1218 
1219  try
1220  {
1221  myClient.call(serverUrl_, "daq." + command, "sii", &result, pset.to_string().c_str(), timestamp, timeout);
1222  }
1223  catch (...)
1224  {
1225  std::stringstream errmsg;
1226  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1227  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1228  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1229  }
1230 
1231  return xmlrpc_c::value_string(result);
1232  }
1233 
1234  std::string artdaq::xmlrpc_commander::send_command_(std::string command, uint64_t a, uint64_t b)
1235  {
1236  if (serverUrl_ == "")
1237  {
1238  std::stringstream errmsg;
1239  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1240  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1241 
1242  }
1243  xmlrpc_c::clientSimple myClient;
1244  xmlrpc_c::value result;
1245 
1246  try
1247  {
1248  myClient.call(serverUrl_, "daq." + command, "ii", &result, a,b);
1249  }
1250  catch (...)
1251  {
1252  std::stringstream errmsg;
1253  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1254  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1255  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1256  }
1257 
1258  return xmlrpc_c::value_string(result);
1259  }
1260 
1261  std::string artdaq::xmlrpc_commander::send_command_(std::string command, art::RunID r, uint64_t a, uint64_t b)
1262  {
1263  if (serverUrl_ == "")
1264  {
1265  std::stringstream errmsg;
1266  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1267  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1268 
1269  }
1270  xmlrpc_c::clientSimple myClient;
1271  xmlrpc_c::value result;
1272 
1273  try
1274  {
1275  myClient.call(serverUrl_, "daq." + command, "iii", &result, r, a, b);
1276  }
1277  catch (...)
1278  {
1279  std::stringstream errmsg;
1280  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1281  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1282  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1283  }
1284 
1285  return xmlrpc_c::value_string(result);
1286  }
1287 
1288  std::string artdaq::xmlrpc_commander::send_command_(std::string command, uint64_t arg1)
1289  {
1290  if (serverUrl_ == "")
1291  {
1292  std::stringstream errmsg;
1293  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1294  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1295 
1296  }
1297  xmlrpc_c::clientSimple myClient;
1298  xmlrpc_c::value result;
1299 
1300  try
1301  {
1302  myClient.call(serverUrl_, "daq." + command, "i", &result, arg1);
1303  }
1304  catch (...)
1305  {
1306  std::stringstream errmsg;
1307  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1308  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1309  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1310  }
1311 
1312  return xmlrpc_c::value_string(result);
1313  }
1314 
1315  std::string artdaq::xmlrpc_commander::send_command_(std::string command, std::string arg1, std::string arg2)
1316  {
1317  if (serverUrl_ == "")
1318  {
1319  std::stringstream errmsg;
1320  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1321  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1322 
1323  }
1324  xmlrpc_c::clientSimple myClient;
1325  xmlrpc_c::value result;
1326 
1327  try
1328  {
1329  myClient.call(serverUrl_, "daq." + command, "ss", &result, arg1.c_str(), arg2.c_str());
1330  }
1331  catch (...)
1332  {
1333  std::stringstream errmsg;
1334  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1335  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1336  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1337  }
1338 
1339  return xmlrpc_c::value_string(result);
1340  }
1341 
1342  std::string artdaq::xmlrpc_commander::send_command_(std::string command, std::string arg1, std::string arg2, uint64_t arg3)
1343  {
1344  if (serverUrl_ == "")
1345  {
1346  std::stringstream errmsg;
1347  errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!";
1348  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1349 
1350  }
1351  xmlrpc_c::clientSimple myClient;
1352  xmlrpc_c::value result;
1353 
1354  try
1355  {
1356  myClient.call(serverUrl_, "daq." + command, "ssi", &result, arg1.c_str(), arg2.c_str(), arg3);
1357  }
1358  catch (...)
1359  {
1360  std::stringstream errmsg;
1361  errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_
1362  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
1363  ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str());
1364  }
1365 
1366  return xmlrpc_c::value_string(result);
1367  }
1368 
1369  std::string xmlrpc_commander::send_register_monitor(std::string monitor_fhicl)
1370  {
1371  return send_command_("register_monitor", monitor_fhicl);
1372  }
1373  std::string xmlrpc_commander::send_unregister_monitor(std::string monitor_label)
1374  {
1375  return send_command_("unregister_monitor", monitor_label);
1376  }
1377  std::string artdaq::xmlrpc_commander::send_init(fhicl::ParameterSet ps, uint64_t a, uint64_t b)
1378  {
1379  return send_command_("init", ps, a, b);
1380  }
1381  std::string artdaq::xmlrpc_commander::send_soft_init(fhicl::ParameterSet ps, uint64_t a, uint64_t b)
1382  {
1383  return send_command_("soft_init", ps, a, b);
1384  }
1385  std::string xmlrpc_commander::send_reinit(fhicl::ParameterSet ps, uint64_t a, uint64_t b)
1386  {
1387  return send_command_("reinit", ps, a, b);
1388  }
1389  std::string xmlrpc_commander::send_start(art::RunID r, uint64_t a, uint64_t b)
1390  {
1391  return send_command_("start", r, a, b);
1392  }
1393  std::string xmlrpc_commander::send_pause(uint64_t a, uint64_t b)
1394  {
1395  return send_command_("pause", a, b);
1396  }
1397  std::string xmlrpc_commander::send_resume(uint64_t a, uint64_t b)
1398  {
1399  return send_command_("resume", a, b);
1400  }
1401  std::string xmlrpc_commander::send_stop(uint64_t a, uint64_t b)
1402  {
1403  return send_command_("stop", a, b);
1404  }
1405  std::string xmlrpc_commander::send_shutdown(uint64_t a)
1406  {
1407  return send_command_("shutdown", a);
1408  }
1410  {
1411  return send_command_("status");
1412  }
1413  std::string xmlrpc_commander::send_report(std::string what)
1414  {
1415  return send_command_("report", what);
1416  }
1418  {
1419  return send_command_("legal_commands");
1420  }
1421  std::string xmlrpc_commander::send_trace_get(std::string name)
1422  {
1423  return send_command_("trace_get", name);
1424  }
1425  std::string xmlrpc_commander::send_trace_set(std::string name, std::string which, uint64_t mask)
1426  {
1427  return send_command_("trace_set", name, which, mask);
1428  }
1429  std::string xmlrpc_commander::send_meta_command(std::string command, std::string arg)
1430  {
1431  return send_command_("meta_command", command, arg);
1432  }
1433  std::string xmlrpc_commander::send_rollover_subrun(uint64_t when, uint32_t sr)
1434  {
1435  return send_command_("rollover_subrun", when, sr);
1436  }
1437 } // namespace artdaq
1438 
1439 DEFINE_ARTDAQ_COMMANDER(artdaq::xmlrpc_commander)
virtual bool do_add_config_archive_entry(std::string const &, std::string const &)
Add the specified key-value pair to the configuration archive list.
Definition: Commandable.cc:497
std::string send_stop(uint64_t, uint64_t) override
Send a stop command over XMLRPC
std::string send_shutdown(uint64_t) override
Send a shutdown command over XMLRPC
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
virtual bool do_clear_config_archive()
Clears the configuration archive list.
Definition: Commandable.cc:503
xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable &commandable)
xmlrpc_commander Constructor
Command class representing a start transition.
rollover_subrun_(xmlrpc_commander &c)
shutdown_ Constructor
std::string send_soft_init(fhicl::ParameterSet, uint64_t, uint64_t) override
Send a soft_init command over XMLRPC
status_ Command class
report_ Command class
std::string send_pause(uint64_t, uint64_t) override
Send a pause command over XMLRPC
virtual std::string clear_config_archive()
Using the transport mechanism, send a clear_config_archive command
virtual std::string unregister_monitor(std::string const &)
Perform the unregister_monitor action.
Definition: Commandable.hh:150
meta_command_ Command class
std::string send_status() override
Send a status command over XMLRPC
std::string send_legal_commands() override
Send a legal_commands command over XMLRPC
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
std::string send_report(std::string) override
Send a report command over XMLRPC
void run_server() override
Run the XMLRPC server.
meta_command_(xmlrpc_commander &c)
meta_command_ Constructor
std::string send_meta_command(std::string, std::string) override
Send an send_meta_command command over XMLRPC
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.
virtual bool do_trace_set(std::string const &type, std::string const &name, uint64_t mask)
Set the given TRACE mask for the given TRACE name.
Definition: Commandable.cc:434
static const uint64_t defaultSequenceID
add_config_archive_entry_(xmlrpc_commander &c)
add_config_archive_entry_ Constructor
virtual std::string register_monitor(fhicl::ParameterSet const &)
Perform the register_monitor action.
Definition: Commandable.hh:139
virtual bool do_meta_command(std::string const &command, std::string const &args)
Run a module-defined command with the given parameter string.
Definition: Commandable.cc:484
register_monitor_ Command class
add_config_archive_entry_ Command class
legal_commands_ Command class
artdaq::Commandable & _commandable
Reference to the Commandable that this Commander Commands.
std::string send_trace_get(std::string) override
Send an send_trace_get command over XMLRPC
std::string send_reinit(fhicl::ParameterSet, uint64_t, uint64_t) override
Send a reinit command over XMLRPC
xmlrpc_commander & _c
The xmlrpc_commander instance that the command will be sent to.
clear_config_archive_ Command class
trace_get_ Command class
std::string send_resume(uint64_t, uint64_t) override
Send a resume command over XMLRPC
status_(xmlrpc_commander &c)
status_ Constructor
clear_config_archive_(xmlrpc_commander &c)
clear_config_archive_ 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 ...
Wrapper for XMLRPC environment construction/destruction
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
std::string send_rollover_subrun(uint64_t, uint32_t) override
Send a send_rollover_subrun command over XMLRPC
std::vector< std::string > legal_commands() const
Get the legal transition commands from the current state.
Definition: Commandable.cc:285
std::string send_start(art::RunID, uint64_t, uint64_t) override
Send a start command over XMLRPC
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
virtual std::string add_config_archive_entry(std::string, std::string)
Using the transport mechanism, send an add_config_archive_entry command
virtual std::string do_trace_get(std::string const &name)
Get the TRACE mask for the given TRACE name If name is &quot;ALL&quot;, then all TRACE masks will be printed...
Definition: Commandable.cc:405
std::string send_init(fhicl::ParameterSet, uint64_t, uint64_t) override
Send an init command over XMLRPC
trace_get_(xmlrpc_commander &c)
trace_msgfacility_set_ Constructor
std::string send_trace_set(std::string, std::string, uint64_t) override
Send an send_trace_msgfacility_set command over XMLRPC
std::atomic< bool > running_
Whether the server is running and able to respond to requests.
virtual bool do_rollover_subrun(uint64_t eventNum, uint32_t subrunNum)
Perform the rollover_subrun transition.
Definition: Commandable.cc:490
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