xref: /reactos/base/services/w32time/ntpclient.c (revision 9393fc32)
1 /*
2  * PROJECT:     ReactOS Timedate Control Panel
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Queries the NTP server
5  * COPYRIGHT:   Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
6  */
7 
8 #include "w32time.h"
9 
10 #include <winsock2.h>
11 
12 #define TIMEOUT 4000 /* 4 second timeout */
13 
14 typedef struct _INFO
15 {
16     SOCKET Sock;
17     SOCKADDR_IN myAddr;
18     SOCKADDR_IN ntpAddr;
19     NTPPACKET SendPacket;
20     NTPPACKET RecvPacket;
21 } INFO, *PINFO;
22 
23 
24 static BOOL
25 InitConnection(PINFO pInfo,
26                LPSTR lpAddress)
27 {
28     WSADATA wsaData;
29     HOSTENT *he;
30     INT Ret;
31 
32     Ret = WSAStartup(MAKEWORD(2, 2),
33                      &wsaData);
34     if (Ret != 0)
35         return FALSE;
36 
37     pInfo->Sock = socket(AF_INET,
38                          SOCK_DGRAM,
39                          0);
40     if (pInfo->Sock == INVALID_SOCKET)
41         return FALSE;
42 
43     /* Setup server info */
44     he = gethostbyname(lpAddress);
45     if (he != NULL)
46     {
47         /* Setup server socket info */
48         ZeroMemory(&pInfo->ntpAddr, sizeof(SOCKADDR_IN));
49         pInfo->ntpAddr.sin_family = AF_INET; // he->h_addrtype;
50         pInfo->ntpAddr.sin_port = htons(NTPPORT);
51         pInfo->ntpAddr.sin_addr = *((struct in_addr *)he->h_addr);
52     }
53     else
54         return FALSE;
55 
56     return TRUE;
57 }
58 
59 
60 static VOID
61 DestroyConnection(VOID)
62 {
63     WSACleanup();
64 }
65 
66 
67 static BOOL
68 GetTransmitTime(PTIMEPACKET ptp)
69 {
70     return TRUE;
71 }
72 
73 
74 /* Send some data to wake the server up */
75 static BOOL
76 SendData(PINFO pInfo)
77 {
78     TIMEPACKET tp = { 0, 0 };
79     INT Ret;
80 
81     ZeroMemory(&pInfo->SendPacket, sizeof(pInfo->SendPacket));
82     pInfo->SendPacket.LiVnMode = 0x1b;        /* 0x1b = 011 011 - version 3 , mode 3 (client) */
83     if (!GetTransmitTime(&tp))
84         return FALSE;
85     pInfo->SendPacket.TransmitTimestamp = tp;
86 
87     Ret = sendto(pInfo->Sock,
88                  (char *)&pInfo->SendPacket,
89                  sizeof(pInfo->SendPacket),
90                  0,
91                  (SOCKADDR *)&pInfo->ntpAddr,
92                  sizeof(SOCKADDR_IN));
93 
94     if (Ret == SOCKET_ERROR)
95         return FALSE;
96 
97     return TRUE;
98 }
99 
100 
101 static ULONG
102 ReceiveData(PINFO pInfo)
103 {
104     TIMEVAL timeVal;
105     FD_SET readFDS;
106     INT Ret;
107     ULONG ulTime = 0;
108 
109     /* Monitor socket for incoming connections */
110     FD_ZERO(&readFDS);
111     FD_SET(pInfo->Sock, &readFDS);
112 
113     /* Set timeout values */
114     timeVal.tv_sec  = TIMEOUT / 1000;
115     timeVal.tv_usec = TIMEOUT % 1000;
116 
117     /* Check for data on the socket for TIMEOUT millisecs */
118     Ret = select(0, &readFDS, NULL, NULL, &timeVal);
119 
120     if ((Ret != SOCKET_ERROR) && (Ret != 0))
121     {
122         Ret = recvfrom(pInfo->Sock,
123                        (char *)&pInfo->RecvPacket,
124                        sizeof(pInfo->RecvPacket),
125                        0,
126                        NULL,
127                        NULL);
128 
129         if (Ret != SOCKET_ERROR)
130             ulTime = ntohl(pInfo->RecvPacket.TransmitTimestamp.dwInteger);
131     }
132 
133     return ulTime;
134 }
135 
136 
137 ULONG
138 GetServerTime(LPWSTR lpAddress)
139 {
140     PINFO pInfo;
141     LPSTR lpAddr;
142     DWORD dwSize = wcslen(lpAddress) + 1;
143     ULONG ulTime = 0;
144 
145     pInfo = (PINFO)HeapAlloc(GetProcessHeap(),
146                              0,
147                              sizeof(INFO));
148     lpAddr = (LPSTR)HeapAlloc(GetProcessHeap(),
149                               0,
150                               dwSize);
151 
152     if (pInfo && lpAddr)
153     {
154         if (WideCharToMultiByte(CP_ACP,
155                                 0,
156                                 lpAddress,
157                                 -1,
158                                 lpAddr,
159                                 dwSize,
160                                 NULL,
161                                 NULL))
162         {
163             if (InitConnection(pInfo, lpAddr))
164             {
165                 if (SendData(pInfo))
166                 {
167                     ulTime = ReceiveData(pInfo);
168                 }
169             }
170 
171             DestroyConnection();
172         }
173     }
174 
175     if (pInfo)
176         HeapFree(GetProcessHeap(), 0, pInfo);
177     if (lpAddr)
178         HeapFree(GetProcessHeap(), 0, lpAddr);
179 
180     return ulTime;
181 }
182