CYCho Posted October 24, 2019 Share Posted October 24, 2019 (edited) Based on codes in an old AutoIt Forum, I made the following code and it works perfectly. But I have couple of questions on how it works. I have to ask the original writer of this code(@Fzz), but he doesn't seem to be active now. Can someone please let me know the internal workings of this code? I'm especially curious about the meaning of packet sent to the NTP server. I don't know what the 96-byte long hex string with a lot of 0's means. I don't know why the hex string is converted to a decimal character string instead of using the decimal characters to start with. I don't know the benefit of using Call() function over using funtion name followed by (). expandcollapse popup;~ Many thanks to @TheXman for his kind guidance. ;~ https://www.autoitscript.com/forum/topic/200643-pulling-time-from-ntp-server/?do=findComment&comment=1439629 #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d #AutoIt3Wrapper_Outfile=NTP_Time_V4.exe #AutoIt3Wrapper_Res_Fileversion=4.0 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #RequireAdmin #include <Constants.au3> #include <Date.au3> Global $hTimeoutTimer = TimerInit() While 1 If Ping("www.google.com") > 0 Then ExitLoop If TimerDiff($hTimeoutTimer) > 120000 Then WriteLog(0, "System has no internet connection") Exit EndIf Sleep(50) WEnd Global $NTP_Server = 'time.google.com', $NTP_Time NTP_GetTime() System_SetTime() Func System_SetTime() ; 2019/10/28 23:09:52.522 ; 12345678901234567890123 Local $m = StringMid($NTP_Time, 6, 2) Local $d = StringMid($NTP_Time, 9, 2) Local $y = StringMid($NTP_Time, 1, 4) Local $h = StringMid($NTP_Time, 12, 2) Local $mi = StringMid($NTP_Time, 15, 2) Local $s = StringMid($NTP_Time, 18, 2) Local $ms = StringMid($NTP_Time, 21, 3) ;~ Sets the new current time to the computer Local $tCurr = _Date_Time_EncodeSystemTime($m, $d, $y, $h, $mi, $s, $ms) Local $tTime = _Date_Time_GetSystemTime() _Date_Time_SetSystemTime(DllStructGetPtr($tCurr)) Local $aTime = _Date_Time_SystemTimeToArray($tTime) WriteLog($aTime, "Update Time: " & $NTP_Time & " UTC") EndFunc ;==>System_SetTime Func NTP_GetTime() Local $tBuffer Local $aSocket Local $xRequest = Binary(""), $xResponse = Binary(""), $hTimeoutTimer, $hEchoTimer, $iDelay Local $iSeconds= 0, $iFractions = 0, $iMsecs = 0 ; Create the NTP request using a 48 byte buffer $tBuffer = DllStructCreate("byte[48]") DllStructSetData($tBuffer, 1, 0x23) ; 00 100 011 = LI(0) / VN(4-NTPv4) / Mode(3-Client) ; Copy the buffer to a variable for sending $xRequest = DllStructGetData($tBuffer, 1) ; Send NTP request UDPStartup() If @error Then WriteLog(0, "UDPStartup failed - @error = " & @error) Exit EndIf OnAutoItExitRegister("udp_shutdown") $aSocket = UDPOpen(TCPNameToIP($NTP_Server), 123) If @error Then WriteLog(0, "UDPOpen failed - @error = " & @error) Exit EndIf Sleep(50) $hTimeoutTimer = TimerInit() While 1 $hEchoTimer = TimerInit() UDPSend($aSocket, $xRequest) If @error Then WriteLog(0, "UDPSend failed - @error = " & @error) Exit EndIf Do $xResponse = UDPRecv($aSocket, DllStructGetSize($tBuffer), $UDP_DATA_BINARY) If @error Then WriteLog(0, "UDPRecv failed - @error = " & @error) Exit EndIf Until $xResponse <> Binary("") $iDelay = Round(TimerDiff($hEchoTimer)/2) If $iDelay < 100 Then ExitLoop EndIf If TimerDiff($hTimeoutTimer) > 120000 Then ; If no response within 2 seconds, then exit WriteLog(0, "UDPRecv timed out") Exit EndIf Sleep(100) WEnd ; Close the socket UDPCloseSocket($aSocket) ; Parse timestamp values ; - Current time is calculated from the xmit timestamp in NTP response header ; - Xmit timestamp seconds is a big-endian, uint32, at binary position 41 ; - Xmit timestamp fraction is a big-endian, uint32, at binary position 45 $iSeconds = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ; seconds since 1900-01-01 00:00:00 $iFractions = Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT) ; the maximum value is 0xFFFFFFFF, which represents 1 second $iMsecs = Round($iFractions / 2^32 * 1000) + $iDelay ; It normally takes about 50 milsecs to get NTP time If $iMsecs >= 1000 Then $iSeconds += 1 $iMsecs -= 1000 EndIf ; Current NTP time $NTP_Time = _DateAdd("s", $iSeconds, "1900/01/01 00:00:00") & StringFormat(".%03i", $iMsecs) EndFunc ;==>NTP_GetTime Func udp_shutdown() UDPShutdown() EndFunc ;==>udp_shutdown Func WriteLog($pTime, $sMessage) Local $fn, $sTime If $pTime = 0 Then $fn = FileOpen(@ScriptDir & "\TimeSync Failed.log", 2) $sTime = _NowCalc() Else $fn = FileOpen(@ScriptDir & "\TimeSync.log", 2) FileDelete(@ScriptDir & "\TimeSync Failed.log") $sTime = StringFormat("System Time: %04d/%02d/%02d %02d:%02d:%02d.%03d UTC", $pTime[2], $pTime[0], $pTime[1], $pTime[3], $pTime[4], $pTime[5], $pTime[6]) EndIf FileWrite($fn, $sTime & @CRLF & $sMessage) FileClose($fn) EndFunc ;==>WriteLog Edit: The above code is my latest version as of 2019/11/24, reflecting all the suggestions thankfully offered by @TheXman. Edit: The compiled version of this code(NTP_Time_V4.exe) was cleared by Microsoft Windows Defender from false detection as of Definition 1.305.2722.0. - 2019/11/24 NTP_Time_V4.exe.zip Edited November 24, 2019 by CYCho hudsonhock 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Earthshine Posted October 24, 2019 Share Posted October 24, 2019 Read the help file to start with. My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
CYCho Posted October 24, 2019 Author Share Posted October 24, 2019 (edited) 11 minutes ago, Earthshine said: Read the help file to start with. Thank you for your prompt response. I thought I read the help file for most of the key words used here, but I could not find answers to my questions. Could you direct me to what key words I should read in help file? Edited October 24, 2019 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Nine Posted October 25, 2019 Share Posted October 25, 2019 Here a modern way to get date/time from all over the world : #include <Constants.au3> Local $String = BinaryToString(InetRead ("http://worldtimeapi.org/api/timezone/America/Toronto.txt",1)) MsgBox (0,"",$String) ;Local $String = BinaryToString(InetRead ( "http://worldtimeapi.org/api/timezone/Europe/Amsterdam",1)) Local $Time = StringRegExp ($String,'datetime: (.+?)T(\d+:\d+:\d+)', $STR_REGEXPARRAYMATCH) MsgBox ($MB_SYSTEMMODAL,"",$Time[0] & " " & $Time[1]) Gianni, CYCho and pixelsearch 3 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
CYCho Posted October 25, 2019 Author Share Posted October 25, 2019 (edited) @Nine, Thanks. your code really simplifies the process of updating the system time. Edit: Quote The API can go down from time-to-time, for relatively long periods. This is what World Time API web site says. If so, I would still like to get time from other reliable NTP servers. Edited October 26, 2019 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 25, 2019 Share Posted October 25, 2019 3 hours ago, CYCho said: Can someone please let me know the internal workings of this code? I'm especially curious about the meaning of packet sent to the NTP server. The internal workings of the code are directly related to the internal workings of the NTP protocol. Everything you want to know about the NTP protocol can be found in RFC5905. The RFC for NTP v4 can be found HERE. It also includes references to previous version RFCs and updates to the RFC5905. 4 hours ago, CYCho said: I don't know why the hex string is converted to a decimal character string instead of using the decimal characters to start with. I don't know the benefit of using Call() function over using funtion name followed by (). As with most programming languages, there are many ways to achieve the same result. The reason that the author chose to do the binary conversions the way he or she did is because that is the way he or she chose to do it. CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 25, 2019 Author Share Posted October 25, 2019 @TheXman, Thanks a lot for your answer. It once again proves how little I know and I have to learn a lot. Maybe I should just use the code as it is. Thank you for enlightening me anyway. zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
CYCho Posted October 25, 2019 Author Share Posted October 25, 2019 (edited) I replaced: MakePacket("1b0e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") with: "300000000000000000000000000000000000000000000000" and the result was as good. The revised string is 3, indicating client mode, followed by 47 zeroes. This way I could do away with converting a binary string to a character string. The revised code: expandcollapse popup;~ This code is a tweak of examples in AutoIt Forum (https://www.autoitscript.com/forum/topic/43079-ntp-c-to-autoit-conversvion/) #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 #AutoIt3Wrapper_Outfile=NTP_Time_V2.exe #AutoIt3Wrapper_Res_Fileversion=2.0 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #RequireAdmin #include <Date.au3> Global $NTP_Server[3] = ['time.google.com','time.windows.com', 'time.nist.gov'], $NTP_IP[3], $ntp, $fn Local $time = TimerInit() While $NTP_IP[0] & $NTP_IP[1] & $NTP_IP[2] = "" Call('check_internet_connectivity') If TimerDiff($time) > 120000 Then $fn = FileOpen(@ScriptDir & '\timesync-failed.txt', 2) FileWrite($fn, "Time sync failed due to no connection.") FileClose($fn) Exit EndIf Sleep(100) WEnd For $i = 0 To 2 If $NTP_IP[$i] <> '' Then Local $adata = Call('NTP_Connect', $NTP_Server[$i]) If $adata <> '' Then Call('Set_Time', $adata) $ntp = $NTP_Server[$i] ExitLoop EndIf EndIf Next If $ntp <> '' Then $fn = FileOpen(@ScriptDir & '\timesync.txt', 2) FileWrite($fn, "Time was sync'ed at " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " based on " & $ntp) FileClose($fn) FileDelete(@ScriptDir & '\timesync-failed.txt') Else $fn = FileOpen(@ScriptDir & '\timesync-failed.txt', 2) FileWrite($fn, "Time sync failed due to no data from ntp servers.") FileClose($fn) EndIf Func check_internet_connectivity() ; check availability of time servers TCPStartup() For $i = 0 to 2 $NTP_IP[$i] = TCPNameToIP ( $NTP_Server[$i]) Sleep(250) Next TCPShutdown () EndFunc Func NTP_Connect($NTP_Server) ; read time from ntp server as unsigned hex UDPStartup() Local $socket = UDPOpen(TCPNameToIP($NTP_Server), 123) UDPSend($socket, "300000000000000000000000000000000000000000000000") Local $data, $time = TimerInit() While $data = "" $data = UDPRecv($socket, 100) ; normally takes about 60 milsecs If TimerDiff($time) > 10000 Then ExitLoop WEnd UDPCloseSocket($socket) UDPShutdown() Return $data EndFunc Func Set_Time($bdata) ; decrypt the time from returned hex string and apply new time to system ; $bdata = "0x340130EC0000000000000014474F4F47E15D224F505D83853030303030303030E15D224F505D8386E15D224F505D8388" Local $unsignedHexValue = StringMid($bdata, 83, 8); Extract time from packet. Disregards the fractional second. Local $value = UnsignedHexToDec($unsignedHexValue) Local $UTC = _DateAdd("s", $value, "1900/01/01 00:00:00") ;~ Extracts the data & time into vars ;~ Date format & offsets ;~ 2009/12/31 19:26:05 ;~ 1234567890123456789 [1 is start of string] Local $m = StringMid($UTC, 6, 2) Local $d = StringMid($UTC, 9, 2) Local $y = StringMid($UTC, 1, 4) Local $h = StringMid($UTC, 12, 2) Local $mi = StringMid($UTC, 15, 2) Local $s = StringMid($UTC, 18, 2) ;~ Sets the new current time to the computer Local $tCurr = _Date_Time_EncodeSystemTime($m, $d, $y, $h, $mi, $s) _Date_Time_SetSystemTime(DllStructGetPtr($tCurr)) EndFunc Func UnsignedHexToDec($n) ; decript UnsignedHexToDec Local $ones = StringRight($n, 1) $n = StringTrimRight($n, 1) Return Dec($n) * 16 + Dec($ones) EndFunc Edited October 29, 2019 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 25, 2019 Share Posted October 25, 2019 (edited) On 10/24/2019 at 10:36 PM, CYCho said: It once again proves how little I know and I have to learn a lot. Maybe I should just use the code as it is. I'm not saying that the original code couldn't have been optimized and cleaned up a little, but it worked and the binary request was correct. But your change makes absolutely no sense. The first word of advice is if you don't know what a particular piece of code is doing, DON'T CHANGE IT! The fact that you got back a good response with your "modification" was sheer luck because, lucky for you in this particular case, most of the information in the NTP request header is ignored. You could have thrown almost any data in the request packet and gotten back a response with a timestamp in it. Obviously you do not work with binary data very often. What the MakePacket() function did was change the hex string representation of a binary packet into an actual binary packet. I'm still trying to understand how you came up with your "modification" though. There is a big difference between 0x1B and "3" and 0x00 and "0". They DO NOT equate to the same binary value. And binary packets are what is sent and received in the NTP protocol, not strings. For example, 0x1B in binary is 00011011. "3", in binary, assuming it is using ascii or UTF-8 encoding, is 00110011 (0x33). 0x00 in binary is 00000000. "0" in binary, assuming ascii or utf-8 encoding, is 00110000 (0x30). If you wanted to get rid of the MakePacket() function, then you could have done something like: ;Replace MakePacket("1b0e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") ;With Binary("0x1b0e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") If you look at the RFC, the first 8 bits of the request/response header is made up of 3 values, LI, VN, and Mode. LI, the Leap Indicator, is the first 2 bits. VN, the NTP version number, is the next 3 bits. And the last 3 bits designates the mode, which in you case should be Client (3). That is why the first byte of request, in the original code, was 0x1B. That breaks down like so: 0x1B = 00011011 00 = Leap Indicator (0) 011 = Version Number (NTPv3) 011 = Mode (3-Client) With your "modification, it breaks down like so: 0x33 = 00110011 00 = Leap Indicator (0) 110 = Version Number (NTPv6) ??? 011 = Mode (3-Client) So the fact is that you got lucky in that you got the Mode correct (Client Request). I guess the NTP server just ignored the fact that you said that you were using a non-existent NTP version or sent back an error packet with a valid timestamp. 😃 Edited October 27, 2019 by TheXman corrected a typo pointed out by CYCho CYCho 1 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 26, 2019 Author Share Posted October 26, 2019 (edited) @TheXman, Thank you for your detailed explanation. I found that all of the following 3 options worked well. 1. UDPSend($socket, Binary("0x1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")) 2. UDPSend($socket, Binary("1b0000000000000000000000000000000000000000000000")) 3. UDPSend($socket, "1b0000000000000000000000000000000000000000000000") It seems to me that the NTP server automatically converts an incoming character string to binary format. If so, can I just use the simplest one (option 3) without Binary()? Edited October 26, 2019 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 26, 2019 Share Posted October 26, 2019 (edited) The NTP server doesn't do any conversions of the inbound data from string representations of binary to binary. The NTP server reads all data in the header as binary, regardless of how you send it. Option 1 is correct. Options 2 & 3 are incorrect. I already explained, in detail, why it happened to work in this specific case. This is second time that I am telling you the same thing. That means you didn't understand what I told you the first time. Binary concepts appear to be beyond your comprehension at the moment. If you are really interested in understanding my answer, maybe it would benefit you to spend some time understanding the difference between binary data and string representations of binary data. Also, if you are really interested in the NTP protocol, you should spend more time reading and absorbing the information in the RFC, especially as it pertains to sending client requests, the request header, and the response packet. As for binary data, I won't even go into the subject big-endian vs little-endian and 1's complement vs 2's complement. It would probably just confuse you even more. For the record, the NTP protocol users 2's complement and big-endian for its numbers. Here's a simple script that demonstrated the difference between actual binary data and string representations of binary data. It also shows the difference between your option 1, 2 & 3. Actually, options 2 & 3 send the same binary data. ConsoleWrite(Binary("0x1B0000") & @CRLF) ConsoleWrite(Binary("1B0000") & @CRLF) ConsoleWrite("1B0000" & @CRLF) Output: 0x1B0000 0x314230303030 1B0000 Edited October 26, 2019 by TheXman CYCho 1 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 26, 2019 Author Share Posted October 26, 2019 (edited) @TheXman, Thank you. A lot of your explanations are beyond my capacity. AutoIt is the only language I ever learned, and that at a time I was well over 60. Thank you for your kindness. Edited October 26, 2019 by CYCho TheXman 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 26, 2019 Share Posted October 26, 2019 You're quite welcome. I love AutoIt and have used it for over 12 years. If I were going to choose a language to learn, at an age well over 60, I would have chosen AutoIt too. Kudos to you! FrancescoDiMuro 1 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 26, 2019 Author Share Posted October 26, 2019 (edited) My final version reflecting @TheXman's correction: expandcollapse popup;~ This code is a tweak of examples in AutoIt Forum (https://www.autoitscript.com/forum/topic/43079-ntp-c-to-autoit-conversvion/) #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 #AutoIt3Wrapper_Outfile=NTP_Time_V2.exe #AutoIt3Wrapper_Res_Fileversion=2.0 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #RequireAdmin #include <Date.au3> Local $NTP_Server= 'time.google.com', $NTP_IP, $fn Local $time = TimerInit() While $NTP_IP = "" TCPStartup() $NTP_IP = TCPNameToIP($NTP_Server) TCPShutdown () If TimerDiff($time) > 120000 Then $fn = FileOpen(@ScriptDir & '\timesync-failed.txt', 2) FileWrite($fn, "Time sync failed due to no connection.") FileClose($fn) Exit EndIf Sleep(100) WEnd Local $adata = Call('NTP_Connect') If $adata <> '' Then Call('Set_Time', $adata) $fn = FileOpen(@ScriptDir & '\timesync.txt', 2) FileWrite($fn, "Time was sync'ed at " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " based on Google time server") FileClose($fn) FileDelete(@ScriptDir & '\timesync-failed.txt') Else $fn = FileOpen(@ScriptDir & '\timesync-failed.txt', 2) FileWrite($fn, "Time sync failed due to no data from Google time server.") FileClose($fn) EndIf Func NTP_Connect() ; read time from ntp server as unsigned hex UDPStartup() Local $socket = UDPOpen(TCPNameToIP($NTP_Server), 123) UDPSend($socket, Binary("0x1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")) Local $data, $time = TimerInit() While $data = "" $data = UDPRecv($socket, 100) ; normally takes about 60 milsecs If TimerDiff($time) > 10000 Then ExitLoop WEnd UDPCloseSocket($socket) UDPShutdown() Return $data EndFunc Func Set_Time($bdata) ; decrypt the time from returned hex string and apply new time to system ;~ $bdata = "0x340130EC0000000000000014474F4F47E15D224F505D83853030303030303030E15D224F505D8386E15D224F505D8388" Local $unsignedHexValue = StringMid($bdata, 83, 8); Extract time from packet. Disregards the fractional second. Local $value = UnsignedHexToDec($unsignedHexValue) Local $UTC = _DateAdd("s", $value, "1900/01/01 00:00:00") ;~ Extracts the data & time into vars ;~ Date format & offsets ;~ 2009/12/31 19:26:05 ;~ 1234567890123456789 [1 is start of string] Local $m = StringMid($UTC, 6, 2) Local $d = StringMid($UTC, 9, 2) Local $y = StringMid($UTC, 1, 4) Local $h = StringMid($UTC, 12, 2) Local $mi = StringMid($UTC, 15, 2) Local $s = StringMid($UTC, 18, 2) ;~ Sets the new current time to the computer Local $tCurr = _Date_Time_EncodeSystemTime($m, $d, $y, $h, $mi, $s) _Date_Time_SetSystemTime(DllStructGetPtr($tCurr)) EndFunc Func UnsignedHexToDec($n) ; decript UnsignedHexToDec Local $ones = StringRight($n, 1) $n = StringTrimRight($n, 1) Return Dec($n) * 16 + Dec($ones) EndFunc Edited October 29, 2019 by CYCho zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
CYCho Posted October 27, 2019 Author Share Posted October 27, 2019 On 10/26/2019 at 12:20 AM, TheXman said: 0x1B = 00001011 00 = Leap Indicator (0) 001 = Version Number (NTPv1) 011 = Mode (3-Client) This should be read like below: 0x1B = 00011011 00 = Leap Indicator (0) 011 = Version Number (NTPv3) 011 = Mode (3-Client) TheXman 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 27, 2019 Share Posted October 27, 2019 Yes, you are correct. Nice catch. 😀 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
TheXman Posted October 27, 2019 Share Posted October 27, 2019 (edited) @CYCho Here's my "quick & dirty" interpretation of the original NTP time request script with a little more error checking, a lot less binary string conversions, and a lot of extra documentation of each step in case you want to study and modify it for your own purposes. expandcollapse popup#include <Constants.au3> #include <date.au3> ntp_example() Func ntp_example() Const $NTP_SERVER = "time.windows.com" Const $MY_TZ_OFFSET = -5 ; Timezone offset in hours Local $tBuffer Local $aSocket Local $xRequest = Binary(""), $xResponse = Binary("") Local $hTimeoutTimer Local $iSeconds = 0 ; Create the NTP request using a 48 byte buffer $tBuffer = DllStructCreate("byte[48]") DllStructSetData($tBuffer, 1, 0x23) ; 00 100 011 = LI(0) / VN(4-NTPv4) / Mode(3-Client) ; Copy the buffer to a variable for sending $xRequest = DllStructGetData($tBuffer, 1) ConsoleWrite("DEBUG: Binary request = " & $xRequest & @CRLF) ; Send NTP request UDPStartup() If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPStartup failed - @error = " & @error) OnAutoItExitRegister("udp_shutdown") ; Do UDPShutdown upon exit $aSocket = UDPOpen(TCPNameToIP($NTP_SERVER), 123) If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPOpen failed - @error = " & @error) UDPSend($aSocket, $xRequest) If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPSend failed - @error = " & @error) ; Receive NTP response $hTimeoutTimer = TimerInit() Do If TimerDiff($hTimeoutTimer) > 2000 Then ExitLoop ; If no response within 2 seconds, then exit the loop $xResponse = UDPRecv($aSocket, DllStructGetSize($tBuffer), $UDP_DATA_BINARY) If @error Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPRecv failed - @error = " & @error) Until $xResponse <> Binary("") ConsoleWrite("DEBUG: Binary response = " & Binary($xResponse) & @CRLF) ; Close the socket UDPCloseSocket($aSocket) ; If the request timed out, exit with a message If $xResponse = Binary("") Then Exit MsgBox($MB_ICONERROR, "ERROR", "UDPRecv timed out") ; Get & display timestamp ; - UTC timestamp is taken from xmit timestamp in NTP response ; - Xmit timestamp is a big-endian, uint32, at binary position 41 ; - Xmit timestamp represents the number of seconds since 1900-01-01 00:00:00 $iSeconds = Dec(Hex(BinaryMid($xResponse, 41, 4)), $NUMBER_64BIT) ConsoleWrite(StringFormat("DEBUG: Xmit timestamp = 0x%s (%s)", Hex(BinaryMid($xResponse, 41, 4)), $iSeconds) & @CRLF) ConsoleWrite("INFO: UTC date/time = " & _DateAdd("s", $iSeconds, "1900/01/01 00:00:00") & @CRLF) ConsoleWrite("INFO: Local date/time = " & _DateAdd("s", $iSeconds + (3600 * $MY_TZ_OFFSET), "1900/01/01 00:00:00") & @CRLF) EndFunc Func udp_shutdown() UDPShutdown() EndFunc Edited October 28, 2019 by TheXman Fixed an insignificant typo CYCho and spudw2k 2 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 27, 2019 Author Share Posted October 27, 2019 @TheXman Your code looks and works like absolutely professional. I will study it. I am glad to see that you started $xRequest with 0x23 because that was what I was thinking after reading your earlier posts. My next goal is to get and set milliseconds as well. I will try and may come back to you for help if I cannot do it alone. Thank you. TheXman 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
TheXman Posted October 28, 2019 Share Posted October 28, 2019 (edited) @CYCho Thank you for the kind words. 3 hours ago, CYCho said: My next goal is to get and set milliseconds as well. I will try and may come back to you for help if I cannot do it alone. Calculating milliseconds from the uint32 Fraction field can seem a bit intimidating at first. Just keep in mind that the Fraction value represents the number of picosecond units. I won't spoil the fun of figuring it out on your own unless you want me to. Feel free to ask for help if you need it (which I'm sure you probably won't). Edited October 28, 2019 by TheXman CYCho 1 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
CYCho Posted October 28, 2019 Author Share Posted October 28, 2019 (edited) @TheXman After several hours of googling, I came up with the following code for calculating fractions of NTP time in millisecs. Your review and comment will be appreciated. $iMilliSecs = Int(Dec(Hex(BinaryMid($xResponse, 45, 4)), $NUMBER_64BIT)/2^32*1000) $iMilliSecs = StringFormat("%03i", $iMilliSecs) Edited October 28, 2019 by CYCho TheXman 1 zPlayer - A Small Audio and Video Player Time Sync + SystemTimeAdjustment Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now