artdaq  v3_00_01
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  } catch (xmlrpc_c::fault const& fault) {
81  xmlrpc_env_set_fault(envP, fault.getCode(),
82  fault.getDescription().c_str());
83  }
84  if (!envP->fault_occurred) {
85  if (result.isInstantiated())
86  retval = result.cValue();
87  else
88  girerr::throwf("Xmlrpc-c user's xmlrpc_c::method object's "
89  "'execute method' failed to set the RPC result "
90  "value.");
91  }
92  } catch (std::exception const& e) {
93  xmlrpc_faultf(envP, "Unexpected error executing code for "
94  "particular method, detected by Xmlrpc-c "
95  "method registry code. Method did not "
96  "fail; rather, it did not complete at all. %s",
97  e.what());
98  } catch (...) {
99  xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
100  "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.");
104  }
105  return retval;
106 }
107 
108 
109 
110 namespace artdaq
111 {
118  std::string exception_msg(const std::runtime_error& er,
119  const std::string& helpText = "execute request")
120  {
121  std::string msg("Exception when trying to ");
122  msg.append(helpText);
123  msg.append(": ");
124  msg.append(er.what()); //std::string(er.what ()).substr (2);
125  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
126  return msg;
127  }
128 
135  std::string exception_msg(const art::Exception& er,
136  const std::string& helpText)
137  {
138  std::string msg("Exception when trying to ");
139  msg.append(helpText);
140  msg.append(": ");
141  msg.append(er.what());
142  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
143  return msg;
144  }
145 
152  std::string exception_msg(const cet::exception& er,
153  const std::string& helpText)
154  {
155  std::string msg("Exception when trying to ");
156  msg.append(helpText);
157  msg.append(": ");
158  msg.append(er.what());
159  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
160  return msg;
161  }
162 
169  std::string exception_msg(const std::string& erText,
170  const std::string& helpText)
171  {
172  std::string msg("Exception when trying to ");
173  msg.append(helpText);
174  msg.append(": ");
175  msg.append(erText);
176  if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1);
177  return msg;
178  }
179 
180 
198  class cmd_ : public xmlrpc_c::method
199  {
200  public:
201 
202  // Can't seem to initialize "_signature" and "_help" in the initialization list...
209  cmd_(xmlrpc_commander& c, const std::string& signature, const std::string& description) : _c(c)
210  {
211  _signature = signature;
212  _help = description;
213  }
214 
220  void execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP) final;
221 
222  protected:
223 
225 
231  virtual bool execute_(const xmlrpc_c::paramList&, xmlrpc_c::value* const retvalP) = 0;
232 
242  template <typename T>
243  T getParam(const xmlrpc_c::paramList& paramList, int index);
244 
268  template <typename T>
269  T getParam(const xmlrpc_c::paramList& paramList, int index, T default_value);
270  };
271 
272  // Users are only allowed to call getParam for predefined types; see
273  // template specializations below this default function
274 
275  template <typename T>
276  T cmd_::getParam(const xmlrpc_c::paramList&, int)
277  {
278  throw cet::exception("cmd_") << "Error in cmd_::getParam(): value type not supported" << std::endl;
279  }
280 
289  template <>
290  uint64_t cmd_::getParam<uint64_t>(const xmlrpc_c::paramList& paramList, int index)
291  {
292  return boost::lexical_cast<uint64_t>(paramList.getInt(index));
293  }
294 
303  template <>
304  std::string cmd_::getParam<std::string>(const xmlrpc_c::paramList& paramList, int index)
305  {
306  return static_cast<std::string>(paramList.getString(index));
307  }
308 
317  template <>
318  art::RunID cmd_::getParam<art::RunID>(const xmlrpc_c::paramList& paramList, int index)
319  {
320  std::string run_number_string = paramList.getString(index);
321  art::RunNumber_t run_number =
322  boost::lexical_cast<art::RunNumber_t>(run_number_string);
323  art::RunID run_id(run_number);
324 
325  return run_id;
326  }
327 
336  template <>
337  fhicl::ParameterSet cmd_::getParam<fhicl::ParameterSet>(const xmlrpc_c::paramList& paramList, int index)
338  {
339  std::string configString = std::string(paramList.getString(index).c_str());
340  TLOG_DEBUG("xmlrpc_commander") << "Loading Parameter Set from string: " << configString << std::endl;
341  fhicl::ParameterSet pset;
342 
343  try
344  {
345  fhicl::make_ParameterSet(configString, pset);
346  }
347  catch (fhicl::exception e)
348  {
349  if (getenv("FHICL_FILE_PATH") == nullptr)
350  {
351  std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
352  setenv("FHICL_FILE_PATH", ".", 0);
353  }
354  cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH");
355  fhicl::make_ParameterSet(configString, lookup_policy, pset);
356  }
357 
358  TLOG_INFO("xmlrpc_commander") << "Parameter Set Loaded." << std::endl;
359  return pset;
360  }
361 
362  template <typename T>
363  T cmd_::getParam(const xmlrpc_c::paramList& paramList, int index,
364  T default_value)
365  {
366  T val = default_value;
367 
368  try
369  {
370  val = getParam<T>(paramList, index);
371  }
372  catch (const cet::exception& exception)
373  {
374  throw exception;
375  }
376  catch (...) {}
377 
378  return val;
379  }
380 
381  void cmd_::execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP)
382  {
383  std::unique_lock<std::mutex> lk(_c.mutex_, std::try_to_lock);
384  if (lk.owns_lock())
385  {
386  try
387  {
388  // JCF, 9/4/14
389 
390  // Assuming the execute_ function returns true, then if the
391  // retvalP argument was untouched, assign it the string
392  // "Success"
393 
394  // See
395  // http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#isinstantiated
396  // for more on the concept of instantiation in xmlrpc_c::value objects
397 
398  if (execute_(paramList, retvalP))
399  {
400  if (!retvalP->isInstantiated())
401  {
402  *retvalP = xmlrpc_c::value_string("Success");
403  }
404  }
405  else
406  {
407  std::string problemReport = _c._commandable.report("transition_status");
408  *retvalP = xmlrpc_c::value_string(problemReport);
409  }
410  }
411  catch (std::runtime_error& er)
412  {
413  std::string msg = exception_msg(er, _help);
414  *retvalP = xmlrpc_c::value_string(msg);
415  TLOG_ERROR("XMLRPC_Commander") << msg << TLOG_ENDL;
416  }
417  catch (art::Exception& er)
418  {
419  std::string msg = exception_msg(er, _help);
420  *retvalP = xmlrpc_c::value_string(msg);
421  TLOG_ERROR("XMLRPC_Commander") << msg << TLOG_ENDL;
422  }
423  catch (cet::exception& er)
424  {
425  std::string msg = exception_msg(er, _help);
426  *retvalP = xmlrpc_c::value_string(msg);
427  TLOG_ERROR("XMLRPC_Commander") << msg << TLOG_ENDL;
428  }
429  catch (...)
430  {
431  std::string msg = exception_msg("Unknown exception", _help);
432  *retvalP = xmlrpc_c::value_string(msg);
433  TLOG_ERROR("XMLRPC_Commander") << msg << TLOG_ENDL;
434  }
435  }
436  else
437  {
438  *retvalP = xmlrpc_c::value_string("busy");
439  }
440  }
441 
442 
444 
445  // JCF, 9/5/14
446 
447  // The three "init" transitions all take a FHiCL parameter list, and
448  // optionally a timeout and a timestamp; thus we can kill three birds
449  // with one stone in the GENERATE_INIT_TRANSITION macro
450 
451 #define GENERATE_INIT_TRANSITION(NAME, CALL, DESCRIPTION) \
452  \
453  class NAME ## _: public cmd_ { \
454  \
455  public: \
456  \
459  explicit NAME ## _(xmlrpc_commander& c): \
460  cmd_(c, "s:sii", DESCRIPTION) {} \
461  \
462  \
463  static const uint64_t defaultTimeout = 45; \
464  \
465  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
466  \
467  private: \
468  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP ) { \
469  fhicl::ParameterSet ps; \
470  try { \
471  ps = getParam<fhicl::ParameterSet>(paramList, 0); \
472  } catch (...) { \
473  *retvalP = xmlrpc_c::value_string ("The "#NAME" message requires a single argument that is a string containing the initialization ParameterSet"); \
474  return true; \
475  } \
476  \
477  return _c._commandable.CALL(ps, \
478  getParam<uint64_t>(paramList, 1, defaultTimeout), \
479  getParam<uint64_t>(paramList, 2, defaultTimestamp) \
480  ); \
481  } \
482  };
483 
484  GENERATE_INIT_TRANSITION(init, initialize, "initialize the program")
485 
486  GENERATE_INIT_TRANSITION(soft_init, soft_initialize, "initialize software components in the program")
487 
488  GENERATE_INIT_TRANSITION(reinit, reinitialize, "re-initialize the program")
489 
490 #undef GENERATE_INIT_TRANSITION
491 
493 
497  class start_ : public cmd_
498  {
499  public:
504  explicit start_(xmlrpc_commander& c) :
505  cmd_(c, "s:iii", "start the run")
506  {}
507 
509  static const uint64_t defaultTimeout = 45;
511  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max();
512 
513  private:
514 
515  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) override
516  {
517  try
518  {
519  getParam<art::RunID>(paramList, 0);
520  }
521  catch (...)
522  {
523  *retvalP = xmlrpc_c::value_string("The start message requires the run number as an argument.");
524  return true;
525  }
526 
527  return _c._commandable.start(getParam<art::RunID>(paramList, 0),
528  getParam<uint64_t>(paramList, 1, defaultTimeout),
529  getParam<uint64_t>(paramList, 2, defaultTimestamp)
530  );
531  }
532  };
533 
534 
536 
537  // JCF, 9/5/14
538 
539  // "pause", "resume" and "stop" all take an optional timeout and
540  // timestamp parameter, so we can generate them all with the
541  // GENERATE_TIMEOUT_TIMESTAMP_TRANSITION macro
542 
543 #define GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(NAME, CALL, DESCRIPTION, TIMEOUT) \
544  \
545  class NAME ## _: public cmd_ { \
546  \
547 public: \
548  \
550  NAME ## _(xmlrpc_commander& c): \
551  cmd_(c, "s:ii", DESCRIPTION) {} \
552  \
553  \
554  static const uint64_t defaultTimeout = TIMEOUT ; \
555  \
556  static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \
557  \
558 private: \
559  \
560  bool execute_ (const xmlrpc_c::paramList& paramList , xmlrpc_c::value* const ) { \
561  \
562  return _c._commandable.CALL( getParam<uint64_t>(paramList, 0, defaultTimeout), \
563  getParam<uint64_t>(paramList, 1, defaultTimestamp) \
564  ); \
565  } \
566  };
567 
568  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(pause, pause, "pause the program", 45)
569 
570  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(resume, resume, "resume the program", 45)
571 
572  GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(stop, stop, "stop the program", 45)
573 
574 #undef GENERATE_TIMEOUT_TIMESTAMP_TRANSITION
575 
576 
580  class shutdown_ : public cmd_
581  {
582  public:
588  cmd_(c, "s:i", "shutdown the program")
589  {}
590 
592  static const uint64_t defaultTimeout = 45;
593 
594  private:
595 
596  bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const)
597  {
598  return _c._commandable.shutdown(getParam<uint64_t>(paramList, 0, defaultTimeout));
599  }
600  };
601 
602 
606  class status_ : public cmd_
607  {
608  public:
614  cmd_(c, "s:n", "report the current state")
615  {}
616 
617  private:
618 
619  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
620  {
621  *retvalP = xmlrpc_c::value_string(_c._commandable.status());
622  return true;
623  }
624  };
625 
626 
630  class report_ : public cmd_
631  {
632  public:
638  cmd_(c, "s:s", "report statistics")
639  {}
640 
641  private:
642  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
643  {
644  try
645  {
646  getParam<std::string>(paramList, 0);
647  }
648  catch (...)
649  {
650  *retvalP = xmlrpc_c::value_string("The report message requires a single argument that selects the type of statistics to be reported.");
651  return true;
652  }
653 
654  *retvalP = xmlrpc_c::value_string(_c._commandable.report(getParam<std::string>(paramList, 0)));
655  return true;
656  }
657  };
658 
662  class legal_commands_ : public cmd_
663  {
664  public:
670  cmd_(c, "s:n", "return the currently legal commands")
671  {}
672 
673  private:
674  bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP)
675  {
676  std::vector<std::string> cmdList = _c._commandable.legal_commands();
677  std::string resultString;
678 
679  for (auto& cmd : cmdList)
680  {
681  resultString.append(cmd + " ");
682  if (cmd == "shutdown")
683  {
684  resultString.append(" reset");
685  }
686  }
687  *retvalP = xmlrpc_c::value_string(resultString);
688 
689  return true;
690  }
691  };
692 
696  class register_monitor_ : public cmd_
697  {
698  public:
704  cmd_(c, "s:s", "Get notified of a new monitor")
705  {}
706 
707  private:
708  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
709  {
710  try
711  {
712  getParam<fhicl::ParameterSet>(paramList, 0);
713  }
714  catch (...)
715  {
716  *retvalP = xmlrpc_c::value_string("The register_monitor command expects a string representing the FHiCL definition of a Transfer plugin");
717  return true;
718  }
719 
720  *retvalP = xmlrpc_c::value_string(_c._commandable.register_monitor(getParam<fhicl::ParameterSet>(paramList, 0)));
721  return true;
722  }
723  };
724 
728  class unregister_monitor_ : public cmd_
729  {
730  public:
736  cmd_(c, "s:s", "Remove a monitor")
737  {}
738 
739  private:
740  bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP)
741  {
742  try
743  {
744  getParam<std::string>(paramList, 0);
745  }
746  catch (...)
747  {
748  *retvalP = xmlrpc_c::value_string("The unregister_monitor command expects a string representing the label of the monitor to be removed");
749  return true;
750  }
751 
752  *retvalP = xmlrpc_c::value_string(_c._commandable.unregister_monitor(getParam<std::string>(paramList, 0)));
753  return true;
754  }
755  };
756 
757 
758  // JCF, 9/4/14
759 
760  // Not sure if anyone was planning to resurrect this code by changing
761  // the preprocessor decision; as such, I'll leave it in for now...
762 
763 #if 0
764  class shutdown_ : public xmlrpc_c::registry::shutdown
765  {
766  public:
767  shutdown_(xmlrpc_c::serverAbyss *server) : _server(server) {}
768 
769  virtual void doit(const std::string& paramString, void*) const
770  {
771  TLOG_INFO("XMLRPC_Commander") << "A shutdown command was sent "
772  << "with parameter "
773  << paramString << "\"" << TLOG_ENDL;
774  _server->terminate();
775  }
776  private:
777  xmlrpc_c::serverAbyss *_server;
778  };
779 #endif
780 
781 
782 
783  xmlrpc_commander::xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable& commandable)
784  : CommanderInterface(ps, commandable)
785  , port_(ps.get<int>("id", 0))
786  , serverUrl_(ps.get<std::string>("server_url", ""))
787  {
788  //std::cout << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_ << std::endl;
789  }
790 
792  {
793  //std::cout << "XMLRPC_COMMANDER RUN_SERVER CALLED!" << std::endl;
794  xmlrpc_c::registry registry;
795  struct xmlrpc_method_info3 methodInfo;
796  memset(&methodInfo, 0 , sizeof(methodInfo));
797 
798 /*#define register_method(m) \
799 // xmlrpc_c::methodPtr const ptr_ ## m(new m ## _(*this));\
800  registry.addMethod ("daq." #m, ptr_ ## m) */
801 #define register_method(m) register_method2(m,0x200000)
802 
803  xmlrpc_env env; // xmlrpc_env_init(&env);
804  xmlrpc_registry ***c_registryPPP;
805  c_registryPPP = (xmlrpc_registry ***)(((char*)&registry)+sizeof(girmem::autoObject));
806 
807 #define register_method2(m,ss) \
808  xmlrpc_c::method * ptr_ ## m(dynamic_cast<xmlrpc_c::method *>(new m ## _(*this))); \
809  methodInfo.methodName = "daq." #m; \
810  methodInfo.methodFunction = &c_executeMethod; \
811  methodInfo.serverInfo = ptr_ ## m; \
812  methodInfo.stackSize = ss; \
813  methodInfo.signatureString = ptr_ ## m ->signature().c_str(); \
814  methodInfo.help = ptr_ ## m ->help().c_str(); \
815  xmlrpc_env_init(&env); \
816  xmlrpc_registry_add_method3(&env,**c_registryPPP,&methodInfo); \
817  if(env.fault_occurred)throw(girerr::error(env.fault_string)); \
818  xmlrpc_env_clean(&env)
819 
820  register_method2(init,0x200000);
821  register_method(soft_init);
822  register_method(reinit);
823  register_method(start);
824  register_method(status);
825  register_method(report);
826  register_method(stop);
827  register_method(pause);
828  register_method(resume);
829  register_method(register_monitor);
830  register_method(unregister_monitor);
831  register_method(legal_commands);
832 
833  register_method(shutdown);
834 
835  // alias "daq.reset" to the internal shutdown transition
836  xmlrpc_c::methodPtr const ptr_reset(new shutdown_(*this));
837  registry.addMethod("daq.reset", ptr_reset);
838 
839 #undef register_method
840 
841  // JCF, 6/3/15
842 
843  // In the following code, I configure a socket to have the
844  // SO_REUSEADDR option so that once an artdaq process closes, the
845  // port it was communicating on becomes immediately available
846  // (desirable if, say, the DAQ program is terminated and then
847  // immediately restarted)
848 
849  // Much of the following code is cribbed from
850  // http://fossies.org/linux/freeswitch/libs/xmlrpc-c/src/cpp/test/server_abyss.cpp
851 
852  // Below, "0" is the default protocol (in this case, given the IPv4
853  // Protocol Family (PF_INET) and the SOCK_STREAM communication
854  // method)
855 
856  XMLRPC_SOCKET socket_file_descriptor = socket(PF_INET, SOCK_STREAM, 0);
857 
858  if (socket_file_descriptor < 0)
859  {
860  throw cet::exception("xmlrpc_commander::run") <<
861  "Problem with the socket() call; C-style errno == " <<
862  errno << " (" << strerror(errno) << ")";
863  }
864 
865  int enable = 1;
866  int retval = setsockopt(socket_file_descriptor,
867  SOL_SOCKET, SO_REUSEADDR,
868  &enable, sizeof(int));
869 
870  if (retval < 0)
871  {
872  throw cet::exception("xmlrpc_commander::run") <<
873  "Problem with the call to setsockopt(); C-style errno == " <<
874  errno << " (" << strerror(errno) << ")";
875  }
876 
877  struct sockaddr_in sockAddr;
878 
879  sockAddr.sin_family = AF_INET;
880  sockAddr.sin_port = htons(port_);
881  sockAddr.sin_addr.s_addr = 0;
882 
883  retval = bind(socket_file_descriptor,
884  reinterpret_cast<struct sockaddr*>(&sockAddr),
885  sizeof(sockAddr));
886 
887  if (retval != 0)
888  {
889  close(socket_file_descriptor);
890  throw cet::exception("xmlrpc_commander::run") <<
891  "Problem with the bind() call; C-style errno == " <<
892  errno << " (" << strerror(errno) << ")";
893  }
894 
895  xmlrpc_c::serverAbyss server(xmlrpc_c::serverAbyss::constrOpt().registryP(&registry).socketFd(socket_file_descriptor));
896 
897 #if 0
898  xmlrpc_c::serverAbyss::shutdown shutdown_obj(&server);
899  registry.setShutdown(&shutdown_obj);
900 #endif
901 
902  TLOG_DEBUG("XMLRPC_Commander") << "running server" << TLOG_ENDL;
903 
904  // JCF, 6/3/15
905 
906  // Use a catch block to clean up (i.e., close the socket). An
907  // opportunity for RAII, although all control paths are limited to
908  // this section of the file...
909 
910  try
911  {
912  server.run();
913  }
914  catch (...)
915  {
916  TLOG_WARNING("XMLRPC_Commander") << "server threw an exception; closing the socket and rethrowing" << TLOG_ENDL;
917  close(socket_file_descriptor);
918  throw;
919  }
920 
921  close(socket_file_descriptor);
922  TLOG_DEBUG("XMLRPC_Commander") << "server terminated" << TLOG_ENDL;
923  }
924  catch (...)
925  {
926  throw;
927  }
928 
929 
930  std::string xmlrpc_commander::send_register_monitor(std::string monitor_fhicl)
931  {
932  if (serverUrl_ == "")
933  {
934  std::stringstream errmsg;
935  errmsg << "Problem attempting XML-RPC call: No server URL set!";
936  ExceptionHandler(ExceptionHandlerRethrow::yes,
937  errmsg.str());
938 
939  }
940  xmlrpc_c::clientSimple myClient;
941  xmlrpc_c::value result;
942 
943  try
944  {
945  myClient.call(serverUrl_, "daq.register_monitor", "s", &result, monitor_fhicl.c_str());
946  }
947  catch (...)
948  {
949  std::stringstream errmsg;
950  errmsg << "Problem attempting XML-RPC call on host " << serverUrl_
951  << "; possible causes are malformed FHiCL or nonexistent process at requested port";
952  ExceptionHandler(ExceptionHandlerRethrow::yes,
953  errmsg.str());
954  }
955 
956  return xmlrpc_c::value_string(result);
957  }
958 
959  std::string xmlrpc_commander::send_unregister_monitor(std::string monitor_label)
960  {
961  if (serverUrl_ == "")
962  {
963  std::stringstream errmsg;
964  errmsg << "Problem attempting XML-RPC call: No server URL set!";
965  ExceptionHandler(ExceptionHandlerRethrow::yes,
966  errmsg.str());
967 
968  }
969 
970  xmlrpc_c::clientSimple myClient;
971  xmlrpc_c::value result;
972 
973  try
974  {
975  myClient.call(serverUrl_, "daq.unregister_monitor", "s", &result, monitor_label.c_str());
976  }
977  catch (...)
978  {
979  std::stringstream errmsg;
980  errmsg << "Problem attempting to unregister monitor via XML-RPC call on host " << serverUrl_
981  << "; possible causes are that the monitor label \""
982  << monitor_label
983  << "\" is unrecognized by contacted process or process at requested port doesn't exist";
984  ExceptionHandler(ExceptionHandlerRethrow::no,
985  errmsg.str());
986  }
987 
988  return xmlrpc_c::value_string(result);
989 
990  }
991 } // namespace artdaq
992 
993 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 std::string unregister_monitor(std::string const &)
Perform the unregister_monitor action.
Definition: Commandable.hh:150
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.
shutdown_ Command class
void run_server() override
Run the 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.
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
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
start_(xmlrpc_commander &c)
start_ Command (cmd_ derived class) 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