sdk-hwV1.3/external/eyesee-mpp/system/public/ntpclient/ntpclient.c

235 lines
6.2 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/**
* @file ntpclient.c
* @brief ntp时间同步客户端
* @author yinzh
* @version v0.1
* @date 2016-03-09
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <poll.h>
#include <arpa/inet.h>
#include <netdb.h> /* gethostbyname */
#include "ntpclient.h"
static int send_packet(int sockfd)
{
unsigned int ntp_head[12];
memset(ntp_head, 0, sizeof(ntp_head));
ntp_head[0] = htonl(DEF_NTP_HEAD_LI | DEF_NTP_HEAD_VN | DEF_NTP_HEAD_MODE |
DEF_NTP_HEAD_STARTUM | DEF_NTP_HEAD_POLL | DEF_NTP_HEAD_PRECISION);
ntp_head[1] = htonl(1<<16); /* Root Delay (seconds) */
ntp_head[2] = htonl(1<<16); /* Root Dispersion (seconds) */
struct timeval now;
gettimeofday(&now, NULL);
/* 将当前时间写到transmit timestamp */
ntp_head[10] = htonl(now.tv_sec + OFFSET_1900_TO_1970); /* 高32位 */
ntp_head[11] = htonl(NTPFRAC(now.tv_usec)); /* 低32位 */
if (send(sockfd, ntp_head, sizeof(ntp_head), 0) == -1) {
printf("send data failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int connect_to_server(const char *ntp_server)
{
int sockfd;
const char *server;
if (ntp_server != NULL) {
server = ntp_server;
} else {
server = DEF_NTP_SERVER;
}
/* struct sockaddr_in addr_src; */
struct sockaddr_in addr_dst;
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1 ) {
printf("create socket failed: %s\n", strerror(errno));
return -1;
}
struct hostent *host;
host = gethostbyname(server);
if (host == NULL) {
herror(server);
return -1;
}
memset(&addr_dst, 0, sizeof(addr_dst));
memcpy(&(addr_dst.sin_addr.s_addr), host->h_addr_list[0], sizeof(addr_dst.sin_addr));
addr_dst.sin_family = AF_INET;
addr_dst.sin_port = htons(DEF_NTP_PORT);
printf("ntp server %s address:%s, port:%d\n", \
server, inet_ntoa(addr_dst.sin_addr), DEF_NTP_PORT);
if (connect(sockfd, (struct sockaddr*)&addr_dst, sizeof(addr_dst)) == -1) {
printf("connect to server failed:%s\n", strerror(errno));
close(sockfd);
return -1;
}
return sockfd;
}
static int get_time_from_server(int sockfd, struct timeval *time)
{
ntp_timestamp_t origtime, recvtime, transtime, desttime;
uint32_t ntp_data[12];
memset(ntp_data, 0, sizeof(ntp_data));
if (recv(sockfd, ntp_data, sizeof(ntp_data), 0) == -1) {
printf("recv failed:%s\n", strerror(errno));
return -1;
}
struct timeval now;
gettimeofday(&now, NULL);
/* 目的时间戳, 表示客户端接收到数据的时间 */
desttime.integer = now.tv_sec + OFFSET_1900_TO_1970;
desttime.fraction = NTPFRAC(now.tv_usec);
/* 原始时间戳, 表示客户端请求数据的时间 */
origtime.integer = ntohl(ntp_data[6]);
origtime.fraction = ntohl(ntp_data[7]);
/* 接收时间戳, 表示服务器接收到数据的时间 */
recvtime.integer = ntohl(ntp_data[8]);
recvtime.fraction = ntohl(ntp_data[9]);
/* 发送时间戳, 表示服务器发送数据的时间 */
transtime.integer = ntohl(ntp_data[10]);
transtime.fraction = ntohl(ntp_data[11]);
/* 转换ntp时间戳到微秒 */
#define NTPTIME_TO_USEC(ntptime) (((long long)ntptime.integer) * 1000000 + USEC(ntptime.fraction))
int64_t origus, recvus, transus, destus, offus, delayus;
origus = NTPTIME_TO_USEC(origtime);
recvus = NTPTIME_TO_USEC(recvtime);
transus = NTPTIME_TO_USEC(transtime);
destus = NTPTIME_TO_USEC(desttime);
/* 总的网络延迟,包括发送和接收过程 */
offus = ((recvus - origus) + (transus - destus))/2;
/* 这个公式的前提是,假设发送过程和接收过程的网络延迟相同 */
delayus = (recvus - origus) + (destus - transus);
printf("offus: %lld, delayus: %lld\n", offus, delayus);
struct timeval newtime;
uint64_t new_usec = (uint64_t)now.tv_sec * 1000000 + now.tv_usec + offus;
printf("new_usec: %llu\n", new_usec);
newtime.tv_sec = new_usec / 1000000;
newtime.tv_usec = new_usec % 1000000;
printf("nowtime.tv_sec:%ld, nowtime.tv_usec:%ld\n", now.tv_sec, now.tv_usec);
printf("newtime.tv_sec:%ld, newtime.tv_usec:%ld\n", newtime.tv_sec, newtime.tv_usec);
memcpy(time, &newtime, sizeof(struct timeval));
return 0;
}
int main(int argc, char *argv[])
{
int sockfd;
int ret;
char need_set = 0;
char *server = NULL;
if (argc >= 3 && !strcmp(argv[1], "-s")) {
need_set = 1;
server = argv[2];
} else if (argc >= 2) {
server = argv[1];
}
while(1) {
/* query_server("0.cn.poll.ntp.org"); */
if ( (sockfd = connect_to_server(server)) == -1) {
printf("try again\n");
sleep(3);
continue;
}
send_packet(sockfd);
struct pollfd pfd;
pfd.fd = sockfd;
pfd.events = POLLIN;
ret = poll(&pfd, 1, 300);
if (ret == 1) {
/* Looks good, try setting time on host ... */
struct timeval time;
if (get_time_from_server(sockfd, &time) == -1) {
close(sockfd);
sleep(1);
continue;
}
if (need_set) {
struct timezone zone;
zone.tz_minuteswest = timezone/60 - 60*daylight;
zone.tz_dsttime = 0;
if (settimeofday(&time, &zone) < 0) {
fprintf(stderr, "set time failed, %s, try again\n", strerror(errno));
close(sockfd);
sleep(5);
system("date 2016-01-01\\ 00:00 ; hwclock -w");
continue;
}
}
close(sockfd);
return 0; /* All done! :) */
} else if (ret == 0) {
printf("timeout retry!\n");
close(sockfd);
sleep(1);
continue;
}
}
close(sockfd);
return 0;
}