• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sntp_client.h"
17 
18 #include <chrono>
19 #include <cstdio>
20 #include <ctime>
21 #include <iomanip>
22 #include <netdb.h>
23 #include <netinet/in.h>
24 #include <securec.h>
25 #include <sstream>
26 #include <string>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 
32 #include "time_common.h"
33 
34 namespace OHOS {
35 namespace MiscServices {
36 namespace {
37 constexpr auto SECONDS_SINCE_FIRST_EPOCH = (2208988800UL); // Seconds from 1/1/1900 00.00 to 1/1/1970 00.00;
38 constexpr uint64_t MILLISECOND_TO_SECOND = 1000;
39 constexpr uint64_t FRACTION_TO_SECOND = 0x100000000;
40 constexpr uint64_t UINT32_MASK = 0xFFFFFFFF;
41 const int VERSION_MASK = 0x38;
42 const int MODE_MASK = 0x7;
43 constexpr int32_t INVALID_RETURN = -1;
44 constexpr int32_t INDEX_ZERO = 0;
45 constexpr int32_t INDEX_ONE = 1;
46 constexpr int32_t INDEX_TWO = 2;
47 constexpr int32_t INDEX_THREE = 3;
48 constexpr int32_t INDEX_FOUR = 4;
49 constexpr int32_t TIME_OUT = 5;
50 constexpr unsigned char MODE_THREE = 3;
51 constexpr unsigned char VERSION_THREE = 3;
52 constexpr double TEN_TO_MINUS_SIX_POWER = 1.0e-6;
53 constexpr double TEN_TO_SIX_POWER = 1.0e6;
54 char const *NTP_PORT = "123";
55 constexpr int32_t NTP_MSG_OFFSET_ROOT_DELAY = 4;
56 constexpr int32_t NTP_MSG_OFFSET_ROOT_DISPERSION = 8;
57 constexpr int32_t NTP_MSG_OFFSET_REFERENCE_IDENTIFIER = 12;
58 constexpr int32_t REFERENCE_TIMESTAMP_OFFSET = 16;
59 constexpr int32_t ORIGINATE_TIMESTAMP_OFFSET = 24;
60 constexpr int32_t RECEIVE_TIMESTAMP_OFFSET = 32;
61 constexpr int32_t TRANSMIT_TIMESTAMP_OFFSET = 40;
62 constexpr int32_t NTP_PACKAGE_SIZE = 48;
63 constexpr int32_t SNTP_MSG_OFFSET_SIX = 6;
64 constexpr int32_t SNTP_MSG_OFFSET_THREE = 3;
65 } // namespace
SNTPClient()66 SNTPClient::SNTPClient()
67 {
68 }
~SNTPClient()69 SNTPClient::~SNTPClient()
70 {
71 }
72 
RequestTime(std::string host)73 bool SNTPClient::RequestTime(std::string host)
74 {
75     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
76     int bufLen = NTP_PACKAGE_SIZE;
77 
78     struct addrinfo hints = { 0 }, *addrs;
79     hints.ai_family = AF_INET;
80     hints.ai_socktype = SOCK_DGRAM;
81     hints.ai_protocol = IPPROTO_UDP;
82 
83     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime1.");
84     int status = getaddrinfo(host.c_str(), NTP_PORT, &hints, &addrs);
85     if (status != 0) {
86         TIME_HILOGE(TIME_MODULE_SERVICE, "getaddrinfo failed");
87         return false;
88     }
89     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime2.");
90     // Create a socket for sending data
91     int sendSocket = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
92     if (sendSocket == 0) {
93         TIME_HILOGE(TIME_MODULE_SERVICE, "create socket failed");
94         return false;
95     }
96     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime3.");
97     // Set send and recv function timeout
98     struct timeval timeout = { TIME_OUT, 0 };
99     setsockopt(sendSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
100     setsockopt(sendSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
101 
102     if (connect(sendSocket, addrs->ai_addr, addrs->ai_addrlen) < 0) {
103         TIME_HILOGE(TIME_MODULE_SERVICE, "socket connect failed");
104         return false;
105     }
106     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime4.");
107     // Create the NTP tx timestamp and fill the fields in the msg to be tx
108     char sendBuf[NTP_PACKAGE_SIZE] = { 0 };
109     CreateMessage(sendBuf);
110     if (send(sendSocket, sendBuf, bufLen, 0) == INVALID_RETURN) {
111         TIME_HILOGE(TIME_MODULE_SERVICE, "Send socket message failed. Host: %{public}s", host.c_str());
112         close(sendSocket);
113         return false;
114     }
115     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime5.");
116     char bufferRx[NTP_PACKAGE_SIZE] = { 0 };
117     // Receive until the peer closes the connection
118     if (recv(sendSocket, bufferRx, NTP_PACKAGE_SIZE, 0) == INVALID_RETURN) {
119         TIME_HILOGE(TIME_MODULE_SERVICE, "Receive socket message failed. Host: %{public}s", host.c_str());
120         close(sendSocket);
121         return false;
122     }
123     TIME_HILOGD(TIME_MODULE_SERVICE, "RequestTime6.");
124     ReceivedMessage(bufferRx);
125     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
126     close(sendSocket);
127     return true;
128 }
129 
SetClockOffset(int clockOffset)130 void SNTPClient::SetClockOffset(int clockOffset)
131 {
132     m_clockOffset = clockOffset;
133 }
134 
GetClockOffset(void)135 int SNTPClient::GetClockOffset(void)
136 {
137     return m_clockOffset;
138 }
139 
GetNtpTimestamp64(int offset,const char * buffer)140 uint64_t SNTPClient::GetNtpTimestamp64(int offset, const char *buffer)
141 {
142     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
143     const int _len = sizeof(uint64_t);
144     char valueRx[_len];
145     errno_t ret = memset_s(valueRx, sizeof(uint64_t), 0, sizeof(uint64_t));
146     if (ret != EOK) {
147         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", ret);
148         return false;
149     }
150     int numOfBit = sizeof(uint64_t) - 1;
151     for (int loop = offset; loop < offset + _len; loop++) {
152         valueRx[numOfBit] = buffer[loop];
153         numOfBit--;
154     }
155 
156     uint64_t milliseconds;
157     ret = memcpy_s(&milliseconds, sizeof(uint64_t), valueRx, sizeof(uint64_t));
158     if (ret != EOK) {
159         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", ret);
160         return false;
161     }
162     return le64toh(milliseconds);
163 }
164 
ConvertUnixToNtp(struct ntp_timestamp * ntpTs,struct timeval * unixTs)165 void SNTPClient::ConvertUnixToNtp(struct ntp_timestamp *ntpTs, struct timeval *unixTs)
166 {
167     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
168     // 0x83AA7E80; the seconds from Jan 1, 1900 to Jan 1, 1970
169     ntpTs->second = unixTs->tv_sec + SECONDS_SINCE_FIRST_EPOCH; // 0x83AA7E80;
170     ntpTs->fraction =
171         (uint32_t)((double)(unixTs->tv_usec + 1) * (double)(1LL << RECEIVE_TIMESTAMP_OFFSET) * TEN_TO_MINUS_SIX_POWER);
172     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
173 }
174 
ConvertNtpToUnix(struct ntp_timestamp * ntpTs,struct timeval * unixTs)175 void SNTPClient::ConvertNtpToUnix(struct ntp_timestamp *ntpTs, struct timeval *unixTs)
176 {
177     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
178     // 0x83AA7E80; the seconds from Jan 1, 1900 to Jan 1, 1970
179     unixTs->tv_sec = ntpTs->second - SECONDS_SINCE_FIRST_EPOCH;
180     unixTs->tv_usec =
181         (uint32_t)((double)ntpTs->fraction * TEN_TO_SIX_POWER / (double)(1LL << RECEIVE_TIMESTAMP_OFFSET));
182     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
183 }
184 
185 /*
186   *	/// SNTP Timestamp Format (as described in RFC 2030)
187   *                         1                   2                   3
188   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
189   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190   *   |                           Seconds                             |
191   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192   *   |                  Seconds Fraction (0-padded)                  |
193   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
194   */
ConvertNtpToStamp(uint64_t _ntpTs)195 int64_t SNTPClient::ConvertNtpToStamp(uint64_t _ntpTs)
196 {
197     auto second = static_cast<uint32_t>((_ntpTs >> RECEIVE_TIMESTAMP_OFFSET) & UINT32_MASK);
198     auto fraction = static_cast<uint32_t>(_ntpTs & UINT32_MASK);
199     if (second == 0 && fraction == 0) {
200         return 0;
201     }
202     if (second < SECONDS_SINCE_FIRST_EPOCH) {
203         return 0;
204     }
205     // convert sntp timestamp to seconds
206     return ((second - SECONDS_SINCE_FIRST_EPOCH) * MILLISECOND_TO_SECOND) +
207            ((fraction * MILLISECOND_TO_SECOND) / FRACTION_TO_SECOND);
208 }
209 
CreateMessage(char * buffer)210 void SNTPClient::CreateMessage(char *buffer)
211 {
212     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
213     struct ntp_timestamp ntp;
214     struct timeval unix;
215 
216     gettimeofday(&unix, NULL);
217     // convert unix time to ntp time
218     ConvertUnixToNtp(&ntp, &unix);
219     ConvertNtpToUnix(&ntp, &unix);
220     uint64_t _ntpTs = ntp.second;
221     _ntpTs = (_ntpTs << RECEIVE_TIMESTAMP_OFFSET) | ntp.fraction;
222     m_originateTimestamp = _ntpTs;
223 
224     SNTPMessage _sntpMsg;
225     // Important, if you don't set the version/mode, the server will ignore you.
226     _sntpMsg.clear();
227     _sntpMsg._leapIndicator = 0;
228     _sntpMsg._versionNumber = VERSION_THREE;
229     _sntpMsg._mode = MODE_THREE;
230     // optional (?)
231     _sntpMsg._originateTimestamp = _ntpTs;
232     char value[sizeof(uint64_t)];
233     errno_t ret = memcpy_s(value, sizeof(uint64_t), &_sntpMsg._originateTimestamp, sizeof(uint64_t));
234     if (ret != EOK) {
235         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", ret);
236         return;
237     }
238     int numOfBit = sizeof(uint64_t) - 1;
239     int offsetEnd = ORIGINATE_TIMESTAMP_OFFSET + sizeof(uint64_t);
240     for (int loop = ORIGINATE_TIMESTAMP_OFFSET; loop < offsetEnd; loop++) {
241         buffer[loop] = value[numOfBit];
242         numOfBit--;
243     }
244     // create the 1-byte info in one go... the result should be 27 :)
245     buffer[INDEX_ZERO] = (_sntpMsg._leapIndicator << SNTP_MSG_OFFSET_SIX) |
246                          (_sntpMsg._versionNumber << SNTP_MSG_OFFSET_THREE) | _sntpMsg._mode;
247     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
248 }
249 
WriteTimeStamp(char * buffer,ntp_timestamp * ntp)250 void SNTPClient::WriteTimeStamp(char *buffer, ntp_timestamp *ntp)
251 {
252     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
253     uint64_t _ntpTs = ntp->second;
254     _ntpTs = (_ntpTs << RECEIVE_TIMESTAMP_OFFSET) | ntp->fraction;
255     m_originateTimestamp = _ntpTs;
256 
257     SNTPMessage _sntpMsg;
258     // Important, if you don't set the version/mode, the server will ignore you.
259     _sntpMsg.clear();
260     _sntpMsg._leapIndicator = 0;
261     _sntpMsg._versionNumber = VERSION_THREE;
262     _sntpMsg._mode = MODE_THREE;
263     _sntpMsg._originateTimestamp = _ntpTs;
264     char value[sizeof(uint64_t)];
265     errno_t ret = memcpy_s(value, sizeof(uint64_t), &_sntpMsg._originateTimestamp, sizeof(uint64_t));
266     if (ret != EOK) {
267         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", ret);
268         return;
269     }
270     int numOfBit = sizeof(uint64_t) - 1;
271     int offsetEnd = ORIGINATE_TIMESTAMP_OFFSET + sizeof(uint64_t);
272     for (int loop = ORIGINATE_TIMESTAMP_OFFSET; loop < offsetEnd; loop++) {
273         buffer[loop] = value[numOfBit];
274         numOfBit--;
275     }
276     // create the 1-byte info in one go... the result should be 27 :)
277     buffer[INDEX_ZERO] = (_sntpMsg._leapIndicator << SNTP_MSG_OFFSET_SIX) |
278                          (_sntpMsg._versionNumber << SNTP_MSG_OFFSET_THREE) | _sntpMsg._mode;
279     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
280 }
281 
ReceivedMessage(char * buffer)282 void SNTPClient::ReceivedMessage(char *buffer)
283 {
284     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
285     struct ntp_timestamp ntp;
286     struct timeval unix;
287 
288     gettimeofday(&unix, NULL);
289     ConvertUnixToNtp(&ntp, &unix);
290     uint64_t _ntpTs = ntp.second;
291     _ntpTs = (_ntpTs << RECEIVE_TIMESTAMP_OFFSET) | ntp.fraction;
292 
293     SNTPMessage _sntpMsg;
294     _sntpMsg.clear();
295     _sntpMsg._leapIndicator = buffer[INDEX_ZERO] >> SNTP_MSG_OFFSET_SIX;
296     _sntpMsg._versionNumber = (buffer[INDEX_ZERO] & VERSION_MASK) >> SNTP_MSG_OFFSET_THREE;
297     _sntpMsg._mode = (buffer[INDEX_ZERO] & MODE_MASK);
298     _sntpMsg._stratum = buffer[INDEX_ONE];
299     _sntpMsg._pollInterval = buffer[INDEX_TWO];
300     _sntpMsg._precision = buffer[INDEX_THREE];
301     _sntpMsg._rootDelay = GetNtpField32(NTP_MSG_OFFSET_ROOT_DELAY, buffer);
302     _sntpMsg._rootDispersion = GetNtpField32(NTP_MSG_OFFSET_ROOT_DISPERSION, buffer);
303     int _refId[INDEX_FOUR];
304     GetReferenceId(NTP_MSG_OFFSET_REFERENCE_IDENTIFIER, buffer, _refId);
305     _sntpMsg._referenceIdentifier[INDEX_ZERO] = _refId[INDEX_ZERO];
306     _sntpMsg._referenceIdentifier[INDEX_ONE] = _refId[INDEX_ONE];
307     _sntpMsg._referenceIdentifier[INDEX_TWO] = _refId[INDEX_TWO];
308     _sntpMsg._referenceIdentifier[INDEX_THREE] = _refId[INDEX_THREE];
309     _sntpMsg._referenceTimestamp = GetNtpTimestamp64(REFERENCE_TIMESTAMP_OFFSET, buffer);
310     _sntpMsg._originateTimestamp = GetNtpTimestamp64(ORIGINATE_TIMESTAMP_OFFSET, buffer);
311     _sntpMsg._receiveTimestamp = GetNtpTimestamp64(RECEIVE_TIMESTAMP_OFFSET, buffer);
312     _sntpMsg._transmitTimestamp = GetNtpTimestamp64(TRANSMIT_TIMESTAMP_OFFSET, buffer);
313 
314     uint64_t _tempOriginate = m_originateTimestamp;
315     if (_sntpMsg._originateTimestamp > 0) {
316         _tempOriginate = _sntpMsg._originateTimestamp;
317     }
318 
319     int64_t _originClient = ConvertNtpToStamp(_tempOriginate);
320     int64_t _receiveServer = ConvertNtpToStamp(_sntpMsg._receiveTimestamp);
321     int64_t _transmitServer = ConvertNtpToStamp(_sntpMsg._transmitTimestamp);
322     int64_t _receiveClient = ConvertNtpToStamp(_ntpTs);
323 
324     int64_t _clockOffset = (((_receiveServer - _originClient) + (_transmitServer - _receiveClient)) / INDEX_TWO);
325     int64_t _roundTripDelay = (_receiveClient - _originClient) - (_transmitServer - _receiveServer);
326     mRoundTripTime = _roundTripDelay;
327     mNtpTime = ConvertNtpToStamp(_ntpTs) + _clockOffset;
328     mNtpTimeReference =
329         std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch())
330             .count();
331     SetClockOffset(_clockOffset);
332     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
333 }
334 
GetNtpField32(int offset,const char * buffer)335 unsigned int SNTPClient::GetNtpField32(int offset, const char *buffer)
336 {
337     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
338     const int _len = sizeof(int);
339     char valueRx[_len];
340     errno_t ret = memset_s(valueRx, _len, 0, _len);
341     if (ret != EOK) {
342         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", ret);
343         return false;
344     }
345     int numOfBit = sizeof(int) - 1;
346     for (int loop = offset; loop < offset + _len; loop++) {
347         valueRx[numOfBit] = buffer[loop];
348         numOfBit--;
349     }
350 
351     unsigned int milliseconds;
352     errno_t retValue = memcpy_s(&milliseconds, sizeof(int), valueRx, sizeof(int));
353     if (retValue != EOK) {
354         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %d\n", retValue);
355         return false;
356     }
357     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
358     return milliseconds;
359 }
360 
GetReferenceId(int offset,char * buffer,int * _outArray)361 void SNTPClient::GetReferenceId(int offset, char *buffer, int *_outArray)
362 {
363     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
364     const int _len = sizeof(int);
365     int num = 0;
366     for (int loop = offset; loop < offset + _len; loop++) {
367         _outArray[num] = buffer[loop];
368         num++;
369     }
370     TIME_HILOGD(TIME_MODULE_SERVICE, "end.");
371 }
372 
clear()373 void SNTPClient::SNTPMessage::clear()
374 {
375     TIME_HILOGD(TIME_MODULE_SERVICE, "start.");
376     errno_t ret = memset_s(this, sizeof(*this), 0, sizeof(*this));
377     if (ret != EOK) {
378         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed.");
379     }
380 }
381 
getNtpTIme()382 int64_t SNTPClient::getNtpTIme()
383 {
384     return mNtpTime;
385 }
386 
getNtpTimeReference()387 int64_t SNTPClient::getNtpTimeReference()
388 {
389     return mNtpTimeReference;
390 }
391 
getRoundTripTime()392 int64_t SNTPClient::getRoundTripTime()
393 {
394     return mRoundTripTime;
395 }
396 } // namespace MiscServices
397 } // namespace OHOS