$treeview $search $mathjax $extrastylesheet
artdaq
v3_04_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /* DarkSide 50 DAQ program 00002 * This file add the xmlrpc commander as a client to the SC 00003 * Author: Alessandro Razeto <Alessandro.Razeto@ge.infn.it> 00004 */ 00005 00006 #pragma GCC diagnostic push 00007 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 00008 #define _LIBCPP_ENABLE_CXX17_REMOVED_FEATURES 1 00009 #include <xmlrpc-c/base.hpp> 00010 #include <xmlrpc-c/registry.hpp> 00011 #include <xmlrpc-c/server_abyss.hpp> 00012 #include <xmlrpc-c/girerr.hpp> 00013 #include <xmlrpc-c/client_simple.hpp> 00014 #undef _LIBCPP_ENABLE_CXX17_REMOVED_FEATURES 00015 #pragma GCC diagnostic pop 00016 #include <stdexcept> 00017 #include <iostream> 00018 #include <limits> 00019 #include <memory> 00020 #include <cstdint> 00021 #define TRACE_NAME (app_name + "_xmlrpc_commander").c_str() 00022 #include "artdaq/DAQdata/Globals.hh" 00023 #include "tracemf.h" 00024 00025 #include "artdaq-core/Utilities/ExceptionHandler.hh" 00026 #include <sys/socket.h> 00027 #include <netinet/in.h> 00028 #include <errno.h> 00029 #include <cstring> 00030 #include <exception> 00031 00032 #include "canvas/Persistency/Provenance/RunID.h" 00033 #include "fhiclcpp/make_ParameterSet.h" 00034 00035 #include "artdaq/ExternalComms/xmlrpc_commander.hh" 00036 //#include "artdaq/Application/LoadParameterSet.hh" 00037 00038 namespace { 00042 class env_wrap { 00043 public: 00044 env_wrap() { xmlrpc_env_init(&this->env_c); }; 00045 ~env_wrap() { xmlrpc_env_clean(&this->env_c); }; 00046 xmlrpc_env env_c; 00047 }; 00048 } // namespace 00049 static xmlrpc_c::paramList 00050 pListFromXmlrpcArray(xmlrpc_value * const arrayP) 00051 { 00052 env_wrap env; 00053 XMLRPC_ASSERT_ARRAY_OK(arrayP); 00054 unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP); 00055 assert(!env.env_c.fault_occurred); 00056 xmlrpc_c::paramList paramList(arraySize); 00057 for (unsigned int i = 0; i < arraySize; ++i) { 00058 xmlrpc_value * arrayItemP; 00059 xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP); 00060 assert(!env.env_c.fault_occurred); 00061 paramList.add(xmlrpc_c::value(arrayItemP)); 00062 xmlrpc_DECREF(arrayItemP); 00063 } 00064 return paramList; 00065 } 00066 static xmlrpc_value * 00067 c_executeMethod(xmlrpc_env * const envP, 00068 xmlrpc_value * const paramArrayP, 00069 void * const methodPtr, 00070 void * const callInfoPtr) 00071 { 00072 xmlrpc_c::method * const methodP(static_cast<xmlrpc_c::method *>(methodPtr)); 00073 xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP)); 00074 xmlrpc_c::callInfo * const callInfoP(static_cast<xmlrpc_c::callInfo *>(callInfoPtr)); 00075 xmlrpc_value * retval; 00076 retval = NULL; // silence used-before-set warning 00077 try { 00078 xmlrpc_c::value result; 00079 try { 00080 xmlrpc_c::method2 * const method2P(dynamic_cast<xmlrpc_c::method2 *>(methodP)); 00081 if (method2P) 00082 method2P->execute(paramList, callInfoP, &result); 00083 else 00084 methodP->execute(paramList, &result); 00085 } 00086 catch (xmlrpc_c::fault const& fault) { 00087 xmlrpc_env_set_fault(envP, fault.getCode(), 00088 fault.getDescription().c_str()); 00089 } 00090 if (!envP->fault_occurred) { 00091 if (result.isInstantiated()) 00092 retval = result.cValue(); 00093 else 00094 girerr::throwf("Xmlrpc-c user's xmlrpc_c::method object's " 00095 "'execute method' failed to set the RPC result " 00096 "value."); 00097 } 00098 } 00099 catch (std::exception const& e) { 00100 xmlrpc_faultf(envP, "Unexpected error executing code for " 00101 "particular method, detected by Xmlrpc-c " 00102 "method registry code. Method did not " 00103 "fail; rather, it did not complete at all. %s", 00104 e.what()); 00105 } 00106 catch (...) { 00107 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, 00108 "Unexpected error executing code for " 00109 "particular method, detected by Xmlrpc-c " 00110 "method registry code. Method did not " 00111 "fail; rather, it did not complete at all."); 00112 } 00113 return retval; 00114 } 00115 00116 00117 00118 namespace artdaq 00119 { 00126 std::string exception_msg(const std::runtime_error& er, 00127 const std::string& helpText = "execute request") 00128 { 00129 std::string msg("Exception when trying to "); 00130 msg.append(helpText); 00131 msg.append(": "); 00132 msg.append(er.what()); //std::string(er.what ()).substr (2); 00133 if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1); 00134 return msg; 00135 } 00136 00143 std::string exception_msg(const art::Exception& er, 00144 const std::string& helpText) 00145 { 00146 std::string msg("Exception when trying to "); 00147 msg.append(helpText); 00148 msg.append(": "); 00149 msg.append(er.what()); 00150 if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1); 00151 return msg; 00152 } 00153 00160 std::string exception_msg(const cet::exception& er, 00161 const std::string& helpText) 00162 { 00163 std::string msg("Exception when trying to "); 00164 msg.append(helpText); 00165 msg.append(": "); 00166 msg.append(er.what()); 00167 if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1); 00168 return msg; 00169 } 00170 00177 std::string exception_msg(const std::string& erText, 00178 const std::string& helpText) 00179 { 00180 std::string msg("Exception when trying to "); 00181 msg.append(helpText); 00182 msg.append(": "); 00183 msg.append(erText); 00184 if (msg[msg.size() - 1] == '\n') msg.erase(msg.size() - 1); 00185 return msg; 00186 } 00187 00188 00206 class cmd_ : public xmlrpc_c::method 00207 { 00208 public: 00209 00210 // Can't seem to initialize "_signature" and "_help" in the initialization list... 00217 cmd_(xmlrpc_commander& c, const std::string& signature, const std::string& description) : _c(c) 00218 { 00219 _signature = signature; 00220 _help = description; 00221 } 00222 00228 void execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP) final; 00229 00230 protected: 00231 00232 xmlrpc_commander & _c; 00233 00239 virtual bool execute_(const xmlrpc_c::paramList&, xmlrpc_c::value* const retvalP) = 0; 00240 00250 template <typename T> 00251 T getParam(const xmlrpc_c::paramList& paramList, int index); 00252 00276 template <typename T> 00277 T getParam(const xmlrpc_c::paramList& paramList, int index, T default_value); 00278 }; 00279 00280 // Users are only allowed to call getParam for predefined types; see 00281 // template specializations below this default function 00282 00283 template <typename T> 00284 T cmd_::getParam(const xmlrpc_c::paramList&, int) 00285 { 00286 throw cet::exception("cmd_") << "Error in cmd_::getParam(): value type not supported" << std::endl; 00287 } 00288 00297 template <> 00298 uint64_t cmd_::getParam<uint64_t>(const xmlrpc_c::paramList& paramList, int index) 00299 { 00300 TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as uint64_t."; 00301 TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index); 00302 return boost::lexical_cast<uint64_t>(paramList.getString(index)); 00303 } 00304 00313 template <> 00314 std::string cmd_::getParam<std::string>(const xmlrpc_c::paramList& paramList, int index) 00315 { 00316 TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as string."; 00317 TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index); 00318 return static_cast<std::string>(paramList.getString(index)); 00319 } 00320 00329 template <> 00330 art::RunID cmd_::getParam<art::RunID>(const xmlrpc_c::paramList& paramList, int index) 00331 { 00332 TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as Run Number."; 00333 TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index); 00334 std::string run_number_string = paramList.getString(index); 00335 art::RunNumber_t run_number = 00336 boost::lexical_cast<art::RunNumber_t>(run_number_string); 00337 art::RunID run_id(run_number); 00338 00339 return run_id; 00340 } 00341 00350 template <> 00351 fhicl::ParameterSet cmd_::getParam<fhicl::ParameterSet>(const xmlrpc_c::paramList& paramList, int index) 00352 { 00353 TLOG(TLVL_TRACE) << "Getting parameter " << index << " from list as ParameterSet."; 00354 TLOG(TLVL_TRACE) << "Param value: " << paramList.getString(index); 00355 std::string configString = std::string(paramList.getString(index).c_str()); 00356 TLOG(TLVL_DEBUG) << "Loading Parameter Set from string: " << configString << std::endl; 00357 fhicl::ParameterSet pset; 00358 00359 try 00360 { 00361 fhicl::make_ParameterSet(configString, pset); 00362 } 00363 catch (fhicl::exception e) 00364 { 00365 if (getenv("FHICL_FILE_PATH") == nullptr) 00366 { 00367 std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n"; 00368 setenv("FHICL_FILE_PATH", ".", 0); 00369 } 00370 cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH"); 00371 fhicl::make_ParameterSet(configString, lookup_policy, pset); 00372 } 00373 00374 TLOG(TLVL_INFO) << "Parameter Set Loaded." << std::endl; 00375 return pset; 00376 } 00377 00378 template <typename T> 00379 T cmd_::getParam(const xmlrpc_c::paramList& paramList, int index, 00380 T default_value) 00381 { 00382 T val = default_value; 00383 00384 try 00385 { 00386 val = getParam<T>(paramList, index); 00387 } 00388 catch (const cet::exception& exception) 00389 { 00390 throw exception; 00391 } 00392 catch (...) {} 00393 00394 return val; 00395 } 00396 00397 void cmd_::execute(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP) 00398 { 00399 std::unique_lock<std::timed_mutex> lk(_c.mutex_, std::chrono::milliseconds(250)); 00400 if (lk.owns_lock()) 00401 { 00402 try 00403 { 00404 // JCF, 9/4/14 00405 00406 // Assuming the execute_ function returns true, then if the 00407 // retvalP argument was untouched, assign it the string 00408 // "Success" 00409 00410 // See 00411 // http://xmlrpc-c.sourceforge.net/doc/libxmlrpc++.html#isinstantiated 00412 // for more on the concept of instantiation in xmlrpc_c::value objects 00413 00414 if (execute_(paramList, retvalP)) 00415 { 00416 if (!retvalP->isInstantiated()) 00417 { 00418 *retvalP = xmlrpc_c::value_string("Success"); 00419 } 00420 } 00421 else 00422 { 00423 std::string problemReport = _c._commandable.report("transition_status"); 00424 *retvalP = xmlrpc_c::value_string(problemReport); 00425 } 00426 } 00427 catch (std::runtime_error& er) 00428 { 00429 std::string msg = exception_msg(er, _help); 00430 *retvalP = xmlrpc_c::value_string(msg); 00431 TLOG(TLVL_ERROR) << msg; 00432 } 00433 catch (art::Exception& er) 00434 { 00435 std::string msg = exception_msg(er, _help); 00436 *retvalP = xmlrpc_c::value_string(msg); 00437 TLOG(TLVL_ERROR) << msg; 00438 } 00439 catch (cet::exception& er) 00440 { 00441 std::string msg = exception_msg(er, _help); 00442 *retvalP = xmlrpc_c::value_string(msg); 00443 TLOG(TLVL_ERROR) << msg; 00444 } 00445 catch (...) 00446 { 00447 std::string msg = exception_msg("Unknown exception", _help); 00448 *retvalP = xmlrpc_c::value_string(msg); 00449 TLOG(TLVL_ERROR) << msg; 00450 } 00451 } 00452 else 00453 { 00454 *retvalP = xmlrpc_c::value_string("busy"); 00455 } 00456 } 00457 00458 00460 00461 // JCF, 9/5/14 00462 00463 // The three "init" transitions all take a FHiCL parameter list, and 00464 // optionally a timeout and a timestamp; thus we can kill three birds 00465 // with one stone in the GENERATE_INIT_TRANSITION macro 00466 00467 #define GENERATE_INIT_TRANSITION(NAME, CALL, DESCRIPTION) \ 00468 \ 00469 class NAME ## _: public cmd_ { \ 00470 \ 00471 public: \ 00472 \ 00475 explicit NAME ## _(xmlrpc_commander& c): \ 00476 cmd_(c, "s:sii", DESCRIPTION) {} \ 00477 \ 00478 \ 00479 static const uint64_t defaultTimeout = 45; \ 00480 \ 00481 static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \ 00482 \ 00483 private: \ 00484 bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const retvalP ) { \ 00485 fhicl::ParameterSet ps; \ 00486 try { \ 00487 ps = getParam<fhicl::ParameterSet>(paramList, 0); \ 00488 } catch (...) { \ 00489 *retvalP = xmlrpc_c::value_string ("The "#NAME" message requires a single argument that is a string containing the initialization ParameterSet"); \ 00490 return true; \ 00491 } \ 00492 \ 00493 return _c._commandable.CALL(ps, \ 00494 getParam<uint64_t>(paramList, 1, defaultTimeout), \ 00495 getParam<uint64_t>(paramList, 2, defaultTimestamp) \ 00496 ); \ 00497 } \ 00498 }; 00499 00500 GENERATE_INIT_TRANSITION(init, initialize, "initialize the program") 00501 00502 GENERATE_INIT_TRANSITION(soft_init, soft_initialize, "initialize software components in the program") 00503 00504 GENERATE_INIT_TRANSITION(reinit, reinitialize, "re-initialize the program") 00505 00506 #undef GENERATE_INIT_TRANSITION 00507 00509 00513 class start_ : public cmd_ 00514 { 00515 public: 00520 explicit start_(xmlrpc_commander& c) : 00521 cmd_(c, "s:iii", "start the run") 00522 {} 00523 00525 static const uint64_t defaultTimeout = 45; 00527 static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); 00528 00529 private: 00530 00531 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) override 00532 { 00533 try 00534 { 00535 getParam<art::RunID>(paramList, 0); 00536 } 00537 catch (...) 00538 { 00539 *retvalP = xmlrpc_c::value_string("The start message requires the run number as an argument."); 00540 return true; 00541 } 00542 00543 return _c._commandable.start(getParam<art::RunID>(paramList, 0), 00544 getParam<uint64_t>(paramList, 1, defaultTimeout), 00545 getParam<uint64_t>(paramList, 2, defaultTimestamp) 00546 ); 00547 } 00548 }; 00549 00550 00552 00553 // JCF, 9/5/14 00554 00555 // "pause", "resume" and "stop" all take an optional timeout and 00556 // timestamp parameter, so we can generate them all with the 00557 // GENERATE_TIMEOUT_TIMESTAMP_TRANSITION macro 00558 00559 #define GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(NAME, CALL, DESCRIPTION, TIMEOUT) \ 00560 \ 00561 class NAME ## _: public cmd_ { \ 00562 \ 00563 public: \ 00564 \ 00566 NAME ## _(xmlrpc_commander& c): \ 00567 cmd_(c, "s:ii", DESCRIPTION) {} \ 00568 \ 00569 \ 00570 static const uint64_t defaultTimeout = TIMEOUT ; \ 00571 \ 00572 static const uint64_t defaultTimestamp = std::numeric_limits<const uint64_t>::max(); \ 00573 \ 00574 private: \ 00575 \ 00576 bool execute_ (const xmlrpc_c::paramList& paramList , xmlrpc_c::value* const ) { \ 00577 \ 00578 return _c._commandable.CALL( getParam<uint64_t>(paramList, 0, defaultTimeout), \ 00579 getParam<uint64_t>(paramList, 1, defaultTimestamp) \ 00580 ); \ 00581 } \ 00582 }; 00583 00584 GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(pause, pause, "pause the program", 45) 00585 00586 GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(resume, resume, "resume the program", 45) 00587 00588 GENERATE_TIMEOUT_TIMESTAMP_TRANSITION(stop, stop, "stop the program", 45) 00589 00590 #undef GENERATE_TIMEOUT_TIMESTAMP_TRANSITION 00591 00592 00596 class shutdown_ : public cmd_ 00597 { 00598 public: 00603 shutdown_(xmlrpc_commander& c) : 00604 cmd_(c, "s:i", "shutdown the program") 00605 {} 00606 00608 static const uint64_t defaultTimeout = 45; 00609 00610 private: 00611 00612 bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const) 00613 { 00614 auto ret = _c._commandable.shutdown(getParam<uint64_t>(paramList, 0, defaultTimeout)); 00615 00616 #if 1 00617 if (_c.server) _c.server->terminate(); 00618 #endif 00619 00620 return ret; 00621 } 00622 }; 00623 00624 00628 class status_ : public cmd_ 00629 { 00630 public: 00635 status_(xmlrpc_commander& c) : 00636 cmd_(c, "s:n", "report the current state") 00637 {} 00638 00639 private: 00640 00641 bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP) 00642 { 00643 *retvalP = xmlrpc_c::value_string(_c._commandable.status()); 00644 return true; 00645 } 00646 }; 00647 00648 00652 class report_ : public cmd_ 00653 { 00654 public: 00659 report_(xmlrpc_commander& c) : 00660 cmd_(c, "s:s", "report statistics") 00661 {} 00662 00663 private: 00664 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00665 { 00666 try 00667 { 00668 getParam<std::string>(paramList, 0); 00669 } 00670 catch (...) 00671 { 00672 *retvalP = xmlrpc_c::value_string("The report message requires a single argument that selects the type of statistics to be reported."); 00673 return true; 00674 } 00675 00676 *retvalP = xmlrpc_c::value_string(_c._commandable.report(getParam<std::string>(paramList, 0))); 00677 return true; 00678 } 00679 }; 00680 00684 class legal_commands_ : public cmd_ 00685 { 00686 public: 00691 legal_commands_(xmlrpc_commander& c) : 00692 cmd_(c, "s:n", "return the currently legal commands") 00693 {} 00694 00695 private: 00696 bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const retvalP) 00697 { 00698 std::vector<std::string> cmdList = _c._commandable.legal_commands(); 00699 std::string resultString; 00700 00701 for (auto& cmd : cmdList) 00702 { 00703 resultString.append(cmd + " "); 00704 if (cmd == "shutdown") 00705 { 00706 resultString.append(" reset"); 00707 } 00708 } 00709 *retvalP = xmlrpc_c::value_string(resultString); 00710 00711 return true; 00712 } 00713 }; 00714 00718 class register_monitor_ : public cmd_ 00719 { 00720 public: 00725 register_monitor_(xmlrpc_commander& c) : 00726 cmd_(c, "s:s", "Get notified of a new monitor") 00727 {} 00728 00729 private: 00730 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00731 { 00732 try 00733 { 00734 getParam<fhicl::ParameterSet>(paramList, 0); 00735 } 00736 catch (...) 00737 { 00738 *retvalP = xmlrpc_c::value_string("The register_monitor command expects a string representing the FHiCL definition of a Transfer plugin"); 00739 return true; 00740 } 00741 00742 *retvalP = xmlrpc_c::value_string(_c._commandable.register_monitor(getParam<fhicl::ParameterSet>(paramList, 0))); 00743 return true; 00744 } 00745 }; 00746 00750 class unregister_monitor_ : public cmd_ 00751 { 00752 public: 00757 unregister_monitor_(xmlrpc_commander& c) : 00758 cmd_(c, "s:s", "Remove a monitor") 00759 {} 00760 00761 private: 00762 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00763 { 00764 try 00765 { 00766 getParam<std::string>(paramList, 0); 00767 } 00768 catch (...) 00769 { 00770 *retvalP = xmlrpc_c::value_string("The unregister_monitor command expects a string representing the label of the monitor to be removed"); 00771 return true; 00772 } 00773 00774 *retvalP = xmlrpc_c::value_string(_c._commandable.unregister_monitor(getParam<std::string>(paramList, 0))); 00775 return true; 00776 } 00777 }; 00778 00779 00783 class trace_set_ : public cmd_ 00784 { 00785 public: 00790 trace_set_(xmlrpc_commander& c) : 00791 cmd_(c, "s:ssi", "Set TRACE mask") 00792 {} 00793 00794 private: 00795 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00796 { 00797 try 00798 { 00799 getParam<std::string>(paramList, 0); 00800 getParam<std::string>(paramList, 1); 00801 getParam<uint64_t>(paramList, 2); 00802 } 00803 catch (...) 00804 { 00805 *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"); 00806 return true; 00807 } 00808 00809 return _c._commandable.do_trace_set(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1), getParam<uint64_t>(paramList, 2)); 00810 } 00811 }; 00812 00816 class trace_get_ : public cmd_ 00817 { 00818 public: 00823 trace_get_(xmlrpc_commander& c) : 00824 cmd_(c, "s:s", "Get TRACE mask") 00825 {} 00826 00827 private: 00828 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00829 { 00830 try 00831 { 00832 getParam<std::string>(paramList, 0); 00833 } 00834 catch (...) 00835 { 00836 *retvalP = xmlrpc_c::value_string("The trace_msgfacility_set command expects a name (ALL for all)"); 00837 return true; 00838 } 00839 00840 *retvalP = xmlrpc_c::value_string(_c._commandable.do_trace_get(getParam<std::string>(paramList, 0))); 00841 return true; 00842 } 00843 }; 00844 00848 class meta_command_ : public cmd_ 00849 { 00850 public: 00855 meta_command_(xmlrpc_commander& c) : 00856 cmd_(c, "s:ss", "Run custom command") 00857 {} 00858 00859 private: 00860 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00861 { 00862 try 00863 { 00864 getParam<std::string>(paramList, 0); 00865 getParam<std::string>(paramList, 1); 00866 } 00867 catch (...) 00868 { 00869 *retvalP = xmlrpc_c::value_string("The meta_command command expects a string command and a string argument"); 00870 return true; 00871 } 00872 00873 return _c._commandable.do_meta_command(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1)); 00874 } 00875 }; 00876 00880 class rollover_subrun_ : public cmd_ 00881 { 00882 public: 00887 rollover_subrun_(xmlrpc_commander& c) : 00888 cmd_(c, "s:ii", "create a new subrun") 00889 {} 00890 00891 static const uint64_t defaultSequenceID = 0xFFFFFFFFFFFFFFFF; 00892 static const uint32_t defaultSubrunNumber = 1; 00893 00894 private: 00895 00896 bool execute_(const xmlrpc_c::paramList& paramList, xmlrpc_c::value* const) 00897 { 00898 auto ret = _c._commandable.do_rollover_subrun(getParam<uint64_t>(paramList, 0, defaultSequenceID), getParam<uint32_t>(paramList, 1, defaultSubrunNumber)); 00899 return ret; 00900 } 00901 }; 00902 00906 class add_config_archive_entry_ : public cmd_ 00907 { 00908 public: 00913 add_config_archive_entry_(xmlrpc_commander& c) : 00914 cmd_(c, "s:ss", "Add an entry to the configuration archive list") 00915 {} 00916 00917 private: 00918 bool execute_(xmlrpc_c::paramList const& paramList, xmlrpc_c::value* const retvalP) 00919 { 00920 try 00921 { 00922 getParam<std::string>(paramList, 0); 00923 getParam<std::string>(paramList, 1); 00924 } 00925 catch (...) 00926 { 00927 *retvalP = xmlrpc_c::value_string("The add_config_archive_entry command expects a string key and a string value"); 00928 return true; 00929 } 00930 00931 return _c._commandable.do_add_config_archive_entry(getParam<std::string>(paramList, 0), getParam<std::string>(paramList, 1)); 00932 } 00933 }; 00934 00938 class clear_config_archive_ : public cmd_ 00939 { 00940 public: 00945 clear_config_archive_(xmlrpc_commander& c) : 00946 cmd_(c, "s:n", "Clear the configuration archive list") 00947 {} 00948 00949 private: 00950 bool execute_(xmlrpc_c::paramList const&, xmlrpc_c::value* const) 00951 { 00952 return _c._commandable.do_clear_config_archive(); 00953 } 00954 }; 00955 00956 // JCF, 9/4/14 00957 00958 // Not sure if anyone was planning to resurrect this code by changing 00959 // the preprocessor decision; as such, I'll leave it in for now... 00960 00961 #if 0 00962 class shutdown_ : public xmlrpc_c::registry::shutdown 00963 { 00964 public: 00965 shutdown_(xmlrpc_c::serverAbyss *server) : _server(server) {} 00966 00967 virtual void doit(const std::string& paramString, void*) const 00968 { 00969 TLOG(TLVL_INFO) << "A shutdown command was sent " 00970 << "with parameter " 00971 << paramString << "\""; 00972 _server->terminate(); 00973 } 00974 private: 00975 xmlrpc_c::serverAbyss *_server; 00976 }; 00977 #endif 00978 00979 00980 00981 xmlrpc_commander::xmlrpc_commander(fhicl::ParameterSet ps, artdaq::Commandable& commandable) 00982 : CommanderInterface(ps, commandable) 00983 , port_(ps.get<int>("id", 0)) 00984 , serverUrl_(ps.get<std::string>("server_url", "")) 00985 , server(nullptr) 00986 { 00987 TLOG(TLVL_INFO) << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_; 00988 if (serverUrl_.find("http") == std::string::npos) 00989 { 00990 serverUrl_ = "http://" + serverUrl_; 00991 } 00992 if (serverUrl_.find(std::to_string(port_)) == std::string::npos && serverUrl_.find(':', 7) == std::string::npos) 00993 { 00994 serverUrl_ = serverUrl_ + ":" + std::to_string(port_); 00995 } 00996 if (serverUrl_.find("RPC2") == std::string::npos) 00997 { 00998 serverUrl_ = serverUrl_ + "/RPC2"; 00999 } 01000 TLOG(TLVL_INFO) << "XMLRPC COMMANDER CONSTRUCTOR: Port: " << port_ << ", Server Url: " << serverUrl_; 01001 01002 } 01003 01004 void xmlrpc_commander::run_server() try 01005 { 01006 //std::cout << "XMLRPC_COMMANDER RUN_SERVER CALLED!" << std::endl; 01007 xmlrpc_c::registry registry; 01008 struct xmlrpc_method_info3 methodInfo; 01009 memset(&methodInfo, 0, sizeof(methodInfo)); 01010 01011 /*#define register_method(m) \ 01012 // xmlrpc_c::methodPtr const ptr_ ## m(new m ## _(*this));\ 01013 registry.addMethod ("daq." #m, ptr_ ## m) */ 01014 #define register_method(m) register_method2(m,0x400000) 01015 01016 xmlrpc_env env; // xmlrpc_env_init(&env); 01017 xmlrpc_registry ***c_registryPPP; 01018 c_registryPPP = (xmlrpc_registry ***)(((char*)®istry) + sizeof(girmem::autoObject)); 01019 01020 #define register_method2(m,ss) \ 01021 xmlrpc_c::method* ptr_ ## m(dynamic_cast<xmlrpc_c::method*>(new m ## _(*this))); \ 01022 std::string m##signature = ptr_ ## m->signature(), m##help = ptr_ ## m->help(); \ 01023 methodInfo.methodName = "daq." #m; \ 01024 methodInfo.methodFunction = &c_executeMethod; \ 01025 methodInfo.serverInfo = ptr_ ## m; \ 01026 methodInfo.stackSize = ss; \ 01027 methodInfo.signatureString = &m##signature[0]; \ 01028 methodInfo.help = &m##help[0]; \ 01029 xmlrpc_env_init(&env); \ 01030 xmlrpc_registry_add_method3(&env,**c_registryPPP,&methodInfo); \ 01031 if(env.fault_occurred)throw(girerr::error(env.fault_string)); \ 01032 xmlrpc_env_clean(&env) 01033 01034 register_method2(init, 0x200000); 01035 register_method(soft_init); 01036 register_method(reinit); 01037 register_method(start); 01038 register_method(status); 01039 register_method(report); 01040 register_method(stop); 01041 register_method(pause); 01042 register_method(resume); 01043 register_method(register_monitor); 01044 register_method(unregister_monitor); 01045 register_method(legal_commands); 01046 register_method(trace_set); 01047 register_method(trace_get); 01048 register_method(meta_command); 01049 register_method(rollover_subrun); 01050 register_method(add_config_archive_entry); 01051 register_method(clear_config_archive); 01052 01053 register_method(shutdown); 01054 01055 // alias "daq.reset" to the internal shutdown transition 01056 xmlrpc_c::methodPtr const ptr_reset(new shutdown_(*this)); 01057 registry.addMethod("daq.reset", ptr_reset); 01058 01059 #undef register_method 01060 01061 // JCF, 6/3/15 01062 01063 // In the following code, I configure a socket to have the 01064 // SO_REUSEADDR option so that once an artdaq process closes, the 01065 // port it was communicating on becomes immediately available 01066 // (desirable if, say, the DAQ program is terminated and then 01067 // immediately restarted) 01068 01069 // Much of the following code is cribbed from 01070 // http://fossies.org/linux/freeswitch/libs/xmlrpc-c/src/cpp/test/server_abyss.cpp 01071 01072 // Below, "0" is the default protocol (in this case, given the IPv4 01073 // Protocol Family (PF_INET) and the SOCK_STREAM communication 01074 // method) 01075 01076 XMLRPC_SOCKET socket_file_descriptor = socket(PF_INET, SOCK_STREAM, 0); 01077 01078 if (socket_file_descriptor < 0) 01079 { 01080 throw cet::exception("xmlrpc_commander::run") << 01081 "Problem with the socket() call; C-style errno == " << 01082 errno << " (" << strerror(errno) << ")"; 01083 } 01084 01085 int enable = 1; 01086 int retval = setsockopt(socket_file_descriptor, 01087 SOL_SOCKET, SO_REUSEADDR, 01088 &enable, sizeof(int)); 01089 01090 if (retval < 0) 01091 { 01092 throw cet::exception("xmlrpc_commander::run") << 01093 "Problem with the call to setsockopt(); C-style errno == " << 01094 errno << " (" << strerror(errno) << ")"; 01095 } 01096 01097 struct sockaddr_in sockAddr; 01098 01099 sockAddr.sin_family = AF_INET; 01100 sockAddr.sin_port = htons(port_); 01101 sockAddr.sin_addr.s_addr = 0; 01102 01103 retval = bind(socket_file_descriptor, 01104 reinterpret_cast<struct sockaddr*>(&sockAddr), 01105 sizeof(sockAddr)); 01106 01107 if (retval != 0) 01108 { 01109 close(socket_file_descriptor); 01110 throw cet::exception("xmlrpc_commander::run") << 01111 "Problem with the bind() call; C-style errno == " << 01112 errno << " (" << strerror(errno) << ")"; 01113 } 01114 01115 server.reset(new xmlrpc_c::serverAbyss(xmlrpc_c::serverAbyss::constrOpt().registryP(®istry).socketFd(socket_file_descriptor))); 01116 01117 #if 0 01118 xmlrpc_c::serverAbyss::shutdown shutdown_obj(&server); 01119 registry.setShutdown(&shutdown_obj); 01120 #endif 01121 01122 TLOG(TLVL_DEBUG) << "running server"; 01123 01124 // JCF, 6/3/15 01125 01126 // Use a catch block to clean up (i.e., close the socket). An 01127 // opportunity for RAII, although all control paths are limited to 01128 // this section of the file... 01129 01130 try 01131 { 01132 running_ = true; 01133 server->run(); 01134 running_ = false; 01135 } 01136 catch (...) 01137 { 01138 TLOG(TLVL_WARNING) << "server threw an exception; closing the socket and rethrowing"; 01139 running_ = false; 01140 close(socket_file_descriptor); 01141 throw; 01142 } 01143 01144 close(socket_file_descriptor); 01145 TLOG(TLVL_DEBUG) << "server terminated"; 01146 } 01147 catch (...) 01148 { 01149 throw; 01150 } 01151 01152 std::string xmlrpc_commander::send_command_(std::string command) 01153 { 01154 if (serverUrl_ == "") 01155 { 01156 std::stringstream errmsg; 01157 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01158 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01159 01160 } 01161 xmlrpc_c::clientSimple myClient; 01162 xmlrpc_c::value result; 01163 01164 try 01165 { 01166 myClient.call(serverUrl_, "daq." + command, "", &result); 01167 } 01168 catch (...) 01169 { 01170 std::stringstream errmsg; 01171 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01172 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01173 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01174 } 01175 01176 return xmlrpc_c::value_string(result); 01177 } 01178 01179 std::string xmlrpc_commander::send_command_(std::string command, std::string arg) 01180 { 01181 if (serverUrl_ == "") 01182 { 01183 std::stringstream errmsg; 01184 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01185 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01186 01187 } 01188 xmlrpc_c::clientSimple myClient; 01189 xmlrpc_c::value result; 01190 01191 try 01192 { 01193 myClient.call(serverUrl_, "daq." + command, "s", &result, arg.c_str()); 01194 } 01195 catch (...) 01196 { 01197 std::stringstream errmsg; 01198 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01199 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01200 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01201 } 01202 01203 return xmlrpc_c::value_string(result); 01204 } 01205 01206 std::string xmlrpc_commander::send_command_(std::string command, fhicl::ParameterSet pset, uint64_t timestamp, uint64_t timeout) 01207 { 01208 if (serverUrl_ == "") 01209 { 01210 std::stringstream errmsg; 01211 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01212 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01213 01214 } 01215 xmlrpc_c::clientSimple myClient; 01216 xmlrpc_c::value result; 01217 01218 try 01219 { 01220 myClient.call(serverUrl_, "daq." + command, "sii", &result, pset.to_string().c_str(), timestamp, timeout); 01221 } 01222 catch (...) 01223 { 01224 std::stringstream errmsg; 01225 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01226 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01227 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01228 } 01229 01230 return xmlrpc_c::value_string(result); 01231 } 01232 01233 std::string artdaq::xmlrpc_commander::send_command_(std::string command, uint64_t a, uint64_t b) 01234 { 01235 if (serverUrl_ == "") 01236 { 01237 std::stringstream errmsg; 01238 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01239 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01240 01241 } 01242 xmlrpc_c::clientSimple myClient; 01243 xmlrpc_c::value result; 01244 01245 try 01246 { 01247 myClient.call(serverUrl_, "daq." + command, "ii", &result, a,b); 01248 } 01249 catch (...) 01250 { 01251 std::stringstream errmsg; 01252 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01253 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01254 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01255 } 01256 01257 return xmlrpc_c::value_string(result); 01258 } 01259 01260 std::string artdaq::xmlrpc_commander::send_command_(std::string command, art::RunID r, uint64_t a, uint64_t b) 01261 { 01262 if (serverUrl_ == "") 01263 { 01264 std::stringstream errmsg; 01265 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01266 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01267 01268 } 01269 xmlrpc_c::clientSimple myClient; 01270 xmlrpc_c::value result; 01271 01272 try 01273 { 01274 myClient.call(serverUrl_, "daq." + command, "iii", &result, r, a, b); 01275 } 01276 catch (...) 01277 { 01278 std::stringstream errmsg; 01279 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01280 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01281 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01282 } 01283 01284 return xmlrpc_c::value_string(result); 01285 } 01286 01287 std::string artdaq::xmlrpc_commander::send_command_(std::string command, uint64_t arg1) 01288 { 01289 if (serverUrl_ == "") 01290 { 01291 std::stringstream errmsg; 01292 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01293 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01294 01295 } 01296 xmlrpc_c::clientSimple myClient; 01297 xmlrpc_c::value result; 01298 01299 try 01300 { 01301 myClient.call(serverUrl_, "daq." + command, "i", &result, arg1); 01302 } 01303 catch (...) 01304 { 01305 std::stringstream errmsg; 01306 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01307 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01308 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01309 } 01310 01311 return xmlrpc_c::value_string(result); 01312 } 01313 01314 std::string artdaq::xmlrpc_commander::send_command_(std::string command, std::string arg1, std::string arg2) 01315 { 01316 if (serverUrl_ == "") 01317 { 01318 std::stringstream errmsg; 01319 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01320 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01321 01322 } 01323 xmlrpc_c::clientSimple myClient; 01324 xmlrpc_c::value result; 01325 01326 try 01327 { 01328 myClient.call(serverUrl_, "daq." + command, "ss", &result, arg1.c_str(), arg2.c_str()); 01329 } 01330 catch (...) 01331 { 01332 std::stringstream errmsg; 01333 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01334 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01335 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01336 } 01337 01338 return xmlrpc_c::value_string(result); 01339 } 01340 01341 std::string artdaq::xmlrpc_commander::send_command_(std::string command, std::string arg1, std::string arg2, uint64_t arg3) 01342 { 01343 if (serverUrl_ == "") 01344 { 01345 std::stringstream errmsg; 01346 errmsg << "Problem attempting " << command << " XML-RPC call: No server URL set!"; 01347 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01348 01349 } 01350 xmlrpc_c::clientSimple myClient; 01351 xmlrpc_c::value result; 01352 01353 try 01354 { 01355 myClient.call(serverUrl_, "daq." + command, "ssi", &result, arg1.c_str(), arg2.c_str(), arg3); 01356 } 01357 catch (...) 01358 { 01359 std::stringstream errmsg; 01360 errmsg << "Problem attempting " << command << " XML-RPC call on host " << serverUrl_ 01361 << "; possible causes are malformed FHiCL or nonexistent process at requested port"; 01362 ExceptionHandler(ExceptionHandlerRethrow::yes, errmsg.str()); 01363 } 01364 01365 return xmlrpc_c::value_string(result); 01366 } 01367 01368 std::string xmlrpc_commander::send_register_monitor(std::string monitor_fhicl) 01369 { 01370 return send_command_("register_monitor", monitor_fhicl); 01371 } 01372 std::string xmlrpc_commander::send_unregister_monitor(std::string monitor_label) 01373 { 01374 return send_command_("unregister_monitor", monitor_label); 01375 } 01376 std::string artdaq::xmlrpc_commander::send_init(fhicl::ParameterSet ps, uint64_t a, uint64_t b) 01377 { 01378 return send_command_("init", ps, a, b); 01379 } 01380 std::string artdaq::xmlrpc_commander::send_soft_init(fhicl::ParameterSet ps, uint64_t a, uint64_t b) 01381 { 01382 return send_command_("soft_init", ps, a, b); 01383 } 01384 std::string xmlrpc_commander::send_reinit(fhicl::ParameterSet ps, uint64_t a, uint64_t b) 01385 { 01386 return send_command_("reinit", ps, a, b); 01387 } 01388 std::string xmlrpc_commander::send_start(art::RunID r, uint64_t a, uint64_t b) 01389 { 01390 return send_command_("start", r, a, b); 01391 } 01392 std::string xmlrpc_commander::send_pause(uint64_t a, uint64_t b) 01393 { 01394 return send_command_("pause", a, b); 01395 } 01396 std::string xmlrpc_commander::send_resume(uint64_t a, uint64_t b) 01397 { 01398 return send_command_("resume", a, b); 01399 } 01400 std::string xmlrpc_commander::send_stop(uint64_t a, uint64_t b) 01401 { 01402 return send_command_("stop", a, b); 01403 } 01404 std::string xmlrpc_commander::send_shutdown(uint64_t a) 01405 { 01406 return send_command_("shutdown", a); 01407 } 01408 std::string xmlrpc_commander::send_status() 01409 { 01410 return send_command_("status"); 01411 } 01412 std::string xmlrpc_commander::send_report(std::string what) 01413 { 01414 return send_command_("report", what); 01415 } 01416 std::string xmlrpc_commander::send_legal_commands() 01417 { 01418 return send_command_("legal_commands"); 01419 } 01420 std::string xmlrpc_commander::send_trace_get(std::string name) 01421 { 01422 return send_command_("trace_get", name); 01423 } 01424 std::string xmlrpc_commander::send_trace_set(std::string name, std::string which, uint64_t mask) 01425 { 01426 return send_command_("trace_set", name, which, mask); 01427 } 01428 std::string xmlrpc_commander::send_meta_command(std::string command, std::string arg) 01429 { 01430 return send_command_("meta_command", command, arg); 01431 } 01432 std::string xmlrpc_commander::send_rollover_subrun(uint64_t when, uint32_t sr) 01433 { 01434 return send_command_("rollover_subrun", when, sr); 01435 } 01436 } // namespace artdaq 01437 01438 DEFINE_ARTDAQ_COMMANDER(artdaq::xmlrpc_commander)