Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
udp_transport_win.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef _TIME_SHIELD_UDP_TRANSPORT_WIN_HPP_INCLUDED
4#define _TIME_SHIELD_UDP_TRANSPORT_WIN_HPP_INCLUDED
5
6#if TIME_SHIELD_PLATFORM_WINDOWS
7
8#include "wsa_guard.hpp"
9#include "udp_transport.hpp"
10
11#include <winsock2.h>
12#include <ws2tcpip.h>
13#include <cstring>
14
15namespace time_shield {
16namespace detail {
17
20 public:
22 bool transact(const UdpRequest& req, int& out_error_code) noexcept override {
23 out_error_code = 0;
24 if (!WsaGuard::instance().success()) {
25 out_error_code = WsaGuard::instance().ret_code();
26 return false;
27 }
28
29 SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
30 if (sock == INVALID_SOCKET) {
31 out_error_code = WSAGetLastError();
32 return false;
33 }
34
35 sockaddr_in addr{};
36 addr.sin_family = AF_INET;
37 addr.sin_port = htons(static_cast<u_short>(req.port));
38
39 addrinfo hints{}, *res = nullptr;
40 hints.ai_family = AF_INET;
41 hints.ai_socktype = SOCK_DGRAM;
42 hints.ai_protocol = IPPROTO_UDP;
43
44 if (getaddrinfo(req.host.c_str(), nullptr, &hints, &res) != 0 || !res) {
45 out_error_code = WSAGetLastError();
46 closesocket(sock);
47 return false;
48 }
49 addr.sin_addr = reinterpret_cast<sockaddr_in*>(res->ai_addr)->sin_addr;
50
51 const int timeout_ms = req.timeout_ms > 0 ? req.timeout_ms : 5000;
52 DWORD timeout = static_cast<DWORD>(timeout_ms);
53 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeout), sizeof(timeout));
54
55 const int send_res = sendto(sock,
56 static_cast<const char*>(req.send_data),
57 static_cast<int>(req.send_size),
58 0,
59 reinterpret_cast<sockaddr*>(&addr),
60 sizeof(addr));
61 if (send_res == SOCKET_ERROR || static_cast<std::size_t>(send_res) != req.send_size) {
62 out_error_code = WSAGetLastError();
63 freeaddrinfo(res);
64 closesocket(sock);
65 return false;
66 }
67
68 sockaddr_in from{};
69 int from_len = sizeof(from);
70 const int recv_res = recvfrom(sock,
71 static_cast<char*>(req.recv_data),
72 static_cast<int>(req.recv_size),
73 0,
74 reinterpret_cast<sockaddr*>(&from),
75 &from_len);
76
77 if (recv_res == SOCKET_ERROR || static_cast<std::size_t>(recv_res) != req.recv_size) {
78 out_error_code = WSAGetLastError();
79 freeaddrinfo(res);
80 closesocket(sock);
81 return false;
82 }
83
84 freeaddrinfo(res);
85 closesocket(sock);
86 return true;
87 }
88 };
89
90} // namespace detail
91} // namespace time_shield
92
93#endif // _TIME_SHIELD_PLATFORM_WINDOWS
94
95#endif // _TIME_SHIELD_UDP_TRANSPORT_WIN_HPP_INCLUDED
int ret_code() const noexcept
Returns the result code from WSAStartup.
Definition wsa_guard.hpp:40
static const WsaGuard & instance()
Returns the singleton instance, initializing WSA if needed.
Definition wsa_guard.hpp:29
Abstract UDP transport interface for NTP queries.
Windows 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.
Singleton guard for WinSock initialization.