FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
udp_sender.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2026-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
8
9#include <bit>
10#include <cstring>
11#include <memory>
12#include <stdexcept>
13#include <string>
14
15#ifdef _WIN32
16#include <winsock2.h>
17#include <ws2tcpip.h>
18#else
19#include <netdb.h>
20#include <sys/socket.h>
21#include <unistd.h>
22#endif
23
24namespace serial::vita49
25{
26 namespace
27 {
28 constexpr int kRequestedUdpSendBufferBytes = 4 * 1024 * 1024;
29
30 void tuneSendBuffer(const int socket_fd) noexcept
31 {
33#ifdef _WIN32
34 const auto* option_value = std::bit_cast<const char*>(&send_buffer_bytes);
35#else
36 const void* option_value = &send_buffer_bytes;
37#endif
39 }
40 }
41
43
45 _socket(other._socket), _address(std::move(other._address)), _address_size(other._address_size)
46 {
47 other._socket = -1;
48 other._address_size = 0;
49 }
50
52 {
53 if (this != &other)
54 {
55 close();
56 _socket = other._socket;
57 _address = std::move(other._address);
58 _address_size = other._address_size;
59 other._socket = -1;
60 other._address_size = 0;
61 }
62 return *this;
63 }
64
65 void UdpSender::open(const std::string& host, const std::uint16_t port)
66 {
67 close();
68 if (host.empty() || port == 0)
69 {
70 throw std::invalid_argument("VITA UDP destination requires non-empty host and non-zero port");
71 }
72
73#ifdef _WIN32
75 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
76 {
77 throw std::runtime_error("WSAStartup failed for VITA UDP sender");
78 }
79#endif
80
82 hints.ai_family = AF_UNSPEC;
83 hints.ai_socktype = SOCK_DGRAM;
84 hints.ai_protocol = IPPROTO_UDP;
85
86 addrinfo* result = nullptr;
87 const auto port_string = std::to_string(port);
88 const int gai = getaddrinfo(host.c_str(), port_string.c_str(), &hints, &result);
89 if (gai != 0)
90 {
91 throw std::runtime_error("VITA UDP destination resolution failed: " + host + ":" + port_string);
92 }
93 std::unique_ptr<addrinfo, decltype(&freeaddrinfo)> const result_guard(result, freeaddrinfo);
94
95 for (auto* candidate = result; candidate != nullptr; candidate = candidate->ai_next)
96 {
97#ifdef _WIN32
98 const int fd =
99 static_cast<int>(::socket(candidate->ai_family, candidate->ai_socktype, candidate->ai_protocol));
100#else
101 const int fd = ::socket(candidate->ai_family, candidate->ai_socktype, candidate->ai_protocol);
102#endif
103 if (fd < 0)
104 {
105 continue;
106 }
107
109 _socket = fd;
110 _address_size = candidate->ai_addrlen;
111 auto storage = std::make_unique<std::byte[]>(_address_size);
112 std::memcpy(storage.get(), candidate->ai_addr, _address_size);
113 _address = std::move(storage);
114 return;
115 }
116
117 throw std::runtime_error("VITA UDP socket creation failed");
118 }
119
120 void UdpSender::send(const std::span<const std::uint8_t> bytes)
121 {
122 if (_socket < 0 || _address == nullptr)
123 {
124 throw std::runtime_error("VITA UDP sender is not open");
125 }
126 if (bytes.empty())
127 {
128 return;
129 }
130
131#ifdef _WIN32
132 const auto* payload = std::bit_cast<const char*>(bytes.data());
133 const auto sent = ::sendto(_socket, payload, static_cast<int>(bytes.size()), 0,
134 static_cast<const sockaddr*>(static_cast<const void*>(_address.get())),
135 static_cast<int>(_address_size));
136#else
137 const auto sent = ::sendto(_socket, bytes.data(), bytes.size(), 0,
138 static_cast<const sockaddr*>(static_cast<const void*>(_address.get())),
139 static_cast<socklen_t>(_address_size));
140#endif
141 if (sent < 0 || static_cast<std::size_t>(sent) != bytes.size())
142 {
143 throw std::runtime_error("VITA UDP send failed");
144 }
145 }
146
148 {
149 if (_socket >= 0)
150 {
151#ifdef _WIN32
152 ::closesocket(_socket);
153 WSACleanup();
154#else
155 ::close(_socket);
156#endif
157 _socket = -1;
158 }
159 _address.reset();
160 _address_size = 0;
161 }
162}
void send(std::span< const std::uint8_t > bytes) override
UdpSender & operator=(const UdpSender &)=delete
void close() noexcept override
void open(const std::string &host, std::uint16_t port) override
math::Vec3 max