📄 sntp.c
字号:
/*说明: 1) 本程序读取配置文件/etc/ntp.conf中的server段所示的时间服务器,如tick.stdtime.gov.tw等; 2) 将这些服务器名转换为IP地址.加入服务器列表中.服务器列表最多能加入MAX_TIME_SERVER个时间服务器. 3) 从服务器列表中选取一个比较精确的时间服务器,使本机同其同步. 4) 主进程调用register_serv()函数载入时间服务器的IP地址,然后调用sntp_start()函数起动sntp客户端. 5) sntp客户端收到发往本进程的UDP包,判定是合法时间服务器所发的包后,作一些比较处理并修改时间. 6) 本进程起动的时间间隔为UPDATEPERIOD秒,超时时间定义为UPDATETIMEOUT秒,分别定义为30*60和10; 7) 有关ntp/sntp的数据结构在sntp.h中定义;*/#include "sntp.h"static intis_better (struct sntp_srv_s *newer, struct sntp_srv_s *old){ time_t last_time, diff; if (!memcmp (&newer->addr, &old->addr, sizeof (struct sockaddr))) return 1; if (newer->stratum < old->stratum) return 1; if (old->timestamp != 0xffffffff) { last_time = TIME_NTP_TO_LOCAL (old->timestamp); diff = time (NULL) - last_time; if (diff > 600) return 1; return 0; } return 1;}intisInServerList (struct sockaddr_in *pserver_addr, struct sockaddr_in *sntp_server_list, unsigned int sntp_num_servers){ int i; for (i = 0; i < sntp_num_servers; i++) { if (memcmp (&(pserver_addr->sin_addr), &(sntp_server_list[i].sin_addr), sizeof (struct in_addr)) == 0) { if (pserver_addr->sin_port == htons(TIME_PORT)) return 1; } } return 0;}voidsntp_start (struct sockaddr_in *server_list, unsigned int num_servers){ if (num_servers == 0) return; struct sockaddr_in *sntp_servers = server_list; unsigned int sntp_num_servers = num_servers; time_t NextTimeUpdate = 0; int fd; int ret; NTP_PACKET ntp_pkt; struct sntp_srv_s new_srv; struct sntp_srv_s best_srv; int mode; int len; time_t new_time, current_time, diff; fd_set readfds; int n; int i; struct timeval timeout; struct timeval *ptimeout = NULL; struct sockaddr_in *preply_addr = (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in)); memset (&best_srv, 0xff, sizeof (best_srv)); fd = socket (AF_INET, SOCK_DGRAM, 0); if (fd <= 0) { perror ("Failed to open socket"); return; } n = fd; while (1) { FD_ZERO (&readfds); FD_SET (fd, &readfds); timeout.tv_sec = SNTP_WAITPERIOD; timeout.tv_usec = 0; ptimeout = &timeout; if (NextTimeUpdate != 0) { current_time = time (NULL); if (current_time < NextTimeUpdate) { timeout.tv_sec = (SNTP_WAITPERIOD > (NextTimeUpdate - current_time) ? (NextTimeUpdate - current_time) : SNTP_WAITPERIOD); } else NextTimeUpdate = 0; } if (NextTimeUpdate == 0 && (sntp_num_servers > 0)) { memset (&ntp_pkt, 0, sizeof (ntp_pkt)); ntp_pkt.Control = NTP_LI_NOLEAP | NTP_MODE_SET (NTP_MODE_CLIENT) | NTP_VERSION_SET (3); for (i = 0; i < sntp_num_servers; i++) { ntp_pkt.TransmitTimestamp.Seconds = htonl (TIME_LOCAL_TO_NTP (time (NULL))); sendto (fd, &ntp_pkt, sizeof (ntp_pkt), 0, (struct sockaddr *) &(sntp_servers[i]), sizeof (struct sockaddr_in)); NextTimeUpdate = time (NULL) + SNTP_WAITPERIOD; } ret = select (n + 1, &readfds, NULL, NULL, ptimeout); if (ret <= 0) { printf ("timeout or error occur\n"); sleep (1); continue; } len = sizeof (struct sockaddr); if (FD_ISSET (fd, &readfds)) { ret = recvfrom (fd, &ntp_pkt, sizeof (ntp_pkt), 0, (struct sockaddr *) preply_addr, &len); if (!isInServerList (preply_addr, sntp_servers, sntp_num_servers)) continue; } if (ret < NTP_PACKET_MINLEN) { perror ("receive size too small"); continue; } new_srv.version = NTP_VERSION_GET (&ntp_pkt); new_srv.stratum = ntp_pkt.Stratum; new_srv.timestamp = ntohl (ntp_pkt.TransmitTimestamp.Seconds); mode = NTP_MODE_GET (&ntp_pkt); if (new_srv.version < 3 || new_srv.version > 4) { continue; } if (mode != NTP_MODE_BROADCAST && mode != NTP_MODE_SERVER) continue; if (is_better (&new_srv, &best_srv)) { best_srv = new_srv; new_time = TIME_NTP_TO_LOCAL (best_srv.timestamp); current_time = time (NULL); diff = current_time - new_time; if (diff < 0) diff = -diff; if (diff > 2) stime (&new_time); } sleep (SNTP_UPDATEPERIOD); NextTimeUpdate = time (NULL); } }}intregister_serv (int j, char *server_name, struct sockaddr_in *server_list){ int i; struct hostent *hp; char *pname; pname = server_name; while ((*pname != ' ') && (*pname != '\t') && (*pname != '\n')) pname++; (*pname) = 0; printf ("the server_name=%s,and the len=%d\n", server_name, strlen (server_name)); for (i = 0; i < 3; i++) { if (!(hp = gethostbyname (server_name))) continue; else break; } if (hp == NULL) return 0; memcpy (&(server_list[j].sin_addr), hp->h_addr, 4); server_list[j].sin_port = htons (TIME_PORT); server_list[j].sin_family = AF_INET; return 1;}intmain (){ int ifork; if ((ifork = fork ()) < 0) { printf (">>can't fork\n"); exit (-1); } else if (ifork > 0) { exit (0); } struct sockaddr_in time_server_list[MAX_SNTP_SERVER]; FILE *fp; fp = fopen ("/etc/ntp.conf", "r"); if (fp <= 0) { printf (" 配置文件不存在,程序不能执行\n"); exit (0); } char linebuf[MAXLINE]; char servname[100]; int i = 0; char *pname; while (fgets (linebuf, MAXLINE, fp) != NULL) { if ((strncmp (linebuf, "server", 6) == 0)) { pname = linebuf; pname += 7; while ((*pname) == ' ') pname++; if (strncmp (pname, "127.", 4) == 0) continue; if (i > MAX_SNTP_SERVER) break; if (register_serv (i, pname, time_server_list)) { printf ("the time server %s is registered\n", pname); i++; } else { printf ("the time server %s register failed\n", pname); } } else continue; } fclose (fp); sntp_start ((struct sockaddr_in *) time_server_list, i--); exit (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -