artdaq  v2_03_00
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
TransferWrapper.cc
1 #include "artdaq/TransferPlugins/TransferWrapper.hh"
2 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
3 #include "artdaq/DAQdata/NetMonHeader.hh"
4 #include "artdaq/DAQdata/Globals.hh"
5 #include "artdaq-core/Utilities/ExceptionHandler.hh"
6 #include "artdaq-core/Data/Fragment.hh"
7 
8 #include "cetlib/BasicPluginFactory.h"
9 #include "fhiclcpp/ParameterSet.h"
10 #pragma GCC diagnostic push
11 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
12 #include <xmlrpc-c/girerr.hpp>
13 #include <xmlrpc-c/base.hpp>
14 #include <xmlrpc-c/client_simple.hpp>
15 #pragma GCC diagnostic pop
16 
17 #include "TBufferFile.h"
18 
19 #include <limits>
20 #include <iostream>
21 #include <string>
22 #include <sstream>
23 #include <csignal>
24 
25 namespace
26 {
27  volatile std::sig_atomic_t gSignalStatus = 0;
28 }
29 
34 void signal_handler(int signal)
35 {
36  gSignalStatus = signal;
37 }
38 
39 artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset) :
40  timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
41  , dispatcherHost_(pset.get<std::string>("dispatcherHost"))
42  , dispatcherPort_(pset.get<std::string>("dispatcherPort"))
43  , serverUrl_("http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2")
44  , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
45  , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", {226, 227, 229}))
46  , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
47  , debugLevel_(pset.get<std::size_t>("debugLevel", 0))
48  , monitorRegistered_(false)
49 {
50  std::signal(SIGINT, signal_handler);
51 
52  try
53  {
54  transfer_ = MakeTransferPlugin(pset, "transfer_plugin", TransferInterface::Role::kReceive);
55  }
56  catch (...)
57  {
58  ExceptionHandler(ExceptionHandlerRethrow::yes,
59  "TransferWrapper: failure in call to MakeTransferPlugin");
60  }
61 
62  xmlrpc_c::clientSimple myClient;
63  xmlrpc_c::value result;
64 
65  TLOG_INFO("TransferWrapper") << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
66  << "\") with the dispatcher aggregator" << TLOG_ENDL;
67 
68  try
69  {
70  myClient.call(serverUrl_, "daq.register_monitor", "s", &result, pset.to_string().c_str());
71  }
72  catch (...)
73  {
74  std::stringstream errmsg;
75  errmsg << "Problem attempting XML-RPC call on host " << dispatcherHost_
76  << ", port " << dispatcherPort_ << "; possible causes are malformed FHiCL or nonexistent process at requested port";
77  ExceptionHandler(ExceptionHandlerRethrow::yes,
78  errmsg.str());
79  }
80 
81  const std::string status = xmlrpc_c::value_string(result);
82 
83  TLOG_INFO("TransferWrapper") << "Response from dispatcher is \""
84  << status << "\"" << TLOG_ENDL;
85 
86  if (status == "Success")
87  {
88  monitorRegistered_ = true;
89  }
90  else
91  {
92  throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response";
93  }
94 }
95 
96 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
97 {
98  std::unique_ptr<artdaq::Fragment> fragmentPtr;
99  bool receivedFragment = false;
100  static bool initialized = false;
101  static size_t fragments_received = 0;
102 
103  while (true && !gSignalStatus)
104  {
105  fragmentPtr = std::make_unique<artdaq::Fragment>();
106 
107  while (!receivedFragment)
108  {
109  if (gSignalStatus)
110  {
111  TLOG_INFO("TransferWrapper") << "Ctrl-C appears to have been hit" << TLOG_ENDL;
112  unregisterMonitor();
113  return;
114  }
115 
116  try
117  {
118  auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
119 
121  {
122  receivedFragment = true;
123  fragments_received++;
124 
125  static size_t cntr = 1;
126 
127  if (debugLevel_ > 1)
128  {
129  TLOG_INFO("TransferWrapper") << "Received " << cntr++ << "-th event, "
130  << "seqID == " << fragmentPtr->sequenceID()
131  << ", type == " << static_cast<int>(fragmentPtr->type()) << TLOG_ENDL;
132  }
133  continue;
134  }
135  else
136  {
137  if (debugLevel_ > 0)
138  {
139  TLOG_WARNING("TransferWrapper") << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again" << TLOG_ENDL;
140  }
141  }
142  }
143  catch (...)
144  {
145  ExceptionHandler(ExceptionHandlerRethrow::yes,
146  "Problem receiving data in TransferWrapper::receiveMessage");
147  }
148  }
149 
150  try
151  {
152  extractTBufferFile(*fragmentPtr, msg);
153  }
154  catch (...)
155  {
156  ExceptionHandler(ExceptionHandlerRethrow::yes,
157  "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
158  }
159 
160  checkIntegrity(*fragmentPtr);
161 
162  if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
163  {
164  initialized = true;
165  break;
166  }
167  else
168  {
169  receivedFragment = false;
170 
171  if (fragments_received > maxEventsBeforeInit_)
172  {
173  throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
174  " events received did not include the \"Init\" event containing necessary info for art; exiting...";
175  }
176  }
177  }
178 }
179 
180 
181 void
182 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
183  std::unique_ptr<TBufferFile>& tbuffer)
184 {
185  const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
186  char* buffer = (char *)malloc(header->data_length);
187  memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
188 
189  // TBufferFile takes ownership of the contents of memory passed to it
190  tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
191 }
192 
193 void
194 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
195 {
196  const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
197  sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
198  const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
199  const size_t metadata = sizeof(artdaq::NetMonHeader);
200  const size_t totalsize = fragment.sizeBytes();
201 
202  const size_t type = static_cast<size_t>(fragment.type());
203 
204  if (totalsize != artdaqheader + metadata + payload)
205  {
206  std::stringstream errmsg;
207  errmsg << "Error: artdaq fragment of type " <<
208  type << ", sequence ID " <<
209  fragment.sequenceID() <<
210  " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
211  " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
212  ", metadata = " << metadata << ", payload = " << payload;
213 
214  TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
215 
216  if (quitOnFragmentIntegrityProblem_)
217  {
218  throw cet::exception("TransferWrapper") << errmsg.str();
219  }
220  else
221  {
222  return;
223  }
224  }
225 
226  auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
227 
228  if (findloc == allowedFragmentTypes_.end())
229  {
230  std::stringstream errmsg;
231  errmsg << "Error: artdaq fragment appears to have type "
232  << type << ", not found in the allowed fragment types list";
233 
234  TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
235  if (quitOnFragmentIntegrityProblem_)
236  {
237  throw cet::exception("TransferWrapper") << errmsg.str();
238  }
239  else
240  {
241  return;
242  }
243  }
244 }
245 
246 void
247 artdaq::TransferWrapper::unregisterMonitor()
248 {
249  if (!monitorRegistered_)
250  {
251  throw cet::exception("TransferWrapper") <<
252  "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
253  }
254 
255  TLOG_INFO("TransferWrapper") << "Requesting that this monitor (" << transfer_->uniqueLabel()
256  << ") be unregistered from the dispatcher aggregator" << TLOG_ENDL;
257 
258  xmlrpc_c::clientSimple myClient;
259  xmlrpc_c::value result;
260 
261  try
262  {
263  myClient.call(serverUrl_, "daq.unregister_monitor", "s", &result, (transfer_->uniqueLabel()).c_str());
264  }
265  catch (...)
266  {
267  std::stringstream errmsg;
268  errmsg << "Problem attempting to unregister monitor via XML-RPC call on host " << dispatcherHost_
269  << ", port " << dispatcherPort_ << "; possible causes are that the monitor label \""
270  << transfer_->uniqueLabel()
271  << "\" is unrecognized by contacted process or process at requested port doesn't exist";
272  ExceptionHandler(ExceptionHandlerRethrow::no,
273  errmsg.str());
274  }
275 
276  const std::string status = xmlrpc_c::value_string(result);
277 
278  TLOG_INFO("TransferWrapper") << "Response from dispatcher is \""
279  << status << "\"" << TLOG_ENDL;
280 
281  if (status == "Success")
282  {
283  monitorRegistered_ = false;
284  }
285  else
286  {
287  throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
288  }
289 }
290 
291 
293 {
294  if (monitorRegistered_)
295  {
296  try
297  {
298  unregisterMonitor();
299  }
300  catch (...)
301  {
302  ExceptionHandler(ExceptionHandlerRethrow::no,
303  "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
304  }
305  }
306 }
void receiveMessage(std::unique_ptr< TBufferFile > &msg)
Receive a Fragment from the TransferInterface, and send it to art.
TransferWrapper(const fhicl::ParameterSet &pset)
TransferWrapper Constructor.
virtual ~TransferWrapper()
TransferWrapper Destructor.
static const int RECV_TIMEOUT
Value to be returned upon receive timeout. Because receivers otherwise return rank, this is also the limit on the number of ranks that artdaq currently supports.
This TransferInterface is a Receiver.
std::unique_ptr< artdaq::TransferInterface > MakeTransferPlugin(const fhicl::ParameterSet &pset, std::string plugin_label, TransferInterface::Role role)
Load a TransferInterface plugin.
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:14
volatile std::sig_atomic_t gSignalStatus
Stores singal from signal handler.
uint64_t data_length
The length of the message.
Definition: NetMonHeader.hh:16