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