00001 #include "artdaq/TransferPlugins/TransferWrapper.hh"
00002 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
00003 #include "artdaq/DAQdata/NetMonHeader.hh"
00004 #include "artdaq/DAQdata/Globals.hh"
00005 #include "artdaq-core/Utilities/ExceptionHandler.hh"
00006 #include "artdaq-core/Data/Fragment.hh"
00007
00008 #include "cetlib/BasicPluginFactory.h"
00009 #include "fhiclcpp/ParameterSet.h"
00010 #pragma GCC diagnostic push
00011 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00012 #include <xmlrpc-c/girerr.hpp>
00013 #include <xmlrpc-c/base.hpp>
00014 #include <xmlrpc-c/client_simple.hpp>
00015 #pragma GCC diagnostic pop
00016
00017 #include "TBufferFile.h"
00018
00019 #include <limits>
00020 #include <iostream>
00021 #include <string>
00022 #include <sstream>
00023 #include <csignal>
00024
00025 namespace
00026 {
00027 volatile std::sig_atomic_t gSignalStatus = 0;
00028 }
00029
00034 void signal_handler(int signal)
00035 {
00036 gSignalStatus = signal;
00037 }
00038
00039 artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset) :
00040 timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
00041 , dispatcherHost_(pset.get<std::string>("dispatcherHost"))
00042 , dispatcherPort_(pset.get<std::string>("dispatcherPort"))
00043 , serverUrl_("http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2")
00044 , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
00045 , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", {226, 227, 229}))
00046 , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
00047 , debugLevel_(pset.get<std::size_t>("debugLevel", 0))
00048 , monitorRegistered_(false)
00049 {
00050 std::signal(SIGINT, signal_handler);
00051
00052 try
00053 {
00054 transfer_ = MakeTransferPlugin(pset, "transfer_plugin", TransferInterface::Role::kReceive);
00055 }
00056 catch (...)
00057 {
00058 ExceptionHandler(ExceptionHandlerRethrow::yes,
00059 "TransferWrapper: failure in call to MakeTransferPlugin");
00060 }
00061
00062 xmlrpc_c::clientSimple myClient;
00063 xmlrpc_c::value result;
00064
00065 TLOG_INFO("TransferWrapper") << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
00066 << "\") with the dispatcher aggregator" << TLOG_ENDL;
00067
00068 try
00069 {
00070 myClient.call(serverUrl_, "daq.register_monitor", "s", &result, pset.to_string().c_str());
00071 }
00072 catch (...)
00073 {
00074 std::stringstream errmsg;
00075 errmsg << "Problem attempting XML-RPC call on host " << dispatcherHost_
00076 << ", port " << dispatcherPort_ << "; possible causes are malformed FHiCL or nonexistent process at requested port";
00077 ExceptionHandler(ExceptionHandlerRethrow::yes,
00078 errmsg.str());
00079 }
00080
00081 const std::string status = xmlrpc_c::value_string(result);
00082
00083 TLOG_INFO("TransferWrapper") << "Response from dispatcher is \""
00084 << status << "\"" << TLOG_ENDL;
00085
00086 if (status == "Success")
00087 {
00088 monitorRegistered_ = true;
00089 }
00090 else
00091 {
00092 throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response";
00093 }
00094 }
00095
00096 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
00097 {
00098 std::unique_ptr<artdaq::Fragment> fragmentPtr;
00099 bool receivedFragment = false;
00100 static bool initialized = false;
00101 static size_t fragments_received = 0;
00102
00103 while (true && !gSignalStatus)
00104 {
00105 fragmentPtr = std::make_unique<artdaq::Fragment>();
00106
00107 while (!receivedFragment)
00108 {
00109 if (gSignalStatus)
00110 {
00111 TLOG_INFO("TransferWrapper") << "Ctrl-C appears to have been hit" << TLOG_ENDL;
00112 unregisterMonitor();
00113 return;
00114 }
00115
00116 try
00117 {
00118 auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
00119
00120 if (result != artdaq::TransferInterface::RECV_TIMEOUT)
00121 {
00122 receivedFragment = true;
00123 fragments_received++;
00124
00125 static size_t cntr = 1;
00126
00127 if (debugLevel_ > 1)
00128 {
00129 TLOG_INFO("TransferWrapper") << "Received " << cntr++ << "-th event, "
00130 << "seqID == " << fragmentPtr->sequenceID()
00131 << ", type == " << static_cast<int>(fragmentPtr->type()) << TLOG_ENDL;
00132 }
00133 continue;
00134 }
00135 else
00136 {
00137 if (debugLevel_ > 0)
00138 {
00139 TLOG_WARNING("TransferWrapper") << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again" << TLOG_ENDL;
00140 }
00141 }
00142 }
00143 catch (...)
00144 {
00145 ExceptionHandler(ExceptionHandlerRethrow::yes,
00146 "Problem receiving data in TransferWrapper::receiveMessage");
00147 }
00148 }
00149
00150 try
00151 {
00152 extractTBufferFile(*fragmentPtr, msg);
00153 }
00154 catch (...)
00155 {
00156 ExceptionHandler(ExceptionHandlerRethrow::yes,
00157 "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
00158 }
00159
00160 checkIntegrity(*fragmentPtr);
00161
00162 if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
00163 {
00164 initialized = true;
00165 break;
00166 }
00167 else
00168 {
00169 receivedFragment = false;
00170
00171 if (fragments_received > maxEventsBeforeInit_)
00172 {
00173 throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
00174 " events received did not include the \"Init\" event containing necessary info for art; exiting...";
00175 }
00176 }
00177 }
00178 }
00179
00180
00181 void
00182 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
00183 std::unique_ptr<TBufferFile>& tbuffer)
00184 {
00185 const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
00186 char* buffer = (char *)malloc(header->data_length);
00187 memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
00188
00189
00190 tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
00191 }
00192
00193 void
00194 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
00195 {
00196 const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
00197 sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
00198 const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
00199 const size_t metadata = sizeof(artdaq::NetMonHeader);
00200 const size_t totalsize = fragment.sizeBytes();
00201
00202 const size_t type = static_cast<size_t>(fragment.type());
00203
00204 if (totalsize != artdaqheader + metadata + payload)
00205 {
00206 std::stringstream errmsg;
00207 errmsg << "Error: artdaq fragment of type " <<
00208 type << ", sequence ID " <<
00209 fragment.sequenceID() <<
00210 " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
00211 " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
00212 ", metadata = " << metadata << ", payload = " << payload;
00213
00214 TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
00215
00216 if (quitOnFragmentIntegrityProblem_)
00217 {
00218 throw cet::exception("TransferWrapper") << errmsg.str();
00219 }
00220 else
00221 {
00222 return;
00223 }
00224 }
00225
00226 auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
00227
00228 if (findloc == allowedFragmentTypes_.end())
00229 {
00230 std::stringstream errmsg;
00231 errmsg << "Error: artdaq fragment appears to have type "
00232 << type << ", not found in the allowed fragment types list";
00233
00234 TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
00235 if (quitOnFragmentIntegrityProblem_)
00236 {
00237 throw cet::exception("TransferWrapper") << errmsg.str();
00238 }
00239 else
00240 {
00241 return;
00242 }
00243 }
00244 }
00245
00246 void
00247 artdaq::TransferWrapper::unregisterMonitor()
00248 {
00249 if (!monitorRegistered_)
00250 {
00251 throw cet::exception("TransferWrapper") <<
00252 "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
00253 }
00254
00255 TLOG_INFO("TransferWrapper") << "Requesting that this monitor (" << transfer_->uniqueLabel()
00256 << ") be unregistered from the dispatcher aggregator" << TLOG_ENDL;
00257
00258 xmlrpc_c::clientSimple myClient;
00259 xmlrpc_c::value result;
00260
00261 try
00262 {
00263 myClient.call(serverUrl_, "daq.unregister_monitor", "s", &result, (transfer_->uniqueLabel()).c_str());
00264 }
00265 catch (...)
00266 {
00267 std::stringstream errmsg;
00268 errmsg << "Problem attempting to unregister monitor via XML-RPC call on host " << dispatcherHost_
00269 << ", port " << dispatcherPort_ << "; possible causes are that the monitor label \""
00270 << transfer_->uniqueLabel()
00271 << "\" is unrecognized by contacted process or process at requested port doesn't exist";
00272 ExceptionHandler(ExceptionHandlerRethrow::no,
00273 errmsg.str());
00274 }
00275
00276 const std::string status = xmlrpc_c::value_string(result);
00277
00278 TLOG_INFO("TransferWrapper") << "Response from dispatcher is \""
00279 << status << "\"" << TLOG_ENDL;
00280
00281 if (status == "Success")
00282 {
00283 monitorRegistered_ = false;
00284 }
00285 else
00286 {
00287 throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
00288 }
00289 }
00290
00291
00292 artdaq::TransferWrapper::~TransferWrapper()
00293 {
00294 if (monitorRegistered_)
00295 {
00296 try
00297 {
00298 unregisterMonitor();
00299 }
00300 catch (...)
00301 {
00302 ExceptionHandler(ExceptionHandlerRethrow::no,
00303 "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
00304 }
00305 }
00306 }