1 #define TRACE_NAME "RequestReceiver"
3 #include "artdaq/DAQrate/RequestReceiver.hh"
4 #include "artdaq/DAQdata/Globals.hh"
5 #include "artdaq/DAQrate/detail/RequestMessage.hh"
7 #include <boost/exception/all.hpp>
8 #include <boost/throw_exception.hpp>
13 #include "canvas/Utilities/Exception.h"
14 #include "cetlib_except/exception.h"
15 #include "fhiclcpp/ParameterSet.h"
17 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
18 #include "artdaq-core/Data/Fragment.hh"
19 #include "artdaq-core/Data/ContainerFragmentLoader.hh"
20 #include "artdaq-core/Utilities/ExceptionHandler.hh"
21 #include "artdaq-core/Utilities/TimeUtils.hh"
32 artdaq::RequestReceiver::RequestReceiver()
34 , request_addr_(
"227.128.12.26")
37 , request_stop_requested_(false)
38 , request_received_(false)
39 , end_of_run_timeout_ms_(1000)
41 , highest_seen_request_(0)
44 artdaq::RequestReceiver::RequestReceiver(
const fhicl::ParameterSet& ps)
45 : request_port_(ps.get<int>(
"request_port", 3001))
46 , request_addr_(ps.get<std::string>(
"request_address",
"227.128.12.26"))
49 , request_stop_requested_(false)
50 , request_received_(false)
51 , end_of_run_timeout_ms_(ps.get<size_t>(
"end_of_run_quiet_timeout_ms", 1000))
53 , highest_seen_request_(0)
55 setupRequestListener();
60 TLOG_INFO(
"RequestReceiver") <<
"Setting up request listen socket, rank=" << my_rank <<
", address=" << request_addr_ <<
":" << request_port_ << TLOG_ENDL;
61 request_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
62 if (request_socket_ < 0)
64 TLOG_ERROR(
"RequestReceiver") <<
"Error creating socket for receiving data requests! err=" << strerror(errno) << TLOG_ENDL;
68 struct sockaddr_in si_me_request;
71 if (setsockopt(request_socket_, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0)
73 TLOG_ERROR(
"RequestReceiver") <<
"Unable to enable port reuse on request socket, err=" << strerror(errno) << TLOG_ENDL;
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_, (
struct sockaddr *)&si_me_request,
sizeof(si_me_request)) == -1)
82 TLOG_ERROR(
"RequestReceiver") <<
"Cannot bind request socket to port " << request_port_ <<
", err=" << strerror(errno) << TLOG_ENDL;
86 if (request_addr_ !=
"localhost")
89 int sts =
ResolveHost(request_addr_.c_str(), mreq.imr_multiaddr);
92 TLOG_ERROR(
"RequestReceiver") <<
"Unable to resolve multicast request address, err=" << strerror(errno) << TLOG_ENDL;
95 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
96 if (setsockopt(request_socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0)
98 TLOG_ERROR(
"RequestReceiver") <<
"Unable to join multicast group, err=" << strerror(errno) << TLOG_ENDL;
102 TLOG_INFO(
"RequestReceiver") <<
"Done setting up request socket, rank=" << my_rank << TLOG_ENDL;
105 artdaq::RequestReceiver::~RequestReceiver()
107 if (!request_received_)
109 TLOG_ERROR(
"RequestReceiver") <<
"Stop request received by RequestReceiver, but no requests have ever been received." << std::endl
110 <<
"Check that UDP port " << request_port_ <<
" is open in the firewall config." << TLOG_ENDL;
113 TLOG_DEBUG(
"RequestReceiver") <<
"Joining requestThread" << TLOG_ENDL;
114 if (requestThread_.joinable()) requestThread_.join();
115 if (request_socket_ != -1) close(request_socket_);
120 if (requestThread_.joinable()) requestThread_.join();
121 TLOG_INFO(
"RequestReceiver") <<
"Starting Request Reception Thread" << TLOG_ENDL;
128 while (!should_stop_)
130 TLOG_ARB(16,
"RequestReceiver") <<
"receiveRequestsLoop: Polling Request socket for new requests" << TLOG_ENDL;
132 int ms_to_wait = 100;
133 struct pollfd ufds[1];
134 ufds[0].fd = request_socket_;
135 ufds[0].events = POLLIN | POLLPRI;
136 int rv = poll(ufds, 1, ms_to_wait);
139 if (rv <= 0 || (ufds[0].revents != POLLIN && ufds[0].revents != POLLPRI))
141 if (request_stop_requested_ && TimeUtils::GetElapsedTimeMilliseconds(request_stop_timeout_) > end_of_run_timeout_ms_)
148 TLOG_ARB(11,
"RequestReceiver") <<
"Recieved packet on Request channel" << TLOG_ENDL;
150 recv(request_socket_, &hdr_buffer,
sizeof(hdr_buffer), 0);
151 TLOG_ARB(11,
"RequestReceiver") <<
"Request header word: 0x" << std::hex << hdr_buffer.
header << TLOG_ENDL;
152 if (!hdr_buffer.
isValid())
continue;
154 request_received_ =
true;
157 TLOG_INFO(
"RequestReceiver") <<
"Received Request Message with the EndOfRun marker. (Re)Starting 1-second timeout for receiving all outstanding requests..." << TLOG_ENDL;
158 request_stop_timeout_ = std::chrono::steady_clock::now();
159 request_stop_requested_ =
true;
162 std::vector<artdaq::detail::RequestPacket> pkt_buffer(hdr_buffer.
packet_count);
165 for (
auto& buffer : pkt_buffer)
167 if (!buffer.isValid())
continue;
168 if (requests_.count(buffer.sequence_id) && requests_[buffer.sequence_id] != buffer.timestamp)
170 TLOG_ERROR(
"RequestReceiver") <<
"Received conflicting request for SeqID "
171 << std::to_string(buffer.sequence_id) <<
"!"
172 <<
" Old ts=" << std::to_string(requests_[buffer.sequence_id])
173 <<
", new ts=" << std::to_string(buffer.timestamp) <<
". Keeping OLD!" << TLOG_ENDL;
175 else if (!requests_.count(buffer.sequence_id))
177 int delta = buffer.sequence_id - highest_seen_request_;
178 TLOG_ARB(11,
"RequestReceiver") <<
"Recieved request for sequence ID " << std::to_string(buffer.sequence_id)
179 <<
" and timestamp " << std::to_string(buffer.timestamp) <<
" (delta: " << delta <<
")" << TLOG_ENDL;
182 TLOG_ARB(11,
"RequestReceiver") <<
"Already serviced this request! Ignoring..." << TLOG_ENDL;
186 std::unique_lock<std::mutex> tlk(request_mutex_);
187 requests_[buffer.sequence_id] = buffer.timestamp;
193 request_cv_.notify_all();
199 void artdaq::RequestReceiver::RemoveRequest(artdaq::Fragment::sequence_id_t reqID)
201 std::unique_lock<std::mutex> lk(request_mutex_);
202 requests_.erase(reqID);
203 if (reqID > highest_seen_request_) highest_seen_request_ = reqID;
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
End of Run mode (Used to end request processing on receiver)
void startRequestReceiverThread()
Function that launches the data request receiver thread (receiveRequestsLoop())
void setupRequestListener()
Opens the socket used to listen for data requests.
void receiveRequestsLoop()
This function receives data request packets, adding new requests to the request list.
The RequestPacket contains information about a single data request.