artdaq  v3_04_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 "cetlib/quiet_unit_test.hpp"
7 #include "cetlib_except/exception.h"
9 #include "artdaq/DAQrate/detail/RoutingPacket.hh"
11 #include <sys/poll.h>
12 
13 
14 BOOST_AUTO_TEST_SUITE(RequestSender_test)
15 
16 #define TRACE_REQUIRE_EQUAL(l,r) do { \
17 if(l == r) { \
18 TLOG(TLVL_DEBUG) << __LINE__ << ": Checking if " << #l << " (" << l << ") equals " << #r << " (" << r << ")...YES!" ; \
19 } \
20 else \
21 { \
22  TLOG(TLVL_ERROR) << __LINE__ << ": Checking if " << #l << " (" << l << ") equals " << #r << " (" << r << ")...NO!" ; \
23 } \
24  BOOST_REQUIRE_EQUAL(l, r); \
25 } while(0)
26 
27 BOOST_AUTO_TEST_CASE(Construct)
28 {
29  artdaq::configureMessageFacility("RequestSender_t", true, true);
30  metricMan->initialize(fhicl::ParameterSet());
31  metricMan->do_start();
32  TLOG(TLVL_INFO) << "Construct Test Case BEGIN" ;
33  fhicl::ParameterSet pset;
34  artdaq::RequestSender t(pset);
35  BOOST_REQUIRE_EQUAL(t.GetRequestMode(), artdaq::detail::RequestMessageMode::Normal);
36  TLOG(TLVL_INFO) << "Construct Test Case END";
37 }
38 
39 BOOST_AUTO_TEST_CASE(Tokens)
40 {
41  artdaq::configureMessageFacility("RequestSender_t", true, true);
42  metricMan->initialize(fhicl::ParameterSet());
43  metricMan->do_start();
44  TLOG(TLVL_INFO) << "Tokens Test Case BEGIN" ;
45  const int TOKEN_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
46  TLOG(TLVL_DEBUG) << "Opening token listener socket" ;
47  auto token_socket = TCP_listen_fd(TOKEN_PORT, 3 * sizeof(artdaq::detail::RoutingToken));
48 
49  fhicl::ParameterSet token_pset;
50  token_pset.put("routing_token_port", TOKEN_PORT);
51  token_pset.put("use_routing_master", true);
52  fhicl::ParameterSet pset;
53  pset.put("routing_token_config", token_pset);
54  artdaq::RequestSender t(pset);
55 
56  my_rank = 0;
57 
58 
59  BOOST_REQUIRE(token_socket != -1);
60  if (token_socket == -1)
61  {
62  TLOG(TLVL_ERROR) << "Token listener socket was not opened successfully." ;
63  BOOST_REQUIRE_EQUAL(false, true);
64  return;
65  }
66 
67  TLOG(TLVL_DEBUG) << "Accepting new connection on token_socket" ;
68  sockaddr_in addr;
69  socklen_t arglen = sizeof(addr);
70  auto conn_sock = accept(token_socket, (struct sockaddr*)&addr, &arglen);
71 
72  t.SendRoutingToken(120, 130);
73 
75  auto sts = read(conn_sock, &buff, sizeof(artdaq::detail::RoutingToken));
76 
77  TRACE_REQUIRE_EQUAL(sts, sizeof(artdaq::detail::RoutingToken));
78  TRACE_REQUIRE_EQUAL(buff.header, TOKEN_MAGIC);
79  TRACE_REQUIRE_EQUAL(buff.new_slots_free, 120);
80  TRACE_REQUIRE_EQUAL(buff.run_number, 130);
81  TRACE_REQUIRE_EQUAL(buff.rank, 0);
82 
83  my_rank = 13;
84  t.SendRoutingToken(335, 17);
85 
86  sts = read(conn_sock, &buff, sizeof(artdaq::detail::RoutingToken));
87 
88  TRACE_REQUIRE_EQUAL(sts, sizeof(artdaq::detail::RoutingToken));
89  TRACE_REQUIRE_EQUAL(buff.header, TOKEN_MAGIC);
90  TRACE_REQUIRE_EQUAL(buff.new_slots_free, 335);
91  TRACE_REQUIRE_EQUAL(buff.run_number, 17);
92  TRACE_REQUIRE_EQUAL(buff.rank, 13);
93 
94  close(conn_sock);
95  close(token_socket);
96  TLOG(TLVL_INFO) << "Tokens Test Case END";
97 }
98 
99 BOOST_AUTO_TEST_CASE(Requests)
100 {
101  artdaq::configureMessageFacility("RequestSender_t", true, true);
102  metricMan->initialize(fhicl::ParameterSet());
103  metricMan->do_start();
104  TLOG(TLVL_INFO) << "Requests Test Case BEGIN" ;
105  const int REQUEST_PORT = (seedAndRandom() % (32768 - 1024)) + 1024;
106  const int DELAY_TIME = 100;
107 #if 0
108  const std::string MULTICAST_IP = "227.28.12.28";
109 #else
110  const std::string MULTICAST_IP = "localhost";
111 #endif
112  fhicl::ParameterSet pset;
113  pset.put("request_port", REQUEST_PORT);
114  pset.put("request_delay_ms", DELAY_TIME);
115  pset.put("send_requests", true);
116  pset.put("request_address", MULTICAST_IP);
117  artdaq::RequestSender t(pset);
118 
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 
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 
243  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
244  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
245 
246  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
247  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
248  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
249  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
250  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
251  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
252 
253  }
254  else
255  {
256  TLOG(TLVL_ERROR) << "Invalid header received" ;
257  BOOST_REQUIRE_EQUAL(false, true);
258  return;
259  }
260  }
261  else
262  {
263  TLOG(TLVL_ERROR) << "Wrong event type from poll" ;
264  BOOST_REQUIRE_EQUAL(false, true);
265  return;
266  }
267  }
268  else
269  {
270  TLOG(TLVL_ERROR) << "Timeout occured waiting for request" ;
271  BOOST_REQUIRE_EQUAL(false, true);
272  return;
273  }
274  rv = poll(ufds, 1, 1000);
275  if (rv > 0)
276  {
277  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
278  {
279  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
280  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
281  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
282  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
284  recv(request_socket, &buffer[0], buffer.size(), 0);
285  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
286  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
287  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
288  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
289  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 2);
290  if (hdr_buffer.isValid())
291  {
292 
293  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
294  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
295 
296  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
297  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 0);
298  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x10);
299  TRACE_REQUIRE_EQUAL(pkt_buffer[1].isValid(), true);
300  TRACE_REQUIRE_EQUAL(pkt_buffer[1].sequence_id, 2);
301  TRACE_REQUIRE_EQUAL(pkt_buffer[1].timestamp, 0x20);
302 
303  }
304  else
305  {
306  TLOG(TLVL_ERROR) << "Invalid header received" ;
307  BOOST_REQUIRE_EQUAL(false, true);
308  return;
309  }
310  }
311  else
312  {
313  TLOG(TLVL_ERROR) << "Wrong event type from poll" ;
314  BOOST_REQUIRE_EQUAL(false, true);
315  return;
316  }
317  }
318  else
319  {
320  TLOG(TLVL_ERROR) << "Timeout occured waiting for request" ;
321  BOOST_REQUIRE_EQUAL(false, true);
322  return;
323  }
324 
325  t.RemoveRequest(0);
326  t.RemoveRequest(2);
327  t.AddRequest(3, 0x30);
328  start_time = std::chrono::steady_clock::now();
329  rv = poll(ufds, 1, 1000);
330  if (rv > 0)
331  {
332  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
333  {
334  auto delay_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
335  BOOST_REQUIRE_GE(delay_time, DELAY_TIME);
336  TLOG(TLVL_TRACE) << "Recieved packet on Request channel";
337  std::vector<uint8_t> buffer(MAX_REQUEST_MESSAGE_SIZE);
339  recv(request_socket, &buffer[0], buffer.size(), 0);
340  memcpy(&hdr_buffer, &buffer[0], sizeof(artdaq::detail::RequestHeader));
341  TRACE_REQUIRE_EQUAL(hdr_buffer.isValid(), true);
342  TRACE_REQUIRE_EQUAL(static_cast<uint8_t>(hdr_buffer.mode),
343  static_cast<uint8_t>(artdaq::detail::RequestMessageMode::EndOfRun));
344  TRACE_REQUIRE_EQUAL(hdr_buffer.packet_count, 1);
345  if (hdr_buffer.isValid())
346  {
347 
348  std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.packet_count);
349  memcpy(&pkt_buffer[0], &buffer[sizeof(artdaq::detail::RequestHeader)], sizeof(artdaq::detail::RequestPacket) * hdr_buffer.packet_count);
350 
351  TRACE_REQUIRE_EQUAL(pkt_buffer[0].isValid(), true);
352  TRACE_REQUIRE_EQUAL(pkt_buffer[0].sequence_id, 3);
353  TRACE_REQUIRE_EQUAL(pkt_buffer[0].timestamp, 0x30);
354 
355  }
356  else
357  {
358  TLOG(TLVL_ERROR) << "Invalid header received" ;
359  BOOST_REQUIRE_EQUAL(false, true);
360  return;
361  }
362  }
363  else
364  {
365  TLOG(TLVL_ERROR) << "Wrong event type from poll" ;
366  BOOST_REQUIRE_EQUAL(false, true);
367  return;
368  }
369  }
370  else
371  {
372  TLOG(TLVL_ERROR) << "Timeout occured waiting for request" ;
373  BOOST_REQUIRE_EQUAL(false, true);
374  return;
375  }
376 
377  close(request_socket);
378  TLOG(TLVL_INFO) << "Requests Test Case END";
379  artdaq::Globals::CleanUpGlobals();
380 }
381 
382 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)
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.