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