2 #include "Mu2e-STMDAQ/processing/udp.hh"
5 UDP::UDP(
const std::shared_ptr<AsyncLogger>& logger_,
6 const std::shared_ptr<STMdata>& stm_,
7 const std::shared_ptr<SignalHandler>& signal_,
12 , is_client(is_client_)
14 ip((stm->master_config.ch_num) ? stm->udp_config.rcv_ip : stm->udp_config.snd_ip)
16 port((stm->master_config.ch_num) ? stm->udp_config.rcv_port
17 : stm->udp_config.snd_port)
19 max_packet_num(stm->buffer_config.max_packet_num)
22 idle_timeout_ms(stm->udp_config.idle_timeout_ms)
23 , last_recv_time(std::chrono::steady_clock::now())
27 socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
32 logger->log(
"UDP: socket creation failed. Exiting...", 0);
37 std::string type = (is_client) ?
"client" :
"server";
39 logger->log(
"UDP: Configuring UDP " + type +
" for " +
40 stm->master_config.ch_name +
" channel...",
44 memset((
char*)&address, 0,
sizeof(address));
45 address.sin_family = AF_INET;
46 address.sin_addr.s_addr = inet_addr(ip.c_str());
47 address.sin_port = htons(port);
51 setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &optval,
sizeof(optval));
67 register_operation(
"receive_data", [
this](
auto& b) { receive_data(b); });
71 void UDP::get_mem_max()
76 std::ifstream rmem_max(
"/proc/sys/net/core/rmem_max");
77 getline(rmem_max, size);
78 std::istringstream iss1(size);
84 "UDP: /proc/sys/net/core/rmem_max = " + std::to_string(RMEM_MAX) +
" bytes.",
88 std::ifstream wmem_max(
"/proc/sys/net/core/wmem_max");
89 getline(wmem_max, size);
95 "UDP: /proc/sys/net/core/wmem_max = " + std::to_string(WMEM_MAX) +
" bytes.",
100 void UDP::configure_server()
103 socklen_t optlen =
sizeof(RMEM_MAX);
104 setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &RMEM_MAX, optlen);
107 getsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &actual_rmem_max, &optlen);
110 logger->log(
"UDP: SO_RCVBUF set to: " + std::to_string(actual_rmem_max) +
" (" +
111 std::to_string(actual_rmem_max / 2) +
112 ") bytes [RMEM_MAX = " + std::to_string(RMEM_MAX) +
" byes].",
116 if(bind(socket_fd, (
struct sockaddr*)&address,
sizeof(address)) < 0)
119 logger->log(
"UDP: Unable to bind socket to IP: " +
120 std::string(inet_ntoa(address.sin_addr)) +
", Port: " +
121 std::to_string(ntohs(address.sin_port)) +
". Exiting....",
127 int flags = fcntl(socket_fd, F_GETFL, 0);
129 fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
132 messages =
new mmsghdr[max_packet_num];
134 iovecs =
new iovec[max_packet_num];
143 read_timeout.tv_sec = stm->udp_config.recv_timeout_s;
144 read_timeout.tv_usec = stm->udp_config.recv_timeout_us;
145 timeout = {read_timeout.tv_sec, read_timeout.tv_usec};
146 setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
150 logger->log(
"UDP: CREATED UDP SERVER. IP = " + ip +
", PORT = " +
151 std::to_string(port) +
", socket = " + std::to_string(socket_fd) +
152 ", timeout = " + std::to_string(read_timeout.tv_sec) +
" s, " +
153 std::to_string(read_timeout.tv_usec) +
" us.",
170 void UDP::setup_buffers()
172 for(
size_t i = 0; i < max_packet_num; ++i)
175 std::memset(&messages[i], 0,
sizeof(mmsghdr));
176 std::memset(&iovecs[i], 0,
sizeof(iovec));
179 iovecs[i].iov_len = MAX_PACKET_SIZE;
182 messages[i].msg_hdr.msg_iov = &iovecs[i];
183 messages[i].msg_hdr.msg_iovlen = 1;
186 messages[i].msg_hdr.msg_name =
nullptr;
187 messages[i].msg_hdr.msg_namelen = 0;
190 messages[i].msg_hdr.msg_control =
nullptr;
191 messages[i].msg_hdr.msg_controllen = 0;
194 messages[i].msg_len = 0;
199 void UDP::configure_client()
202 socklen_t optlen =
sizeof(WMEM_MAX);
203 setsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, &WMEM_MAX, optlen);
206 getsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, &actual_wmem_max, &optlen);
209 logger->log(
"UDP: SO_SNDBUF set to: " + std::to_string(actual_wmem_max) +
" (" +
210 std::to_string(actual_wmem_max / 2) +
211 ") bytes [WMEM_MAX = " + std::to_string(WMEM_MAX) +
" byes].",
216 logger->log(
"UDP: CREATED UDP CLIENT. IP = " + ip +
217 ", PORT = " + std::to_string(port) +
218 ", socket = " + std::to_string(socket_fd) +
".",
223 void UDP::receive_data(std::shared_ptr<DataStruct>& buffer)
226 size_t required = max_packet_num * MAX_PACKET_SIZE;
227 size_t available = buffer->zs.size() *
sizeof(int16_t);
228 if(available < required)
230 std::cerr <<
"ERROR: raw buffer too small: " << available <<
" bytes available, "
231 << required <<
" required.\n";
236 for(
size_t i = 0; i < max_packet_num; ++i)
239 iovecs[i].iov_base = buffer->zs.data() + (i * MAX_PACKET_LEN);
240 messages[i].msg_hdr.msg_iov = &iovecs[i];
242 messages[i].msg_len = 0;
243 messages[i].msg_hdr.msg_flags = 0;
248 buffer->orig_len = 0;
251 if(!waiting_for_data)
252 start_wait = std::chrono::high_resolution_clock::now();
255 int packets_this_call = 0;
258 while(!stop::should_stop())
261 int poll_ret = poll(&pfd, 1, stm->udp_config.poll_timeout_ms);
267 logger->log(
"UDP: UDP::receive_data - poll failed!", 0);
272 else if(poll_ret > 0)
275 if(!has_received_data)
278 end_wait = std::chrono::high_resolution_clock::now();
280 if(packets_this_call > 0)
282 wait_time += end_wait - start_wait;
283 add_wait(end_wait - start_wait);
288 int retval = recvmmsg(socket_fd,
289 &messages[packets_this_call],
290 max_packet_num - packets_this_call,
300 strerror_r(errno, buf,
sizeof(buf));
301 std::string errorStr(buf);
304 "UDP: UDP::receive_data - recvmmsg failed with error code: " +
305 (std::to_string(errno)) +
" " + errorStr,
307 std::this_thread::sleep_for(std::chrono::seconds(3));
312 packets_this_call += retval;
317 last_recv_time = std::chrono::steady_clock::now();
318 idle_timeout_logged =
false;
322 buffer->zs_len += retval * MAX_PACKET_LEN;
323 buffer->orig_len = buffer->zs_len;
326 total_packets_received += retval;
329 if(!has_received_data)
330 has_received_data =
true;
333 if(logger && waiting_for_data)
334 logger->log(
"UDP: Receiving data...", 1);
337 waiting_for_data =
false;
340 if(packets_this_call == max_packet_num)
348 if(!waiting_for_data)
351 if(!has_received_data)
354 logger->log(
"UDP: Waiting for data from STM firmware...", 1);
359 start_wait = std::chrono::high_resolution_clock::now();
363 "UDP: Stopped receiving from STM firmware. Waiting for "
370 waiting_for_data =
true;
373 if(has_received_data && !idle_timeout_logged)
375 auto now = std::chrono::steady_clock::now();
376 auto idle_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
377 now - last_recv_time)
380 if(idle_ms > idle_timeout_ms)
382 idle_timeout_logged =
true;
383 logger->log(
"UDP: Idle timeout after " + std::to_string(idle_ms) +
384 "ms, releasing buffer.",
386 buffer->has_idle_timeout =
true;
392 if(packets_this_call > 0)
402 end_wait = std::chrono::high_resolution_clock::now();
404 wait_time += end_wait - start_wait;
405 add_wait(end_wait - start_wait);
412 void UDP::send_packet(
const std::vector<int16_t>& data_vec)
416 iov.iov_base =
const_cast<int16_t*
>(data_vec.data());
417 iov.iov_len = data_vec.size() *
sizeof(int16_t);
420 memset(&msg, 0,
sizeof(msg));
421 msg.msg_name = &address;
422 msg.msg_namelen =
sizeof(address);
426 ssize_t sent_bytes = sendmsg(socket_fd, &msg, 0);
428 if(__builtin_expect(sent_bytes == -1, 0))
431 logger->log(std::string(
"send_packet error: ") + strerror(errno), 0);