mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-04-22 14:38:14 +02:00
104 lines
3.5 KiB
C++
104 lines
3.5 KiB
C++
// SPDX-License-Identifier: LGPL-3.0-or-other
|
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
#include "sls/UdpRxSocket.h"
|
|
#include "sls/logger.h"
|
|
#include "sls/network_utils.h"
|
|
#include "sls/sls_detector_exceptions.h"
|
|
#include <cstdint>
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
|
|
namespace sls {
|
|
|
|
UdpRxSocket::UdpRxSocket(int port, ssize_t packet_size, const char *hostname,
|
|
int kernel_buffer_size)
|
|
: packet_size_(packet_size) {
|
|
struct addrinfo hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_UNSPEC;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
hints.ai_protocol = 0;
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
struct addrinfo *res = nullptr;
|
|
|
|
const std::string portname = std::to_string(port);
|
|
if (getaddrinfo(hostname, portname.c_str(), &hints, &res)) {
|
|
throw RuntimeError("Failed at getaddrinfo with " +
|
|
std::string(hostname));
|
|
}
|
|
sockfd_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
if (sockfd_ == -1) {
|
|
throw RuntimeError("Failed to create UDP RX socket");
|
|
}
|
|
if (bind(sockfd_, res->ai_addr, res->ai_addrlen) == -1) {
|
|
throw RuntimeError("Failed to bind UDP RX socket");
|
|
}
|
|
freeaddrinfo(res);
|
|
|
|
// If we get a specified buffer size that is larger than the set one
|
|
// we set it. Otherwise we leave it there since it could have been
|
|
// set by the rx_udpsocksize command
|
|
if (kernel_buffer_size) {
|
|
auto current = getBufferSize() / 2;
|
|
if (current < kernel_buffer_size) {
|
|
setBufferSize(kernel_buffer_size);
|
|
if (getBufferSize() / 2 < kernel_buffer_size) {
|
|
LOG(logWARNING)
|
|
<< "Could not set buffer size. Got: " << getBufferSize() / 2
|
|
<< " instead of " << kernel_buffer_size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UdpRxSocket::~UdpRxSocket() { Shutdown(); }
|
|
ssize_t UdpRxSocket::getPacketSize() const noexcept { return packet_size_; }
|
|
|
|
bool UdpRxSocket::ReceivePacket(char *dst) noexcept {
|
|
auto bytes_received =
|
|
recvfrom(sockfd_, dst, packet_size_, 0, nullptr, nullptr);
|
|
return bytes_received == packet_size_;
|
|
}
|
|
|
|
ssize_t UdpRxSocket::ReceiveDataOnly(char *dst) noexcept {
|
|
auto r = recvfrom(sockfd_, dst, packet_size_, 0, nullptr, nullptr);
|
|
constexpr ssize_t eiger_header_packet = 40; // only detector that has this
|
|
if (r == eiger_header_packet) {
|
|
LOG(logWARNING) << "Got header pkg";
|
|
r = recvfrom(sockfd_, dst, packet_size_, 0, nullptr, nullptr);
|
|
}
|
|
// temporary workaround for Eiger firmware (stop sends bad packets of size 8
|
|
// bytes)
|
|
if (r == 8) {
|
|
LOG(logWARNING) << "Ignoring bad packet of size 8 bytes";
|
|
r = recvfrom(sockfd_, dst, packet_size_, 0, nullptr, nullptr);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int UdpRxSocket::getBufferSize() const {
|
|
int ret = 0;
|
|
socklen_t optlen = sizeof(ret);
|
|
if (getsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &ret, &optlen) == -1)
|
|
throw RuntimeError("Could not get socket buffer size");
|
|
return ret;
|
|
}
|
|
|
|
void UdpRxSocket::setBufferSize(int size) {
|
|
if (setsockopt(sockfd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
|
|
throw RuntimeError("Could not set socket buffer size");
|
|
}
|
|
|
|
void UdpRxSocket::Shutdown() {
|
|
shutdown(sockfd_, SHUT_RDWR);
|
|
if (sockfd_ >= 0) {
|
|
close(sockfd_);
|
|
sockfd_ = -1;
|
|
}
|
|
}
|
|
} // namespace sls
|