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