26 #include <system_error> 31 #include <arpa/inet.h> 55 unsigned int port, std::optional<IPAddress> address,
56 unsigned long max_bitrate, std::unique_ptr<UnixSyscalls> syscalls)
57 : port_(port), address_(
std::move(address)), max_bitrate_(max_bitrate),
58 syscalls_(
std::move(syscalls)), socket_(-1),
59 next_time_(
std::chrono::steady_clock::now())
72 syscalls_->close(socket_);
82 const std::vector<uint8_t> &data,
const IPAddress &address)
84 if (max_bitrate_ != 0)
87 auto now = std::chrono::steady_clock::now();
91 std::this_thread::sleep_for(next_time_ - now);
94 next_time_ = now + (1000 * 1000 * data.size() * 8) / max_bitrate_ * 1us;
98 struct sockaddr_in addr;
99 addr.sin_family = AF_INET;
100 addr.sin_port = htons(static_cast<uint16_t>(address.
port()));
101 addr.sin_addr.s_addr =
102 htonl(static_cast<uint32_t>(address.
address()));
103 std::memset(addr.sin_zero,
'\0',
sizeof(addr.sin_zero));
105 auto err = syscalls_->sendto(
106 socket_, data.data(), data.size(), 0,
107 reinterpret_cast<struct sockaddr *
>(&addr),
sizeof(addr));
111 throw std::system_error(std::error_code(errno, std::system_category()));
123 const std::chrono::nanoseconds &timeout)
125 std::chrono::milliseconds timeout_ms =
126 std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
127 struct pollfd fds = {socket_, POLLIN, 0};
128 auto result = syscalls_->poll(
129 &fds, 1, static_cast<int>(timeout_ms.count()));
134 throw std::system_error(std::error_code(errno, std::system_category()));
140 if (fds.revents & POLLERR)
142 syscalls_->close(socket_);
144 return {std::vector<uint8_t>(),
IPAddress(0)};
147 else if (fds.revents & POLLIN)
154 return {std::vector<uint8_t>(),
IPAddress(0)};
162 void UnixUDPSocket::create_socket_()
167 if ((socket_ = syscalls_->socket(AF_INET, SOCK_DGRAM, 0)) < 0)
169 throw std::system_error(std::error_code(errno, std::system_category()));
173 struct sockaddr_in addr;
174 addr.sin_family = AF_INET;
175 addr.sin_port = htons(static_cast<uint16_t>(port_));
179 addr.sin_addr.s_addr =
180 htonl(static_cast<uint32_t>(address_.value().address()));
184 addr.sin_addr.s_addr = htonl(INADDR_ANY);
187 std::memset(addr.sin_zero,
'\0',
sizeof(addr.sin_zero));
189 if ((syscalls_->bind(socket_, reinterpret_cast<struct sockaddr *>(&addr),
192 throw std::system_error(std::error_code(errno, std::system_category()));
205 std::pair<std::vector<uint8_t>,
IPAddress> UnixUDPSocket::receive_()
210 if ((syscalls_->ioctl(socket_, FIONREAD, &packet_size)) < 0)
212 throw std::system_error(std::error_code(errno, std::system_category()));
216 std::vector<uint8_t> buffer;
217 buffer.resize(static_cast<size_t>(packet_size));
218 struct sockaddr_in addr;
219 socklen_t addrlen =
sizeof(addr);
220 auto size = syscalls_->recvfrom(
221 socket_, buffer.data(), buffer.size(), 0,
222 reinterpret_cast<struct sockaddr *
>(&addr), &addrlen);
227 throw std::system_error(std::error_code(errno, std::system_category()));
231 if (addrlen <=
sizeof(addr) && addr.sin_family == AF_INET)
234 IPAddress(ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
240 return {std::vector<uint8_t>(),
IPAddress(0)};
259 os <<
"udp {" << std::endl;
260 os <<
" port " << std::to_string(port_) <<
";" << std::endl;
262 if (address_.has_value())
264 os <<
" address " << address_.value() <<
";" << std::endl;
267 if (max_bitrate_ != 0)
269 os <<
" max_bitrate " << max_bitrate_ <<
";" << std::endl;
UnixUDPSocket(unsigned int port, std::optional< IPAddress > address={}, unsigned long max_bitrate=0, std::unique_ptr< UnixSyscalls > syscalls=std::make_unique< UnixSyscalls >())
unsigned int port() const
virtual std::pair< std::vector< uint8_t >, IPAddress > receive(const std::chrono::nanoseconds &timeout=std::chrono::nanoseconds::zero()) final
virtual void send(const std::vector< uint8_t > &data, const IPAddress &address) final
unsigned long address() const
std::ostream & print_(std::ostream &os) const final