artdaq  v3_07_01
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_master", 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, (struct sockaddr*)&addr, &arglen);
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 BOOST_AUTO_TEST_CASE(Requests)
101 {
102  artdaq::configureMessageFacility("RequestSender_t", true, true);
103  metricMan->initialize(fhicl::ParameterSet());
104  metricMan->do_start();
105  TLOG(TLVL_INFO) << "Requests Test Case BEGIN";
106  const int REQUEST_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
107  const int DELAY_TIME = 100;
108 #if 0
109  const std::string MULTICAST_IP = "227.28.12.28";
110 #else
111  const std::string MULTICAST_IP = "localhost";
112 #endif
113  fhicl::ParameterSet pset;
114  pset.put("request_port", REQUEST_PORT);
115  pset.put("request_delay_ms", DELAY_TIME);
116  pset.put("send_requests", true);
117  pset.put("request_address", MULTICAST_IP);
118  artdaq::RequestSender t(pset);
119 
120  TLOG(TLVL_DEBUG) << "Opening request listener socket";
121  auto request_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
122 
123  struct sockaddr_in si_me_request;
124 
125  int yes = 1;
126  if (setsockopt(request_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
127  {
128  TLOG(TLVL_ERROR) << "Unable to set reuse on request socket";
129  BOOST_REQUIRE_EQUAL(true, false);
130  return;
131  }
132  memset(&si_me_request, 0, sizeof(si_me_request));
133  si_me_request.sin_family = AF_INET;
134  si_me_request.sin_port = htons(REQUEST_PORT);
135  si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
136  if (bind(request_socket, (struct sockaddr*)&si_me_request, sizeof(si_me_request)) == -1)
137  {
138  TLOG(TLVL_ERROR) << "Cannot bind request socket to port " << REQUEST_PORT;
139  BOOST_REQUIRE_EQUAL(true, false);
140  return;
141  }
142 
143  if (MULTICAST_IP != "localhost")
144  {
145  struct ip_mreq mreq;
146  int sts = ResolveHost(MULTICAST_IP.c_str(), mreq.imr_multiaddr);
147  if (sts == -1)
148  {
149  TLOG(TLVL_ERROR) << "Unable to resolve multicast request address";
150  BOOST_REQUIRE_EQUAL(true, false);
151  return;
152  }
153  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
154  if (setsockopt(request_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
155  {
156  TLOG(TLVL_ERROR) << "Unable to join multicast group";
157  BOOST_REQUIRE_EQUAL(true, false);
158  return;
159  }
160  }
161 
162  TLOG(TLVL_DEBUG) << "Sending request";
163  auto start_time = std::chrono::steady_clock::now();
164  t.AddRequest(0, 0x10);
165  struct pollfd ufds[1];
166 
167  TLOG(TLVL_DEBUG) << "Receiving Request";
168  ufds[0].fd = request_socket;
169  ufds[0].events = POLLIN | POLLPRI;
170  int rv = poll(ufds, 1, 10000);
171  if (rv > 0)
172  {
173  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
174  {
175  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
176  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
177  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
178  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
180  recv(request_socket, &buffer[0], buffer.size(), 0);
181  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
182  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
183  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
184  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::Normal));
185  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
186  if (hdr_buffer.isValid())
187  {
188  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
189  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
190 
191  for (auto& buffer : pkt_buffer)
192  {
193  TRACE_REQUIRE_EQUAL(buffer.isValid(), true);
194  TRACE_REQUIRE_EQUAL(buffer.sequence_id, 0);
195  TRACE_REQUIRE_EQUAL(buffer.timestamp, 0x10);
196  }
197  }
198  else
199  {
200  TLOG(TLVL_ERROR) << "Invalid header received";
201  BOOST_REQUIRE_EQUAL(false, true);
202  return;
203  }
204  }
205  else
206  {
207  TLOG(TLVL_ERROR) << "Wrong event type from poll";
208  BOOST_REQUIRE_EQUAL(false, true);
209  return;
210  }
211  }
212  else
213  {
214  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
215  BOOST_REQUIRE_EQUAL(false, true);
216  return;
217  }
218 
219  // SetRequestMode and AddRequest BOTH send requests...
220  start_time = std::chrono::steady_clock::now();
222  t.AddRequest(2, 0x20);
223  rv = poll(ufds, 1, 1000);
224  if (rv > 0)
225  {
226  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
227  {
228  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
229  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
230  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
231  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
233  recv(request_socket, &buffer[0], buffer.size(), 0);
234  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
235  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
236  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
237  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
238  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
239  if (hdr_buffer.isValid())
240  {
241  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
242  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
243 
244  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
245  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
246  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
247  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
248  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
249  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
250  }
251  else
252  {
253  TLOG(TLVL_ERROR) << "Invalid header received";
254  BOOST_REQUIRE_EQUAL(false, true);
255  return;
256  }
257  }
258  else
259  {
260  TLOG(TLVL_ERROR) << "Wrong event type from poll";
261  BOOST_REQUIRE_EQUAL(false, true);
262  return;
263  }
264  }
265  else
266  {
267  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
268  BOOST_REQUIRE_EQUAL(false, true);
269  return;
270  }
271  rv = poll(ufds, 1, 1000);
272  if (rv > 0)
273  {
274  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
275  {
276  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
277  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
278  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
279  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
281  recv(request_socket, &buffer[0], buffer.size(), 0);
282  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
283  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
284  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
285  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
286  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
287  if (hdr_buffer.isValid())
288  {
289  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
290  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
291 
292  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
293  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
294  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
295  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
296  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
297  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
298  }
299  else
300  {
301  TLOG(TLVL_ERROR) << "Invalid header received";
302  BOOST_REQUIRE_EQUAL(false, true);
303  return;
304  }
305  }
306  else
307  {
308  TLOG(TLVL_ERROR) << "Wrong event type from poll";
309  BOOST_REQUIRE_EQUAL(false, true);
310  return;
311  }
312  }
313  else
314  {
315  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
316  BOOST_REQUIRE_EQUAL(false, true);
317  return;
318  }
319 
320  t.RemoveRequest(0);
321  t.RemoveRequest(2);
322  t.AddRequest(3, 0x30);
323  start_time = std::chrono::steady_clock::now();
324  rv = poll(ufds, 1, 1000);
325  if (rv > 0)
326  {
327  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
328  {
329  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
330  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
331  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
332  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
334  recv(request_socket, &buffer[0], buffer.size(), 0);
335  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
336  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
337  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
338  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
339  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
340  if (hdr_buffer.isValid())
341  {
342  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
343  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
344 
345  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
346  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 3);
347  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x30);
348  }
349  else
350  {
351  TLOG(TLVL_ERROR) << "Invalid header received";
352  BOOST_REQUIRE_EQUAL(false, true);
353  return;
354  }
355  }
356  else
357  {
358  TLOG(TLVL_ERROR) << "Wrong event type from poll";
359  BOOST_REQUIRE_EQUAL(false, true);
360  return;
361  }
362  }
363  else
364  {
365  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
366  BOOST_REQUIRE_EQUAL(false, true);
367  return;
368  }
369 
370  close(request_socket);
371  TLOG(TLVL_INFO) << "Requests Test Case END";
373 }
374 
375 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.