in OSNetworkRequirementChecker-PC/main.cpp [131:270]
int query_ntp_server(const char *hostname, int ntp_port, int src_port)
{
int iRes = 0;
// Build the NTP packet
ntp_packet packet = { 0 };
packet.li = 0; // No warning
packet.vn = 4; // Version 4 (aka IPv4-only)
packet.mode = 3; // Client Mode
// Log the requested hostname.
std::cout << "- time from " << hostname;
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
iRes = getSocketErrorCode();
std::cerr << "WSAStartup() failed with error code " << iRes << std::endl;
WSACleanup();
return iRes;
}
#endif
// Does the host exist?
struct hostent *server = gethostbyname(hostname);
if (server == NULL)
{
iRes = getSocketErrorCode();
std::cerr << "<???> --> gethostbyname() error " << iRes << std::endl;
}
else
{
// Setup the server address
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = *(long *)(server->h_addr_list[0]);
server_addr.sin_port = htons(ntp_port);
char server_ip_addr[INET_ADDRSTRLEN];
sprintf(server_ip_addr, "%s", inet_ntoa(*((struct in_addr *)server->h_addr)));
// Log the resolved IP address.
std::cout << "<" << server_ip_addr << "> --> ";
// Setup the source address (for source port customization)
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// Optionally, set the given outbound port
if (src_port > 0)
{
client_addr.sin_port = htons(src_port);
}
// Open an UDP socket
int sock_fd = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0)
{
iRes = getSocketErrorCode();
std::cerr << "socket() open error " << iRes << std::endl;
}
else
{
// Set a receive timeout
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
DWORD timeout = SOCKET_TIMEOUT_SEC * 1000;
if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) < 0)
{
iRes = getSocketErrorCode();
std::cerr << "setsockopt() failed with error " << iRes << std::endl;
}
#else
struct timeval tv;
tv.tv_sec = SOCKET_TIMEOUT_SEC;
tv.tv_usec = 0;
if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)) < 0)
{
iRes = getSocketErrorCode();
std::cerr << "setsockopt() failed with error " << iRes << std::endl;
}
#endif
// Bind it to the client w/optional desired source port
if (bind(sock_fd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0)
{
iRes = getSocketErrorCode();
std::cerr << "bind() failed with error " << iRes << std::endl;
}
else
{
// Send the NTP packet
int sent_bytes = sendto(sock_fd, (const char *)&packet, sizeof(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (sent_bytes < 0)
{
iRes = getSocketErrorCode();
std::cerr << "sendto() failed with error " << iRes << std::endl;
}
else
{
// Receive the NTP data back
socklen_t client_addr_len = sizeof(client_addr);
int recv_bytes = recvfrom(sock_fd, (char *)&packet, sizeof(packet), 0, (struct sockaddr *)&client_addr, &client_addr_len);
if (recv_bytes < 0)
{
iRes = getSocketErrorCode();
std::cerr << "recvfrom() failed with error " << iRes << std::endl;
}
else
{
// Firstly, the "endianness" of txTm_s needs to be converted from the network's big-endian to the local host's one.
// txTm_s contains the number of seconds passed since 00:00:00 UTC Jan 1st 1900, as of when the packet left the NTP server.
packet.txTm_s = ntohl(packet.txTm_s);
// The Unix epoch is the number of seconds since 00:00:00 UTC Jan 1st 1970,
// therefore we subtract 70 years worth of seconds from the time returned by the NTP server.
time_t txTm = (time_t)((uint64_t)packet.txTm_s - NTP_TIMESTAMP_DELTA);
// Print the time we got from the NTP server, accounting the local timezone and conversion from UTC time.
std::cout << ctime((const time_t *)&txTm);
}
}
}
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
closesocket(sock_fd);
#else
close(sock_fd);
#endif
}
}
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
WSACleanup();
#endif
return iRes;
}