OpenWrt_Luci_Lua/1_6.h12_dev/ntp/timesync/server.c
2015-07-08 19:16:28 +08:00

214 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h> /* gettimeofday() */
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h> /* for time() and ctime() */
//1900至1970年间经过的总秒数
#define UTC_NTP 2208988800U /* 1970 - 1900 */
/* get Timestamp for NTP in LOCAL ENDIAN */
void gettime64(uint32_t ts[])
{
struct timeval tv;
gettimeofday(&tv, NULL);
ts[0] = tv.tv_sec + UTC_NTP;
ts[1] = (4294*(tv.tv_usec)) + ((1981*(tv.tv_usec))>>11);
}
int die(const char *msg)
{
if (msg) {
fputs(msg, stderr);
}
exit(-1);
}
void log_request_arrive(uint32_t *ntp_time)
{
time_t t;
if (ntp_time) {
t = *ntp_time - UTC_NTP;
} else {
t = time(NULL);
}
printf("A request comes at: %s", ctime(&t));
}
void log_ntp_event(char *msg)
{
puts(msg);
}
//应答client
int ntp_reply(
int socket_fd,
struct sockaddr *saddr_p,
socklen_t saddrlen,
unsigned char recv_buf[],
uint32_t recv_time[])
{
/* Assume that recv_time is in local endian ! */
unsigned char send_buf[48];
uint32_t *u32p;
/* do not use 0xC7 because the LI=11 can be `unsynchronized` */
if ((recv_buf[0] & 0x07/*0xC7*/) != 0x3) {
/* LI VN Mode stimmt nicht */
log_ntp_event("Invalid request: found error at the first byte");
return 1;
}
/* 设置 LI VN Mode 的值
LI = 0
VN = Version Number 同 Client
Mode = 4
*/
send_buf[0] = (recv_buf[0] & 0x38) + 4;
/* Stratum */
send_buf[1] = 0x01;
/* Reference ID = "LOCL" ,即参考时钟源的标识*/
*(uint32_t*)&send_buf[12] = htonl(0x4C4F434C);
/* Copy Poll */
send_buf[2] = recv_buf[2];
/* Precision in Microsecond ( from API gettimeofday() ) */
send_buf[3] = (signed char)(-6); /* 2^(-6) sec */
u32p = (uint32_t *)&send_buf[4];
/* 设置Root Delay = 0, Root Dispersion = 0 */
*u32p++ = 0;
*u32p++ = 0;
/* Reference ID前面已经设置*/
u32p++;
/* 设置 Reference TimeStamp */
gettime64(u32p);
*u32p = htonl(*u32p - 60); /* -1 Min.*/
u32p++;
*u32p = htonl(*u32p); /* -1 Min.*/
u32p++;
/* Originate Time = Transmit Time @ Client */
*u32p++ = *(uint32_t *)&recv_buf[40];
*u32p++ = *(uint32_t *)&recv_buf[44];
/* Receive Time @ Server */
*u32p++ = htonl(recv_time[0]);
*u32p++ = htonl(recv_time[1]);
/* 设置 Transmit Time*/
gettime64(u32p);
*u32p = htonl(*u32p); /* -1 Min.*/
u32p++;
*u32p = htonl(*u32p); /* -1 Min.*/
if ( sendto( socket_fd,
send_buf,
sizeof(send_buf), 0,
saddr_p, saddrlen)
< 48) {
perror("sendto error");
return 1;
}
return 0;
}
void request_process_loop(int fd)
{
struct sockaddr src_addr;
socklen_t src_addrlen = sizeof(src_addr);
unsigned char buf[48];
uint32_t recv_time[2];
pid_t pid;
while (1) {
while (recvfrom(fd, buf,
48, 0,
&src_addr,
&src_addrlen)
< 48 ); /* invalid request */
gettime64(recv_time);
/* recv_time in local endian */
log_request_arrive(recv_time);
pid = fork();
if (pid == 0) {
/* Child */
ntp_reply(fd, &src_addr , src_addrlen, buf, recv_time);
exit(0);
} else if (pid == -1) {
perror("fork() error");
die(NULL);
}
/* return to parent */
}
}
void ntp_server()
{
int s;
struct sockaddr_in sinaddr;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("Can not create socket.");
die(NULL);
}
memset(&sinaddr, 0, sizeof(sinaddr));
sinaddr.sin_family = AF_INET;
//NTP基于UDP报文传输使用的UDP端口号为123
sinaddr.sin_port = htons(123);
sinaddr.sin_addr.s_addr = INADDR_ANY;
if (0 != bind(s, (struct sockaddr *)&sinaddr, sizeof(sinaddr))) {
perror("Bind error");
die(NULL);
}
log_ntp_event( "\n========================================\n"
"= Server started, waiting for requests =\n"
"========================================\n");
request_process_loop(s);
close(s);
}
void wait_wrapper()
{
int s;
wait(&s);
}
int main(int argc, char *argv[], char **env)
{
signal(SIGCHLD,wait_wrapper);
ntp_server();
return 0;
}