ntp-tools / ntpprint-win.c /
b37f41a 2 months ago
1 contributor
109 lines | 3.04kb
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <time.h>

#pragma comment(lib, "ws2_32.lib")

#define NTP_TIMESTAMP_DELTA 2208988800ull

typedef struct {
    unsigned char li_vn_mode;      // Eight bits. li, vn, and mode.
    unsigned char stratum;         // Stratum level of the local clock.
    unsigned char poll;            // Maximum interval between successive messages.
    unsigned char precision;       // Precision of the local clock.

    unsigned int rootDelay;
    unsigned int rootDispersion;
    unsigned int refId;

    unsigned int refTm_s;
    unsigned int refTm_f;

    unsigned int origTm_s;
    unsigned int origTm_f;

    unsigned int rxTm_s;
    unsigned int rxTm_f;

    unsigned int txTm_s;
    unsigned int txTm_f;
} NTPPacket;

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <ntp_server>\n", argv[0]);
        return 1;
    }

    const char* ntp_server = argv[1];
    WSADATA wsaData;
    SOCKET sock;
    struct sockaddr_in serverAddr;
    NTPPacket packet;

    WSAStartup(MAKEWORD(2, 2), &wsaData);

    memset(&packet, 0, sizeof(NTPPacket));
    packet.li_vn_mode = 0x1B;  // LI = 0, VN = 3 (version), Mode = 3 (client)

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == INVALID_SOCKET) {
        perror("socket");
        return 1;
    }

    struct timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

    struct hostent* server = gethostbyname(ntp_server);
    if (!server) {
        printf("Error: Cannot resolve hostname %s\n", ntp_server);
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(123); // NTP port
    memcpy(&serverAddr.sin_addr, server->h_addr, server->h_length);

    int sent = sendto(sock, (char*)&packet, sizeof(NTPPacket), 0,
                      (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if (sent == SOCKET_ERROR) {
        perror("sendto");
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    struct sockaddr_in recvAddr;
    int recvAddrLen = sizeof(recvAddr);
    int recvLen = recvfrom(sock, (char*)&packet, sizeof(NTPPacket), 0,
                           (struct sockaddr*)&recvAddr, &recvAddrLen);
    if (recvLen == SOCKET_ERROR) {
        //perror("recvfrom");
        if (WSAGetLastError() == WSAETIMEDOUT) {
            printf("Timeout: No response from NTP server within 5 seconds.\n");
        } else {
            perror("recvfrom");
        }
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    packet.txTm_s = ntohl(packet.txTm_s);  // Convert from network byte order
    time_t txTime = (time_t)(packet.txTm_s - NTP_TIMESTAMP_DELTA);

    printf("NTP Response: %s", ctime(&txTime));

    closesocket(sock);
    WSACleanup();
    return 0;
}