artdaq  v3_12_02
RequestSender_t.cc
1 #define BOOST_TEST_MODULE RequestSender_t
2 #include "boost/test/unit_test.hpp"
3 
4 #include "tracemf.h"
5 #define TRACE_NAME "RequestSender_t"
6 
7 #include "artdaq-core/Utilities/configureMessageFacility.hh"
10 #include "artdaq/DAQrate/detail/RequestSender.hh"
11 #include "artdaq/DAQrate/detail/RoutingPacket.hh"
12 
13 #include <sys/poll.h>
14 
15 BOOST_AUTO_TEST_SUITE(RequestSender_test)
16 
17 #define TRACE_REQUIRE_EQUAL(l, r) \
18  do \
19  { \
20  if ((l) == (r)) \
21  { \
22  TLOG(TLVL_DEBUG) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...YES!"; \
23  } \
24  else \
25  { \
26  TLOG(TLVL_ERROR) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...NO!"; \
27  } \
28  BOOST_REQUIRE_EQUAL((l), (r)); \
29  } while (0)
30 
31 BOOST_AUTO_TEST_CASE(Construct)
32 {
33  artdaq::configureMessageFacility("RequestSender_t", true, true);
34  metricMan->initialize(fhicl::ParameterSet());
35  metricMan->do_start();
36  TLOG(TLVL_INFO) << "Construct Test Case BEGIN";
37  fhicl::ParameterSet pset;
38  artdaq::RequestSender t(pset);
40  TLOG(TLVL_INFO) << "Construct Test Case END";
41 }
42 
43 // NOLINTNEXTLINE(readability-function-size)
44 BOOST_AUTO_TEST_CASE(Requests)
45 {
46  artdaq::configureMessageFacility("RequestSender_t", true, true);
47  metricMan->initialize(fhicl::ParameterSet());
48  metricMan->do_start();
49  TLOG(TLVL_INFO) << "Requests Test Case BEGIN";
50  const int REQUEST_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
51  const int DELAY_TIME = 100;
52 #if 0
53  const std::string MULTICAST_IP = "227.28.12.28";
54 #else
55  const std::string MULTICAST_IP = "localhost";
56 #endif
57  fhicl::ParameterSet pset;
58  pset.put("request_port", REQUEST_PORT);
59  pset.put("request_delay_ms", DELAY_TIME);
60  pset.put("send_requests", true);
61  pset.put("request_address", MULTICAST_IP);
62  artdaq::RequestSender t(pset);
63 
64  TLOG(TLVL_DEBUG) << "Opening request listener socket";
65  auto request_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
66 
67  struct sockaddr_in si_me_request;
68 
69  int yes = 1;
70  if (setsockopt(request_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
71  {
72  TLOG(TLVL_ERROR) << "Unable to set reuse on request socket";
73  BOOST_REQUIRE_EQUAL(true, false);
74  return;
75  }
76  memset(&si_me_request, 0, sizeof(si_me_request));
77  si_me_request.sin_family = AF_INET;
78  si_me_request.sin_port = htons(REQUEST_PORT);
79  si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
80  if (bind(request_socket, reinterpret_cast<struct sockaddr*>(&si_me_request), sizeof(si_me_request)) == -1) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
81  {
82  TLOG(TLVL_ERROR) << "Cannot bind request socket to port " << REQUEST_PORT;
83  BOOST_REQUIRE_EQUAL(true, false);
84  return;
85  }
86 
87  if (MULTICAST_IP != "localhost")
88  {
89  struct ip_mreq mreq;
90  int sts = ResolveHost(MULTICAST_IP.c_str(), mreq.imr_multiaddr);
91  if (sts == -1)
92  {
93  TLOG(TLVL_ERROR) << "Unable to resolve multicast request address";
94  BOOST_REQUIRE_EQUAL(true, false);
95  return;
96  }
97  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
98  if (setsockopt(request_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
99  {
100  TLOG(TLVL_ERROR) << "Unable to join multicast group";
101  BOOST_REQUIRE_EQUAL(true, false);
102  return;
103  }
104  }
105 
106  TLOG(TLVL_DEBUG) << "Sending request";
107  auto start_time = std::chrono::steady_clock::now();
108  t.AddRequest(0, 0x10);
109  struct pollfd ufds[1];
110 
111  TLOG(TLVL_DEBUG) << "Receiving Request";
112  ufds[0].fd = request_socket;
113  ufds[0].events = POLLIN | POLLPRI;
114  int rv = poll(ufds, 1, 10000);
115  if (rv > 0)
116  {
117  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
118  {
119  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
120  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
121  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
122  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
124  recv(request_socket, &buffer[0], buffer.size(), 0);
125  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
126  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
127  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
128  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::Normal));
129  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
130  if (hdr_buffer.isValid())
131  {
132  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
133  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
134 
135  for (auto& buffer : pkt_buffer)
136  {
137  TRACE_REQUIRE_EQUAL(buffer.isValid(), true);
138  TRACE_REQUIRE_EQUAL(buffer.sequence_id, 0);
139  TRACE_REQUIRE_EQUAL(buffer.timestamp, 0x10);
140  }
141  }
142  else
143  {
144  TLOG(TLVL_ERROR) << "Invalid header received";
145  BOOST_REQUIRE_EQUAL(false, true);
146  return;
147  }
148  }
149  else
150  {
151  TLOG(TLVL_ERROR) << "Wrong event type from poll";
152  BOOST_REQUIRE_EQUAL(false, true);
153  return;
154  }
155  }
156  else
157  {
158  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
159  BOOST_REQUIRE_EQUAL(false, true);
160  return;
161  }
162 
163  // SetRequestMode and AddRequest BOTH send requests...
164  start_time = std::chrono::steady_clock::now();
166  t.AddRequest(2, 0x20);
167  rv = poll(ufds, 1, 1000);
168  if (rv > 0)
169  {
170  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
171  {
172  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
173  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
174  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
175  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
177  recv(request_socket, &buffer[0], buffer.size(), 0);
178  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
179  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
180  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
181  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
182  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
183  if (hdr_buffer.isValid())
184  {
185  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
186  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
187 
188  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
189  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
190  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
191  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
192  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
193  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
194  }
195  else
196  {
197  TLOG(TLVL_ERROR) << "Invalid header received";
198  BOOST_REQUIRE_EQUAL(false, true);
199  return;
200  }
201  }
202  else
203  {
204  TLOG(TLVL_ERROR) << "Wrong event type from poll";
205  BOOST_REQUIRE_EQUAL(false, true);
206  return;
207  }
208  }
209  else
210  {
211  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
212  BOOST_REQUIRE_EQUAL(false, true);
213  return;
214  }
215  rv = poll(ufds, 1, 1000);
216  if (rv > 0)
217  {
218  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
219  {
220  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
221  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
222  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
223  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
225  recv(request_socket, &buffer[0], buffer.size(), 0);
226  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
227  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
228  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
229  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
230  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
231  if (hdr_buffer.isValid())
232  {
233  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
234  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
235 
236  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
237  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
238  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
239  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
240  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
241  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
242  }
243  else
244  {
245  TLOG(TLVL_ERROR) << "Invalid header received";
246  BOOST_REQUIRE_EQUAL(false, true);
247  return;
248  }
249  }
250  else
251  {
252  TLOG(TLVL_ERROR) << "Wrong event type from poll";
253  BOOST_REQUIRE_EQUAL(false, true);
254  return;
255  }
256  }
257  else
258  {
259  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
260  BOOST_REQUIRE_EQUAL(false, true);
261  return;
262  }
263 
264  t.RemoveRequest(0);
265  t.RemoveRequest(2);
266  t.AddRequest(3, 0x30);
267  start_time = std::chrono::steady_clock::now();
268  rv = poll(ufds, 1, 1000);
269  if (rv > 0)
270  {
271  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
272  {
273  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
274  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
275  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
276  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
278  recv(request_socket, &buffer[0], buffer.size(), 0);
279  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
280  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
281  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
282  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
283  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
284  if (hdr_buffer.isValid())
285  {
286  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
287  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
288 
289  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
290  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 3);
291  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x30);
292  }
293  else
294  {
295  TLOG(TLVL_ERROR) << "Invalid header received";
296  BOOST_REQUIRE_EQUAL(false, true);
297  return;
298  }
299  }
300  else
301  {
302  TLOG(TLVL_ERROR) << "Wrong event type from poll";
303  BOOST_REQUIRE_EQUAL(false, true);
304  return;
305  }
306  }
307  else
308  {
309  TLOG(TLVL_ERROR) << "Timeout occured waiting for request";
310  BOOST_REQUIRE_EQUAL(false, true);
311  return;
312  }
313 
314  close(request_socket);
315  TLOG(TLVL_INFO) << "Requests Test Case END";
317 }
318 
319 BOOST_AUTO_TEST_SUITE_END()
void RemoveRequest(Fragment::sequence_id_t seqID)
Remove a request from the request list.
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.cc:34
detail::RequestMessageMode GetRequestMode() const
Get the mode for RequestMessages.
End of Run mode (Used to end request processing on receiver)
static void CleanUpGlobals()
Clean up statically-allocated Manager class instances.
Definition: Globals.hh:156
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.
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.
void SetRequestMode(detail::RequestMessageMode mode)
Set the mode for RequestMessages. Used to indicate when RequestSender should enter &quot;EndOfRun&quot; mode...
The RequestPacket contains information about a single data request.
void AddRequest(Fragment::sequence_id_t seqID, Fragment::timestamp_t timestamp)
Add a request to the request list.