blob: 704643aee8bd752f09ec877b08016f0a0ddc45e6 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001/*
2* FILE: ntp.c
3* NOTE: socket网络编程学习,NTP时间获取程序
4*
5* TIME: 2021年11月13日00:05:39
6*/
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <stdio.h>
10#include <errno.h>
11#include <netdb.h>
12#include <string.h>
13#include <unistd.h>
14#include <time.h>
15#include <netinet/in.h>
b.liu778645e2024-06-21 16:47:42 +080016#include <sys/time.h>
liubin281ac462023-07-19 14:22:54 +080017
18#include "mbtk_log.h"
19
20#define NTP_PORT 123
21#define TIME_PORT 37
22#define NTP_SERVER_IP "cn.pool.ntp.org"
23
24#define NTP_PORT_STR "123"
25#define NTPV1 "NTP/V1"
26#define NTPV2 "NTP/V2"
27
28#define NTPV3 "NTP/V3"
29#define NTPV4 "NTP/V4"
30#define TIME "TIME/UDP"
31
32#define NTP_PCK_LEN 48
33
34#define LI 0
35#define VN 3
36#define MODE 3
37#define STRATUM 0
38#define POLL 4
39#define PREC -6
40
41#define JAN_1970 0x83aa7e80 /* 1900 年~1970 年之间的时间秒数 */
42#define NTPFRAC(x) (4294 * (x) + ((1981 * (x)) >> 11))
43#define USEC(x) (((x) >> 12) - 759 * ((((x) >> 10) + 32768) >> 16))
44
45
46time_t sys_time;
47typedef struct _ntp_time
48{
49 unsigned int coarse;
50 unsigned int fine;
51} ntp_time;
52
53/* NTP时钟同步报文 */
54struct ntp_packet
55{
56 unsigned char leap_ver_mode;
57 unsigned char startum;
58 char poll;
59 char precision;
60 int root_delay;
61 int root_dispersion;
62 int reference_identifier;
63 ntp_time reference_timestamp;
64 ntp_time originage_timestamp;
65 ntp_time receive_timestamp;
66 ntp_time transmit_timestamp;
67};
68
69char protocol[32];
70
71int construct_packet(char *packet)
72{
73 char version = 1;
74 long tmp_wrd;
liubin281ac462023-07-19 14:22:54 +080075 time_t timer;
76 strcpy(protocol, NTPV4);
77 /*判断协议版本*/
78 if(!strcmp(protocol, NTPV1)||!strcmp(protocol, NTPV2)||!strcmp(protocol, NTPV3)||!strcmp(protocol, NTPV4))
79 {
80 memset(packet, 0, NTP_PCK_LEN);
liubin281ac462023-07-19 14:22:54 +080081 /*设置 16 字节的包头*/
82 version = protocol[5] - 0x30;
83 tmp_wrd = htonl((LI << 30)|(version << 27) \
84 |(MODE << 24)|(STRATUM << 16)|(POLL << 8)|(PREC & 0xff));
85 memcpy(packet, &tmp_wrd, sizeof(tmp_wrd));
86
87 /*设置 Root Delay、 Root Dispersion 和 Reference Indentifier */
88 tmp_wrd = htonl(1<<16);
89 memcpy(&packet[4], &tmp_wrd, sizeof(tmp_wrd));
90 memcpy(&packet[8], &tmp_wrd, sizeof(tmp_wrd));
91 /*设置 Timestamp 部分*/
92 time(&timer);
93 /*设置 Transmit Timestamp coarse*/
94 tmp_wrd = htonl(JAN_1970 + (long)timer);
95 memcpy(&packet[40], &tmp_wrd, sizeof(tmp_wrd));
96 /*设置 Transmit Timestamp fine*/
97 tmp_wrd = htonl((long)NTPFRAC(timer));
98 memcpy(&packet[44], &tmp_wrd, sizeof(tmp_wrd));
99 return NTP_PCK_LEN;
100 }
101 else if (!strcmp(protocol, TIME))/* "TIME/UDP" */
102 {
liubin281ac462023-07-19 14:22:54 +0800103 memset(packet, 0, 4);
104 return 4;
105 }
106
107 return 0;
108}
109
110/*获取 NTP 时间*/
111int get_ntp_time(int sk, struct addrinfo *addr, struct ntp_packet *ret_time)
112{
113 fd_set pending_data;
114 struct timeval block_time;
115 char data[NTP_PCK_LEN * 8];
b.liu778645e2024-06-21 16:47:42 +0800116 socklen_t data_len = addr->ai_addrlen;
b.liu9e8584b2024-11-06 19:21:28 +0800117 int packet_len, count = 0, result;
liubin281ac462023-07-19 14:22:54 +0800118
119 /* 组织请求报文 */
120 if (!(packet_len = construct_packet(data)))
121 {
122 return 0;
123 }
124 /*客户端给服务器端发送 NTP 协议数据包*/
125 if ((result = sendto(sk, data, packet_len, 0, addr->ai_addr, data_len)) < 0)
126 {
127 LOGE("sendto");
128 return 0;
129 }
130 /*调用select()函数,并设定超时时间为10s*/
131 FD_ZERO(&pending_data);
132 FD_SET(sk, &pending_data);
133 block_time.tv_sec=10;
134 block_time.tv_usec=0;
135 if (select(sk + 1, &pending_data, NULL, NULL, &block_time) > 0)
136 {
137 /*接收服务器端的信息*/
138 if ((count = recvfrom(sk, data, NTP_PCK_LEN * 8, 0, addr->ai_addr, &data_len)) < 0)
139 {
140 LOGE("recvfrom");
141 return 0;
142 }
143
144 // if (protocol == TIME)
145 if(!strcmp(protocol,TIME))
146 {
147 memcpy(&ret_time->transmit_timestamp, data, 4);
148 return 1;
149 }
150 else if (count < NTP_PCK_LEN)
151 {
152 return 0;
153 }
154
155 /* 设置接收 NTP 包的数据结构 */
156 ret_time->leap_ver_mode = ntohl(data[0]);
157 ret_time->startum = ntohl(data[1]);
158 ret_time->poll = ntohl(data[2]);
159 ret_time->precision = ntohl(data[3]);
160 ret_time->root_delay = ntohl(*(int*)&(data[4]));
161 ret_time->root_dispersion = ntohl(*(int*)&(data[8]));
162 ret_time->reference_identifier = ntohl(*(int*)&(data[12]));
163 ret_time->reference_timestamp.coarse = ntohl(*(int*)&(data[16]));
164 ret_time->reference_timestamp.fine = ntohl(*(int*)&(data[20]));
165 ret_time->originage_timestamp.coarse = ntohl(*(int*)&(data[24]));
166 ret_time->originage_timestamp.fine = ntohl(*(int*)&(data[28]));
167 ret_time->receive_timestamp.coarse = ntohl(*(int*)&(data[32]));
168 ret_time->receive_timestamp.fine = ntohl(*(int*)&(data[36]));
169 ret_time->transmit_timestamp.coarse = ntohl(*(int*)&(data[40]));
170 ret_time->transmit_timestamp.fine = ntohl(*(int*)&(data[44]));
171
172 /* 将NTP时间戳转换为日期 */
173 time_t currentTime = ret_time->transmit_timestamp.coarse - JAN_1970;
174 sys_time = ret_time->transmit_timestamp.coarse - JAN_1970;
175 struct tm CurlocalTime;
176 localtime_r(&currentTime, &CurlocalTime);
177 char dateTime[30];
178 strftime(dateTime, 30, "%Y-%m-%d %H:%M:%S %A", &CurlocalTime);
179
180 LOGI("%s\n", dateTime);
181
182 return 1;
183 } /* end of if select */
184
185
186 return 0;
187}
188
189/* 修改本地时间 */
190int set_local_time(struct ntp_packet * pnew_time_packet)
191{
192 struct timeval tv;
193 tv.tv_sec = pnew_time_packet->transmit_timestamp.coarse - JAN_1970;
194 tv.tv_usec = USEC(pnew_time_packet->transmit_timestamp.fine);
195 return settimeofday(&tv, NULL);
196}
197
198int ntp_main()
199{
200 int sockfd, rc;
201 struct addrinfo hints, *res = NULL;
202 struct ntp_packet new_time_packet;
203
204 memset(&hints, 0, sizeof(hints));
205 hints.ai_family = AF_INET;
206 hints.ai_socktype = SOCK_DGRAM;
207 hints.ai_protocol = IPPROTO_UDP;
208
209 /*调用 getaddrinfo()函数, 获取地址信息*/
210 rc = getaddrinfo(NTP_SERVER_IP, NTP_PORT_STR, &hints, &res);
211 if (rc != 0)
212 {
213 LOGE("getaddrinfo");
214 return 0;
215 }
216
217 /* 创建套接字 */
218 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //IPv4, 数据报套接字, UDP
219 if (sockfd <0 )
220 {
221 LOGE("socket");
222 return 0;
223 }
224
225 /*调用取得 NTP 时间的函数*/
226 if (get_ntp_time(sockfd, res, &new_time_packet))
227 {
liuyang54582902024-04-19 18:06:25 +0800228 printf("NTP client success!\n");
liubin281ac462023-07-19 14:22:54 +0800229 LOGI("NTP client success!\n");
230 }
liuyang54582902024-04-19 18:06:25 +0800231 else
232 {
liuyangd0f7fdb2024-04-22 13:53:23 +0800233 printf("NTP client fail!\n");
234 LOGE("NTP client fail!\n");
liuyang54582902024-04-19 18:06:25 +0800235 close(sockfd);
236 return 0;
237 }
liubin281ac462023-07-19 14:22:54 +0800238
239 close(sockfd);
240
241 return sys_time;
242}
243
244time_t ntp_server_set(const char* server_ip, const char * port)
245{
246 int sockfd, rc;
247 struct addrinfo hints, *res = NULL;
248 struct ntp_packet new_time_packet;
249
250 memset(&hints, 0, sizeof(hints));
251 hints.ai_family = AF_INET;
252 hints.ai_socktype = SOCK_DGRAM;
253 hints.ai_protocol = IPPROTO_UDP;
254
255 printf("server_ip:%s,port:%s\n", server_ip, port);
256
257 /*调用 getaddrinfo()函数, 获取地址信息*/
258 rc = getaddrinfo(NTP_SERVER_IP, NTP_PORT_STR, &hints, &res);
259 if (rc != 0)
260 {
261 printf("getaddrinfo");
262 return 0;
263 }
264
265 /* 创建套接字 */
266 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //IPv4, 数据报套接字, UDP
267 if (sockfd <0 )
268 {
269 printf("socket");
270 return 0;
271 }
272
273 /*调用取得 NTP 时间的函数*/
274 if (get_ntp_time(sockfd, res, &new_time_packet))
275 {
276 printf("NTP client success!\n");
277 }
278
279 close(sockfd);
280
281 return sys_time;
282}
283
284
285time_t mbtk_ntp_server_set(const char* server_ip, const char * port)
286{
287 return ntp_server_set(server_ip, port);
288}
289
290
291int mbtk_at_systime(void)
292{
293 return ntp_main();
294}
295
296