artdaq  v3_09_00
RequestSender_t.cc
1 #define TRACE_NAME "RequestSender_t"
2 
3 #include "artdaq/DAQrate/RequestSender.hh"
4 
5 #define BOOST_TEST_MODULE RequestSender_t
6 #include <sys/poll.h>
9 #include "artdaq/DAQrate/detail/RoutingPacket.hh"
10 #include "cetlib/quiet_unit_test.hpp"
11 #include "cetlib_except/exception.h"
12 
13 BOOST_AUTO_TEST_SUITE(RequestSender_test)
14 
15 #define TRACE_REQUIRE_EQUAL(l, r) \
16  do \
17  { \
18  if ((l) == (r)) \
19  { \
20  TLOG(TLVL_DEBUG) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...YES!"; \
21  } \
22  else \
23  { \
24  TLOG(TLVL_ERROR) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...NO!"; \
25  } \
26  BOOST_REQUIRE_EQUAL((l), (r)); \
27  } while (0)
28 
29 BOOST_AUTO_TEST_CASE(Construct)
30 {
31  artdaq::configureMessageFacility("RequestSender_t", true, true);
32  metricMan->initialize(fhicl::ParameterSet());
33  metricMan->do_start();
34  TLOG(TLVL_INFO) << "Construct Test Case BEGIN";
35  fhicl::ParameterSet pset;
36  artdaq::RequestSender t(pset);
37  BOOST_REQUIRE_EQUAL(t.GetRequestMode(), artdaq::detail::RequestMessageMode::Normal);
38  TLOG(TLVL_INFO) << "Construct Test Case END";
39 }
40 
41 BOOST_AUTO_TEST_CASE(Tokens)
42 {
43  artdaq::configureMessageFacility("RequestSender_t", true, true);
44  metricMan->initialize(fhicl::ParameterSet());
45  metricMan->do_start();
46  TLOG(TLVL_INFO) << "Tokens Test Case BEGIN";
47  const int TOKEN_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
48  TLOG(TLVL_DEBUG) << "Opening token listener socket";
49  auto token_socket = TCP_listen_fd(TOKEN_PORT, 3 * sizeof(artdaq::detail::RoutingToken));
50 
51  fhicl::ParameterSet token_pset;
52  token_pset.put("routing_token_port", TOKEN_PORT);
53  token_pset.put("use_routing_manager", true);
54  fhicl::ParameterSet pset;
55  pset.put("routing_token_config", token_pset);
56  artdaq::RequestSender t(pset);
57 
58  my_rank = 0;
59 
60  BOOST_REQUIRE(token_socket != -1);
61  if (token_socket == -1)
62  {
63  TLOG(TLVL_ERROR) << "Token listener socket was not opened successfully.";
64  BOOST_REQUIRE_EQUAL(false, true);
65  return;
66  }
67 
68  TLOG(TLVL_DEBUG) << "Accepting new connection on token_socket";
69  sockaddr_in addr;
70  socklen_t arglen = sizeof(addr);
71  auto conn_sock = accept(token_socket, reinterpret_cast<struct sockaddr*>(&addr), &arglen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
72 
73  t.SendRoutingToken(120, 130);
74 
76  auto sts = read(conn_sock, &buff, sizeof(artdaq::detail::RoutingToken));
77 
78  TRACE_REQUIRE_EQUAL(sts, sizeof(artdaq::detail::RoutingToken));
79  TRACE_REQUIRE_EQUAL(buff.header, TOKEN_MAGIC);
80  TRACE_REQUIRE_EQUAL(buff.new_slots_free, 120);
81  TRACE_REQUIRE_EQUAL(buff.run_number, 130);
82  TRACE_REQUIRE_EQUAL(buff.rank, 0);
83 
84  my_rank = 13;
85  t.SendRoutingToken(335, 17);
86 
87  sts = read(conn_sock, &buff, sizeof(artdaq::detail::RoutingToken));
88 
89  TRACE_REQUIRE_EQUAL(sts, sizeof(artdaq::detail::RoutingToken));
90  TRACE_REQUIRE_EQUAL(buff.header, TOKEN_MAGIC);
91  TRACE_REQUIRE_EQUAL(buff.new_slots_free, 335);
92  TRACE_REQUIRE_EQUAL(buff.run_number, 17);
93  TRACE_REQUIRE_EQUAL(buff.rank, 13);
94 
95  close(conn_sock);
96  close(token_socket);
97  TLOG(TLVL_INFO) << "Tokens Test Case END";
98 }
99 
100 // NOLINTNEXTLINE(readability-function-size)
101 BOOST_AUTO_TEST_CASE(Requests)
102 {
103  artdaq::configureMessageFacility("RequestSender_t", true, true);
104  metricMan->initialize(fhicl::ParameterSet());
105  metricMan->do_start();
106  TLOG(TLVL_INFO) << "Requests Test Case BEGIN";
107  const int REQUEST_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
108  const int DELAY_TIME = 100;
109 #if 0
110  const std::string MULTICAST_IP = "227.28.12.28";
111 #else
112  const std::string MULTICAST_IP = "localhost";
113 #endif
114  fhicl::ParameterSet pset;
115  pset.put("request_port", REQUEST_PORT);
116  pset.put("request_delay_ms", DELAY_TIME);
117  pset.put("send_requests", true);
118  pset.put("request_address", MULTICAST_IP);
119  artdaq::RequestSender t(pset);
120 
121  TLOG(TLVL_DEBUG) << "Opening request listener socket";
122  auto request_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
123 
124  struct sockaddr_in si_me_request;
125 
126  int yes = 1;
127  if (setsockopt(request_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
128  {
129  TLOG(TLVL_ERROR) << "Unable to set reuse on request socket";
130  BOOST_REQUIRE_EQUAL(true, false);
131  return;
132  }
133  memset(&si_me_request, 0, sizeof(si_me_request));
134  si_me_request.sin_family = AF_INET;
135  si_me_request.sin_port = htons(REQUEST_PORT);
136  si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
137  if (bind(request_socket, reinterpret_cast<struct sockaddr*>(&si_me_request), sizeof(si_me_request)) == -1) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
138  {
139  TLOG(TLVL_ERROR) << "Cannot bind request socket to port " << REQUEST_PORT;
140  BOOST_REQUIRE_EQUAL(true, false);
141  return;
142  }
143 
144  if (MULTICAST_IP != "localhost")
145  {
146  struct ip_mreq mreq;
147  int sts = ResolveHost(MULTICAST_IP.c_str(), mreq.imr_multiaddr);
148  if (sts == -1)
149  {
150  TLOG(TLVL_ERROR) << "Unable to resolve multicast request address";
151  BOOST_REQUIRE_EQUAL(true, false);
152  return;
153  }
154  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
155  if (setsockopt(request_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
156  {
157  TLOG(TLVL_ERROR) << "Unable to join multicast group";
158  BOOST_REQUIRE_EQUAL(true, false);
159  return;
160  }
161  }
162 
163  TLOG(TLVL_DEBUG) << "Sending request";
164  auto start_time = std::chrono::steady_clock::now();
165  t.AddRequest(0, 0x10);
166  struct pollfd ufds[1];
167 
168  TLOG(TLVL_DEBUG) << "Receiving Request";
169  ufds[0].fd = request_socket;
170  ufds[0].events = POLLIN | POLLPRI;
171  int rv = poll(ufds, 1, 10000);
172  if (rv > 0)
173  {
174  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
175  {
176  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
177  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
178  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
179  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
181  recv(request_socket, &buffer[0], buffer.size(), 0);
182  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
183  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
184  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
185  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::Normal));
186  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
187  if (hdr_buffer.isValid())
188  {
189  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
190  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
191 
192  for (auto& buffer : pkt_buffer)
193  {
194  TRACE_REQUIRE_EQUAL(buffer.isValid(), true);
195  TRACE_REQUIRE_EQUAL(buffer.sequence_id, 0);
196  TRACE_REQUIRE_EQUAL(buffer.timestamp, 0x10);
197  }
198  }
199  else
200  {
201  TLOG(TLVL_ERROR) << "Invalid header received";
202  BOOST_REQUIRE_EQUAL(false, true);
203  return;
204  }
205  }
206  else
207  {
208  TLOG(TLVL_ERROR) << "Wrong event type from poll";
209  BOOST_REQUIRE_EQUAL(false, true);
210  return;
211  }
212  }
213  else
214  {
215  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
216  BOOST_REQUIRE_EQUAL(false, true);
217  return;
218  }
219 
220  // SetRequestMode and AddRequest BOTH send requests...
221  start_time = std::chrono::steady_clock::now();
223  t.AddRequest(2, 0x20);
224  rv = poll(ufds, 1, 1000);
225  if (rv > 0)
226  {
227  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
228  {
229  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
230  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
231  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
232  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
234  recv(request_socket, &buffer[0], buffer.size(), 0);
235  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
236  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
237  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
238  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
239  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
240  if (hdr_buffer.isValid())
241  {
242  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
243  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
244 
245  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
246  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
247  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
248  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
249  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
250  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
251  }
252  else
253  {
254  TLOG(TLVL_ERROR) << "Invalid header received";
255  BOOST_REQUIRE_EQUAL(false, true);
256  return;
257  }
258  }
259  else
260  {
261  TLOG(TLVL_ERROR) << "Wrong event type from poll";
262  BOOST_REQUIRE_EQUAL(false, true);
263  return;
264  }
265  }
266  else
267  {
268  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
269  BOOST_REQUIRE_EQUAL(false, true);
270  return;
271  }
272  rv = poll(ufds, 1, 1000);
273  if (rv > 0)
274  {
275  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
276  {
277  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
278  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
279  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
280  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
282  recv(request_socket, &buffer[0], buffer.size(), 0);
283  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
284  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
285  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
286  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
287  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
288  if (hdr_buffer.isValid())
289  {
290  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
291  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
292 
293  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
294  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
295  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
296  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
297  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
298  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
299  }
300  else
301  {
302  TLOG(TLVL_ERROR) << "Invalid header received";
303  BOOST_REQUIRE_EQUAL(false, true);
304  return;
305  }
306  }
307  else
308  {
309  TLOG(TLVL_ERROR) << "Wrong event type from poll";
310  BOOST_REQUIRE_EQUAL(false, true);
311  return;
312  }
313  }
314  else
315  {
316  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
317  BOOST_REQUIRE_EQUAL(false, true);
318  return;
319  }
320 
321  t.RemoveRequest(0);
322  t.RemoveRequest(2);
323  t.AddRequest(3, 0x30);
324  start_time = std::chrono::steady_clock::now();
325  rv = poll(ufds, 1, 1000);
326  if (rv > 0)
327  {
328  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
329  {
330  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
331  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
332  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
333  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
335  recv(request_socket, &buffer[0], buffer.size(), 0);
336  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
337  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
338  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
339  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
340  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
341  if (hdr_buffer.isValid())
342  {
343  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
344  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
345 
346  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
347  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 3);
348  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x30);
349  }
350  else
351  {
352  TLOG(TLVL_ERROR) << "Invalid header received";
353  BOOST_REQUIRE_EQUAL(false, true);
354  return;
355  }
356  }
357  else
358  {
359  TLOG(TLVL_ERROR) << "Wrong event type from poll";
360  BOOST_REQUIRE_EQUAL(false, true);
361  return;
362  }
363  }
364  else
365  {
366  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
367  BOOST_REQUIRE_EQUAL(false, true);
368  return;
369  }
370 
371  close(request_socket);
372  TLOG(TLVL_INFO) << "Requests Test Case END";
374 }
375 
376 BOOST_AUTO_TEST_SUITE_END()
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.cc:33
End of Run mode (Used to end request processing on receiver)
static void CleanUpGlobals()
Clean up statically-allocated Manager class instances.
Definition: Globals.hh:150
The RequestSender contains methods used to send data requests and Routing tokens. ...
RequestMessageMode mode
Communicates additional information to the Request receiver.
bool isValid() const
Check the magic bytes of the packet.
unsigned new_slots_free
The number of slots free in the token sender (usually 1)
Header of a RequestMessage. Contains magic bytes for validation and a count of expected RequestPacket...
uint32_t packet_count
The number of RequestPackets in this Request message.
The RoutingToken contains the magic bytes, the rank of the token sender, and the number of slots free...
int TCP_listen_fd(int port, int rcvbuf)
Create a TCP listening socket on the given port and INADDR_ANY, with the given receive buffer...
The RequestPacket contains information about a single data request.
int rank
The rank from which the RoutingToken came.
unsigned run_number
The Run with which this token should be associated.
uint32_t header
The magic bytes that help validate the RoutingToken.