Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
udp_transport_posix.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef _TIME_SHIELD_UDP_TRANSPORT_POSIX_HPP_INCLUDED
4#define _TIME_SHIELD_UDP_TRANSPORT_POSIX_HPP_INCLUDED
5
6#if TIME_SHIELD_PLATFORM_UNIX
7
8#include "udp_transport.hpp"
9
10#include <arpa/inet.h>
11#include <netdb.h>
12#include <netinet/in.h>
13#include <sys/socket.h>
14#include <unistd.h>
15#include <cerrno>
16#include <cstring>
17
18namespace time_shield {
19namespace detail {
20
23 public:
25 bool transact(const UdpRequest& req, int& out_error_code) noexcept override {
26 out_error_code = 0;
27 const int sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
28 if (sock < 0) {
29 out_error_code = errno;
30 return false;
31 }
32
33 addrinfo hints{}, *res = nullptr;
34 hints.ai_family = AF_INET;
35 hints.ai_socktype = SOCK_DGRAM;
36 hints.ai_protocol = IPPROTO_UDP;
37
38 const int resolve_code = getaddrinfo(req.host.c_str(), nullptr, &hints, &res);
39 if (resolve_code != 0 || !res) {
40 out_error_code = (resolve_code != 0) ? resolve_code : errno;
41 ::close(sock);
42 return false;
43 }
44
45 sockaddr_in addr{};
46 addr.sin_family = AF_INET;
47 addr.sin_port = htons(static_cast<uint16_t>(req.port));
48 addr.sin_addr = reinterpret_cast<sockaddr_in*>(res->ai_addr)->sin_addr;
49 freeaddrinfo(res);
50 res = nullptr;
51
52 const int timeout_ms = req.timeout_ms > 0 ? req.timeout_ms : 5000;
53 timeval tv;
54 tv.tv_sec = timeout_ms / 1000;
55 tv.tv_usec = (timeout_ms % 1000) * 1000;
56 ::setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
57
58 const ssize_t sent = ::sendto(sock,
59 req.send_data,
60 req.send_size,
61 0,
62 reinterpret_cast<sockaddr*>(&addr),
63 sizeof(addr));
64 if (sent < 0 || static_cast<std::size_t>(sent) != req.send_size) {
65 out_error_code = errno;
66 ::close(sock);
67 return false;
68 }
69
70 sockaddr_in from{};
71 socklen_t from_len = sizeof(from);
72 const ssize_t received = ::recvfrom(sock,
73 req.recv_data,
74 req.recv_size,
75 0,
76 reinterpret_cast<sockaddr*>(&from),
77 &from_len);
78
79 if (received < 0 || static_cast<std::size_t>(received) != req.recv_size) {
80 out_error_code = errno;
81 ::close(sock);
82 return false;
83 }
84
85 ::close(sock);
86 return true;
87 }
88 };
89
90} // namespace detail
91} // namespace time_shield
92
93#endif // _TIME_SHIELD_PLATFORM_UNIX
94
95#endif // _TIME_SHIELD_UDP_TRANSPORT_POSIX_HPP_INCLUDED
Abstract UDP transport interface for NTP queries.
POSIX UDP transport for NTP queries.
bool transact(const UdpRequest &req, int &out_error_code) noexcept override
Send request and receive response over UDP.
Main namespace for the Time Shield library.
UDP request parameters for NTP transactions.