/* Synchronize the time periodically. */ /* Copyright (C) 2003-2004 imacat. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ���v�Ҧ� (c) 2003-2004 �̺��ߡC ���{���O�ۥѳn��A�z�i�H���Ӧۥѳn�����|�] Free Software Foundation �^�X���� GNU �q�Τ��@�\�i�ұ��ڡ] GNU General Public License �^�ĤG�� �ӭק�M���s�o�G�o�@�{���A�Ϊ̦ۥѿ�ܨϥΥ����s�������C �o�G�o�@�{�����ت��O�Ʊ楦���ΡA���S�������O�C�ƦܨS���A�X�S�w�ت� �����t����O�C��ԲӪ����p�аѾ\ GNU �q�Τ��@�\�i�ҡC �z���Ӥw�g�M�{���@�_����@�� GNU �q�Τ��@�\�i�Ҫ��ƥ��C�p�G�٨S���A�g �H���G Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Filename: synctime.c Description: Synchronize the time periodically Author: imacat <imacat@mail.imacat.idv.tw> Date: 2003-12-22 Copyright: (c) 2003 imacat */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Headers */ #include <arpa/inet.h> #include <errno.h> #include <getopt.h> #include <netdb.h> #include <netinet/in.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <syslog.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <time.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/atm.h> #include <net/if.h> /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #include <rtk/options.h> /*ping_zhang:20081217 END*/ extern int h_errno; #ifdef EMBED #include "../../config/autoconf.h" #endif /* Configuration */ #define AUTHOR "Realtek" #define AUTHORMAIL "imacat@mail.imacat.idv.tw" #define EXEC_USER "root" #define PIDDIR "/var/run" #define DEFAULT_INTERVAL 900 #define MAX_NETWORK_ERROR 1200 #define SNTP_PORT 123 #define VERSION "1.0" // Commented by Mason Yu #if 0 #define VERSTR "\ %s v%s, Copyright (C) 2003-2004 %s\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ \n" #endif #define VERSTR "\ %s v%s, Copyright (C) 2004-2005 %s\n\ \n" #define LONGHELP "\ Usage: %s [-i n] [-d ifname] [-p file] server\n\ Synchronize the system time against a time server periodically. It\n\ uses RFC 1361 SNTP service UDP port 123 to synchronize the time. You\n\ may need to be root to synchronize the system time.\n\ \n\ -i,--interval n Set the synchronization interval to n seconds. (%d)\n\ -d,--device ifname Set the interface name used to synchronize. (%s)\n\ -p,--pidfile file The PID file location. (%s)\n\ -h,--help Display this help.\n\ -v,--version Display version information.\n\ server Time server to synchronize against.\n\ \n" #define EXIT_OK 0 #define EXIT_ARGERR 1 #define EXIT_NETERR 2 #define EXIT_SYSERR 127 #define EPOCH_DIFF ((unsigned long) 86400 * (365 * 70 + 17)) #define syslog(a,format,argv...) printf(format,##argv) /* Prototypes */ void set_this_file (char *argv0); void parse_args (int argc, char *argv[]); void check_priv (void); void xexit (int status) __attribute__((noreturn)); void verror (int status, char *message, va_list ap) __attribute__((noreturn)); void error (int status, char *message, ...) __attribute__((noreturn, format(printf, 2, 3))); void vwarn (char *message, va_list ap); void warn (char *message, ...) __attribute__((format(printf, 1, 2))); void neterror (int firstsync, time_t errstart, char *message, ...) __attribute__((format(printf, 3, 4))); void sigterm_exit (int signum) __attribute__((noreturn)); void sigusr1(int); void daemonize (void); void makepid (void); void setsigterm (void); // Kaohj -- let user process kick to sync the time void setsigusr1 (void); #if 0 double synctime (void); #else int synctime (void); #endif /*ping_zhang:20081223 START:add to make each ntp server is used.*/ #ifdef SNTP_MULTI_SERVER void init_server_used(void); unsigned int check_server_all_used(void); #endif /*ping_zhang:20081223 END*/ void fork2background (void); void closeall (void); void settime (time_t t); unsigned long fromnetnum (const char *oct); const char *tonetnum (unsigned long num); unsigned long usec2frac (long usec); long frac2usec (unsigned long frac); void *xmalloc (size_t size); char *xstrcpy (const char *src); char *xstrcat (int n, ...); time_t xtime (time_t *t); void xgettimeofday (struct timeval *tv, struct timezone *tz); void xsettimeofday (const struct timeval *tv , const struct timezone *tz); void xchdir (const char *path); pid_t xfork (void); pid_t xsetsid (void); long xsysconf (int name, const char *confname); FILE *xfopen (const char *path, const char *mode); void xfclose (FILE *stream); int xfprintf (FILE *stream, const char *format, ...) __attribute__((format(printf, 2, 3))); /* Variables */ char *this_file = NULL, *pidfile = NULL; #ifdef CONFIG_BOA_WEB_E8B_CH #define SNTP_MULTI_SERVER #endif #ifdef SNTP_MULTI_SERVER #define MAX_MUTLI_SERVER_NUM 2 char *server_name[MAX_MUTLI_SERVER_NUM] = {0}; /*ping_zhang:20081223 START:add to make each ntp server is used.*/ unsigned int server_used[MAX_MUTLI_SERVER_NUM] = {0}; /*ping_zhang:20081223 END*/ int udp; #else char *server_name = NULL; #endif int interval = -1, daemonized = 0; char *interface = NULL; struct sockaddr_in server; /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ enum eTStatus { eTStatusDisabled, eTStatusUnsynchronized, eTStatusSynchronized, eTStatusErrorFailed,/*Error_FailedToSynchronize*/ eTStatusError }; #endif /*ping_zhang:20081217 END*/ /* set_this_file: Get the name of this file return: none. */ void set_this_file (char *argv0) { char *p; p = rindex (argv0, '/'); if (p == NULL) this_file = xstrcpy (argv0); else this_file = xstrcpy (++p); return; } // Kaohj // Return: 0 -> fail // 1 -> successful #ifdef SNTP_MULTI_SERVER static int get_server(const char* servername) #else static int get_server() #endif { int r; struct in_addr server_addr; struct hostent *server_hostent; #if 0 void *p; size_t len; #endif #ifdef SNTP_MULTI_SERVER r = inet_aton (servername, &server_addr); if (r == 0) { /* Try DNS look up */ server_hostent = gethostbyname (servername); if (server_hostent == NULL) { //error (EXIT_ARGERR, "%s: %s.", server_name, hstrerror (h_errno)); printf ("%s: %s.", servername, hstrerror (h_errno)); return 0; } /* Obtain the IP number, reverse the byte order */ #if 0 server_addr.s_addr = ((server_hostent->h_addr_list[0][3] << 24) & 0xFF000000) | ((server_hostent->h_addr_list[0][2] << 16) & 0x00FF0000) | ((server_hostent->h_addr_list[0][1] << 8) & 0x0000FF00) | (server_hostent->h_addr_list[0][0] & 0x000000FF); #endif server_addr.s_addr = *((unsigned long *)server_hostent->h_addr); #if 0 /* Modify the server name for logging */ len = strlen (servername) + 20; p = (void *) servername; servername = (char *) xmalloc (len); snprintf ((char *)servername, len, "%s (%hhu.%hhu.%hhu.%hhu)", (char *) p, server_hostent->h_addr_list[0][0], server_hostent->h_addr_list[0][1], server_hostent->h_addr_list[0][2], server_hostent->h_addr_list[0][3]); free (p); #endif } #else r = inet_aton (server_name, &server_addr); if (r == 0) { /* Try DNS look up */ server_hostent = gethostbyname (server_name); if (server_hostent == NULL) { //error (EXIT_ARGERR, "%s: %s.", server_name, hstrerror (h_errno)); printf ("%s: %s.", server_name, hstrerror (h_errno)); return 0; } /* Obtain the IP number, reverse the byte order */ #if 0 server_addr.s_addr = ((server_hostent->h_addr_list[0][3] << 24) & 0xFF000000) | ((server_hostent->h_addr_list[0][2] << 16) & 0x00FF0000) | ((server_hostent->h_addr_list[0][1] << 8) & 0x0000FF00) | (server_hostent->h_addr_list[0][0] & 0x000000FF); #endif server_addr.s_addr = *((unsigned long *)server_hostent->h_addr); /* Modify the server name for logging */ #if 0 len = strlen (server_name) + 20; p = (void *) server_name; server_name = (char *) xmalloc (len); snprintf (server_name, len, "%s (%hhu.%hhu.%hhu.%hhu)", (char *) p, server_hostent->h_addr_list[0][0], server_hostent->h_addr_list[0][1], server_hostent->h_addr_list[0][2], server_hostent->h_addr_list[0][3]); free (p); #endif } #endif /* Save the server infomation */ server.sin_family = AF_INET; server.sin_addr = server_addr; server.sin_port = htons (SNTP_PORT); return 1; } /* parse_args: Parse the arguments. return: none. */ void parse_args (int argc, char *argv[]) { static struct option longopts[] = { {"interval", 1, NULL, 'i'}, {"device", 1, NULL, 'd'}, {"pidfile", 1, NULL, 'p'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'v'}, #ifdef SNTP_MULTI_SERVER {"server",1,NULL,'s'}, #endif {0, 0, 0, 0} }; int i, r, c, c0, longindex = 0; // Kaohj #if 0 struct in_addr server_addr; struct hostent *server_hostent; void *p; size_t len; #endif /* Set the default value */ interval = DEFAULT_INTERVAL; interface = NULL; pidfile = xstrcat (4, PIDDIR, "/", this_file, ".pid"); while (1) { #ifdef SNTP_MULTI_SERVER c = getopt_long (argc, argv, "i:d:p:s:hv", longopts, &longindex); #else c = getopt_long (argc, argv, "i:d:p:hv", longopts, &longindex); #endif if (c == -1) break; switch (c) { case 'i': r = sscanf (optarg, "%5d%c", &interval, &c0); if (r != 1 || interval <= 0) error (EXIT_ARGERR, "invalid interval: %s.", optarg); break; case 'd': if(interface) free(interface); interface = xstrcpy (optarg); break; case 'p': if (pidfile != NULL) free (pidfile); pidfile = xstrcpy (optarg); break; case 'h': printf (LONGHELP, this_file, interval, pidfile); exit (EXIT_OK); case 'v': // Commened by Mason Yu printf (VERSTR, this_file, VERSION, AUTHOR); exit (EXIT_OK); #ifdef SNTP_MULTI_SERVER case 's': for(i=0;i<MAX_MUTLI_SERVER_NUM;i++) { if(!server_name[i]) { server_name[i]= xstrcpy (optarg); break; } } break; #endif default: exit (EXIT_ARGERR); } } #ifndef SNTP_MULTI_SERVER /* Process each argument */ for (i = optind; i < argc; i++) switch (i - optind) { case 0: server_name = xstrcpy (argv[i]); break; default: error (EXIT_ARGERR, "Too many argument: %s.", argv[i]); } #endif /* Process the interval */ if (interval == -1) interval = DEFAULT_INTERVAL; /* Process the PID file */ /* Compose the default PID file path */ if (pidfile == NULL) pidfile = xstrcat (4, PIDDIR, "/", this_file, ".pid"); // Mason Yu. Kill process in real time. /* Make the PID file */ //makepid (); #ifndef SNTP_MULTI_SERVER /* Process the time server */ if (server_name == NULL) error (EXIT_ARGERR, "Please specify the time server."); // Kaohj r = get_server(); #endif #if 0 r = inet_aton (server_name, &server_addr); if (r == 0) { /* Try DNS look up */ server_hostent = gethostbyname (server_name); if (server_hostent == NULL) { //error (EXIT_ARGERR, "%s: %s.", server_name, hstrerror (h_errno)); printf ("%s: %s.", server_name, hstrerror (h_errno)); return; } /* Obtain the IP number, reverse the byte order */ // Kaohj #if 0 server_addr.s_addr = ((server_hostent->h_addr_list[0][3] << 24) & 0xFF000000) | ((server_hostent->h_addr_list[0][2] << 16) & 0x00FF0000) | ((server_hostent->h_addr_list[0][1] << 8) & 0x0000FF00) | (server_hostent->h_addr_list[0][0] & 0x000000FF); #endif server_addr.s_addr = *((unsigned long *)server_hostent->h_addr); /* Modify the server name for logging */ len = strlen (server_name) + 20; p = (void *) server_name; server_name = (char *) xmalloc (len); snprintf (server_name, len, "%s (%hhu.%hhu.%hhu.%hhu)", (char *) p, server_hostent->h_addr_list[0][0], server_hostent->h_addr_list[0][1], server_hostent->h_addr_list[0][2], server_hostent->h_addr_list[0][3]); free (p); } /* Save the server infomation */ server.sin_family = AF_INET; server.sin_addr = server_addr; server.sin_port = htons (SNTP_PORT); #endif return; } /* xexit: Properly handle the exit. return: none. */ void xexit (int status) { int r; /* Proper exit in daemon mode */ if (daemonized) { /* Remove the PID file */ r = unlink (pidfile); if (r == -1) syslog (LOG_ERR, "unlink %s: %s at %s line %d.", pidfile, strerror (errno), __FILE__, __LINE__); /* Close the syslog */ closelog (); } // Mason Yu. Kill process in real time. if(pidfile) { unlink(pidfile); } // free memory #ifdef SNTP_MULTI_SERVER for(r=0; r<MAX_MUTLI_SERVER_NUM; r++) { if(server_name[r]) free(server_name[r]); } #else if (server_name) free(server_name); #endif exit (status); } /* verror: Issue an error with variable argument list */ void verror (int status, char *message, va_list ap) { /* Issue the error message */ if (daemonized) { vsyslog (LOG_ERR, message, ap); syslog (LOG_ERR, "Exited upon unrecoverable network error."); } else { vfprintf (stderr, message, ap); fprintf (stderr, "\n"); } xexit (status); } /* error: Issue an error */ void error (int status, char *message, ...) { va_list ap; /* Handle errors with verror */ va_start (ap, message); verror (status, message, ap); va_end (ap); /* No return */ } /* vwarn: Issue a warning with variable argument list */ void vwarn (char *message, va_list ap) { /* Issue the warning message */ if (daemonized) vsyslog (LOG_WARNING, message, ap); else vfprintf (stderr, message, ap); return; } /* warn: Issue a warning */ void warn (char *message, ...) { va_list ap; /* Handle warnings with vwarn */ va_start (ap, message); vwarn (message, ap); va_end (ap); return; } /* neterror: Issue a network error */ void neterror (int firstsync, time_t errstart, char *message, ...) { va_list ap; time_t now; va_start (ap, message); /* Don't pass it if we can't even synchronize the first time */ if (firstsync) verror (EXIT_NETERR, message, ap); /* Warn it */ vwarn (message, ap); now = xtime (NULL); /* First error */ if (errstart == 0) errstart = now; /* Errors lasted for too long */ else if (now - errstart > MAX_NETWORK_ERROR) error (EXIT_NETERR, "Exited upon network error exceeding %d seconds.", MAX_NETWORK_ERROR); return; } /* sigterm: End the program */ void sigterm_exit (int signum) { /* Log the exit */ syslog (LOG_INFO, "Exited upon TERM signal.\n"); // Mason Yu. Kill process in real time. //jim remove pid file #if 0 if(pidfile) { unlink(pidfile); } printf("%s: %s removed.\n", __FUNCTION__, pidfile); #endif /* Exit normally */ xexit (EXIT_OK); } void sigusr1(int dummy) { syslog(LOG_INFO, "vsntp: Kicked to wake-up by SIGUSR1\n"); } /* daemonize: Daemonize the process */ /* http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 */ void daemonize (void) { /* Fork to be a new process group leader */ fork2background (); /* Become a new session group leader, to get rid of the controlling terminal */ xsetsid (); /* Fork again to get rid of this new session */ fork2background (); /* chdir to "/", to avoid staying on any mounted file system */ xchdir ("/"); /* Avoid inheriting umasks */ umask (0); /* Close all opened file descriptors */ closeall (); /* Set the flag */ daemonized = 1; /* Start the syslog */ openlog (this_file, LOG_PID, LOG_DAEMON); /* Log the start */ syslog (LOG_INFO, "Start synchronization with %s.", server_name); return; } /* makepid: Make the PID file */ void makepid (void) { pid_t pid; FILE *fp; int skfd; struct atmif_sioc mysio; // Mason Yu. Kill process in real time. int pid_old; FILE *fp2; /* Record the PID */ pid = getpid (); #ifdef CONFIG_DEV_xDSL if((skfd = socket(PF_ATMPVC, SOCK_DGRAM, 0)) < 0){ perror("socket open error"); //exit(1); } else { mysio.number = 0; mysio.length = sizeof(struct SAR_IOCTL_CFG); mysio.arg = (void *)&pid; ioctl(skfd, SENT_SNTP_PID, &mysio); close(skfd); } #endif // Mason Yu. Kill process in real time. fp2 = fopen(pidfile, "r"); if ( fp2 != NULL ) { fscanf(fp2, "%d", &pid_old); //printf("Kill old vsntp process\n"); kill(pid_old, SIGTERM); unlink(pidfile); fclose(fp2); // wait until old process exit ... sleep(1); } /* Save to the file */ fp = xfopen (pidfile, "w"); xfprintf (fp, "%d\n", pid); xfclose (fp); return; } /* setsigterm: Configure the way we exit */ void setsigterm (void) { struct sigaction action; // Mason Yu. Kill process in real time. action.sa_flags = 0; /* Set the TERM signal handler */ action.sa_handler = sigterm_exit; /* Block further signals */ sigemptyset (&action.sa_mask); // Mason Yu. Kill process in real time. sigaddset(&action.sa_mask, SIGTERM); /* Set the TERM signal handler */ sigaction (SIGTERM, &action, NULL); return; } /* setsigusr1: Configure the way that user process can request to sync the time */ void setsigusr1 (void) { struct sigaction sa; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGUSR1); sa.sa_handler = sigusr1; sigaction(SIGUSR1, &sa, NULL); } #ifdef SNTP_MULTI_SERVER int try_server_valid() { fprintf(stderr,"%s\n",__FUNCTION__); int i,r; struct ifreq req; for(i=0;i<MAX_MUTLI_SERVER_NUM;i++) { if(!server_name[i]) continue; if(server_used[i]) continue; /*ping_zhang:20081223 add to check whether the ntp_server[i] has been tried.*/ server_used[i]=1; /*ping_zhang:20081223 mark the ntp_server[i] has been tried.*/ if(!get_server(server_name[i])) continue; /* Create the UDP socket */ udp = socket (PF_INET, SOCK_DGRAM, 0); if(interface) { strncpy(req.ifr_ifrn.ifrn_name, interface, 16); if (setsockopt(udp, SOL_SOCKET, SO_BINDTODEVICE,(char *)&req, sizeof(req)) < 0) { close(udp); warn ("Bind to interface error: %s.", strerror(errno)); } } /* Initialize the connection */ r = connect (udp, (struct sockaddr*) &server, sizeof (server)); if (r < 0) { // Kaohj printf("connect %s: %s\n", server_name[i], strerror (errno)); /* neterror (firstsync, errstart, "connect %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); */ /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); udp=0; } else { break; } } return udp; } /*ping_zhang:20081223 START:add to make each ntp server is used.*/ void init_server_used(void) { int i; for(i=0; i<MAX_MUTLI_SERVER_NUM; i++) { if(server_name[i]) server_used[i] = 0; /*useable and unused*/ else server_used[i] = 2; /*unuseable*/ } return; } /*check if all server are tried return 0: yes 1: no*/ unsigned int check_server_all_used(void) { int i; for(i=0; i<MAX_MUTLI_SERVER_NUM; i++) { if(server_used[i]==0) return 1; } return 0; } /*ping_zhang:20081223 END*/ #endif #if 0 /* synctime: Synchronize the time. See RFC 1361. return: Time offset that is synchronized.*/ double synctime (void) { int i, r, udp; static int firstsync = 1; char buf[61]; ssize_t len; static time_t errstart = 0; static struct timeval tv1, tv2, tv3, tv4, tvnew; struct timezone tz; double t1, t2, t3, t4, toff, tnew; /* Create the UDP socket */ udp = socket (PF_INET, SOCK_DGRAM, 0); /* Initialize the connection */ r = connect (udp, (struct sockaddr*) &server, sizeof (server)); if (r == -1) { neterror (firstsync, errstart, "connect %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return 0; } /* Send to the server */ /* Pad zeroes */ for (i = 0; i < 61; i++) buf[i] = 0; /* 00 001 011 - leap, ntp ver, client. See RFC 1361. */ buf[0] = (0 << 6) | (1 << 3) | 3; /* Get the local sent time - Originate Timestamp */ xgettimeofday (&tv1, &tz); t1 = (double) tv1.tv_sec + (double) tv1.tv_usec / 1000000; /* Send to the server */ memcpy (&buf[40], tonetnum ((unsigned long) tv1.tv_sec + EPOCH_DIFF), 4); memcpy (&buf[44], tonetnum (usec2frac (tv1.tv_usec)), 4); len = send (udp, buf, 48, 0); if (len == -1) { neterror (firstsync, errstart, "send %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return 0; } /* Read from the server */ len = recv (udp, &buf, 60, 0); if (len == -1) { neterror (firstsync, errstart, "recv %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return 0; } /* Close the socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); /* Get the local received time */ xgettimeofday (&tv4, &tz); t4 = (double) tv4.tv_sec + (double) tv4.tv_usec / 1000000; /* Get the remote Receive Timestamp */ tv2.tv_sec = fromnetnum (&buf[32]) - EPOCH_DIFF; tv2.tv_usec = frac2usec (fromnetnum (&buf[36])); t2 = (double) tv2.tv_sec + (double) tv2.tv_usec / 1000000; /* Get the remote Transmit Timestamp */ tv3.tv_sec = fromnetnum (&buf[40]) - EPOCH_DIFF; tv3.tv_usec = frac2usec (fromnetnum (&buf[44])); t3 = (double) tv3.tv_sec + (double) tv3.tv_usec / 1000000; /* Calculate the time offset */ toff = (t2 + t3 - t1 - t4) / 2; /* Calculate the new time */ tnew = t4 + toff; tvnew.tv_usec = (long long) (tnew * 1000000) % 1000000; tvnew.tv_sec = ((long long) (tnew * 1000000) - tvnew.tv_usec) / 1000000; /* Set the time */ // Mason Yu //tz.tz_minuteswest = 480; //tz.tz_dsttime = 0; //const struct timezone tzz = { 28800, 0 }; //xsettimeofday (&tvnew, &tzz); //tvnew.tv_sec += 8*60*60; // Taiwan xsettimeofday (&tvnew, &tz); /* Re-initialize the error timer */ errstart = 0; /* Remove the first time flag */ firstsync = 0; return toff; } #else int synctime (void) { #ifdef SNTP_MULTI_SERVER int i, r; #else int i, r, udp; #endif static int firstsync = 1; char buf[61]; ssize_t len; static time_t errstart = 0; static struct timeval tv1, tv2, tv3, tv4, tvnew; struct timezone tz; unsigned long t1, t2, t3, t4, toff, tnew; // Kaohj fd_set rfd; struct timeval to; int loop; FILE *fp; struct ifreq req; #ifdef SNTP_MULTI_SERVER try_next_server: if(!udp&&!try_server_valid()) { /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusErrorFailed); fclose(fp); } #endif /*ping_zhang:20081217 END*/ /*ping_zhang:20081223 START:check if each ntp server is tried.*/ if(check_server_all_used()==1) { udp=0; goto try_next_server; } /*ping_zhang:20081223 END*/ return 0; } #else // Kaohj if (server.sin_family == 0) { if (!get_server()) return 0; } /* Create the UDP socket */ udp = socket (PF_INET, SOCK_DGRAM, 0); if(interface) { strncpy(req.ifr_ifrn.ifrn_name, interface, 16); if (setsockopt(udp, SOL_SOCKET, SO_BINDTODEVICE,(char *)&req, sizeof(req)) < 0) { close(udp); warn ("Bind to interface error: %s.", strerror(errno)); } } /* Initialize the connection */ r = connect (udp, (struct sockaddr*) &server, sizeof (server)); if (r == -1) { /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusErrorFailed); fclose(fp); } #endif /*ping_zhang:20081217 END*/ // Kaohj printf("connect %s: %s\n", server_name, strerror (errno)); /* neterror (firstsync, errstart, "connect %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); */ /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return 0; } #endif // Kaohj loop = 0; retry: /* Send to the server */ /* Pad zeroes */ for (i = 0; i < 61; i++) buf[i] = 0; /* 00 001 011 - leap, ntp ver, client. See RFC 1361. */ buf[0] = (0 << 6) | (1 << 3) | 3; /* Get the local sent time - Originate Timestamp */ xgettimeofday (&tv1, &tz); // Kaohj //t1 = (double) tv1.tv_sec + (double) tv1.tv_usec / 1000000; t1 = tv1.tv_sec + tv1.tv_usec / 1000000; //printf("tv1: %d, %d, t1=%d\n", (unsigned long)tv1.tv_sec, (unsigned long)tv1.tv_usec, t1); /* Send to the server */ memcpy (&buf[40], tonetnum ((unsigned long) tv1.tv_sec + EPOCH_DIFF), 4); memcpy (&buf[44], tonetnum (usec2frac (tv1.tv_usec)), 4); len = send (udp, buf, 48, 0); if (len < 0) { /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusErrorFailed); fclose(fp); } #endif /*ping_zhang:20081217 END*/ if (errno != EINTR) printf("send %s: %s at %s line %d.\n", server_name, strerror (errno), __FILE__, __LINE__); /* neterror (firstsync, errstart, "send %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); */ /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); /*ping_zhang:20081223 START:check if each ntp server is tried.*/ #ifdef SNTP_MULTI_SERVER if(check_server_all_used()==1) { udp=0; goto try_next_server; } #endif /*ping_zhang:20081223*/ return 0; } /* Read from the server */ // kaohj -- retry if necessary to.tv_sec = 1; to.tv_usec = 0; FD_ZERO(&rfd); FD_SET(udp, &rfd); if ((select(udp+1, &rfd, NULL, NULL, &to)) > 0) { len = recv (udp, &buf, 60, 0); } else { loop++; if (loop <= 5) goto retry; /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusErrorFailed); fclose(fp); } #endif /*ping_zhang:20081217 END*/ close (udp); /*ping_zhang:20081223 START:check if each ntp server is tried.*/ #ifdef SNTP_MULTI_SERVER if(check_server_all_used()==1) { udp=0; goto try_next_server; } #endif /*ping_zhang:20081223 END*/ return 0; } if (len < 0) { /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusErrorFailed); fclose(fp); } #endif /*ping_zhang:20081217 END*/ if (errno != EINTR) printf("recv %s: %s at %s line %d.\n", server_name, strerror (errno), __FILE__, __LINE__); /* neterror (firstsync, errstart, "recv %s: %s at %s line %d.", server_name, strerror (errno), __FILE__, __LINE__); */ /* Close the opened socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); /*ping_zhang:20081223 START:check if each ntp server is tried.*/ #ifdef SNTP_MULTI_SERVER if(check_server_all_used()==1) { udp=0; goto try_next_server; } #endif /*ping_zhang:20081223 END*/ return 0; } /* Close the socket */ r = close (udp); if (r != 0) warn ("close udp: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); /* Get the local received time */ xgettimeofday (&tv4, &tz); // Kaohj //t4 = (double) tv4.tv_sec + (double) tv4.tv_usec / 1000000; t4 = tv4.tv_sec + tv4.tv_usec / 1000000; //printf("tv4: %d, %d, t4=%d\n", (unsigned long)tv4.tv_sec, (unsigned long)tv4.tv_usec, t4); /* Get the remote Receive Timestamp */ tv2.tv_sec = fromnetnum (&buf[32]) - EPOCH_DIFF; tv2.tv_usec = frac2usec (fromnetnum (&buf[36])); // Kaohj //t2 = (double) tv2.tv_sec + (double) tv2.tv_usec / 1000000; t2 = tv2.tv_sec + tv2.tv_usec / 1000000; //printf("tv2: %d, %d, t2=%d\n", tv2.tv_sec, tv2.tv_usec, t2); /* Get the remote Transmit Timestamp */ tv3.tv_sec = fromnetnum (&buf[40]) - EPOCH_DIFF; tv3.tv_usec = frac2usec (fromnetnum (&buf[44])); // Kaohj //t3 = (double) tv3.tv_sec + (double) tv3.tv_usec / 1000000; t3 = tv3.tv_sec + tv3.tv_usec / 1000000; //printf("tv3: %d, %d, t3=%d\n", tv3.tv_sec, tv3.tv_usec, t3); /* Calculate the time offset */ toff = (t2 + t3 - t1 - t4) / 2; /* Calculate the new time */ // Kaohj //tnew = t4 + toff; tnew = (t2 + t3 - t1 + t4) / 2; //printf("toff=%d, tnew=%d\n", toff, tnew); //tvnew.tv_usec = (long long) (tnew * 1000000) % 1000000; tvnew.tv_usec = 0; // Kaohj //tvnew.tv_sec = ((long long) (tnew * 1000000) - tvnew.tv_usec) / 1000000; tvnew.tv_sec = tnew; //printf("tvnew: %d, %d\n", tvnew.tv_sec, tvnew.tv_usec); /* Set the time */ xsettimeofday (&tvnew, &tz); /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusSynchronized); fclose(fp); } #endif /*ping_zhang:20081217 END*/ /* Re-initialize the error timer */ errstart = 0; /* Remove the first time flag */ firstsync = 0; return toff; } #endif /* fork2background: Fork to the background. return: none. */ void fork2background (void) { pid_t pid; /* Fork */ pid = xfork (); /* Exit the parent process */ if (pid != 0) exit (0); return; } /* closeall: Close all the opened file descriptors, especially: stdin, stdout and stderr. return: none. */ void closeall (void) { int i; long openmax; openmax = xsysconf (_SC_OPEN_MAX, "_SC_OPEN_MAX"); for (i = 0; i < openmax; i++) close (i); return; } /* fromnetnum: Convert from a network number to a C number. return: the number in unsigned long. */ unsigned long fromnetnum (const char *oct) { return ((unsigned char) oct[0] << 24 | (unsigned char) oct[1] << 16 | (unsigned char) oct[2] << 8 | (unsigned char) oct[3]); } /* tonetnum: Convert from a C number to a network number. return: the number in network octet. */ const char *tonetnum (unsigned long num) { static char oct[5] = "0000"; oct[0] = (num >> 24) & 255; oct[1] = (num >> 16) & 255; oct[2] = (num >> 8) & 255; oct[3] = num & 255; return oct; } /* usec2frac: Convert from microsecond to fraction of a second. return: Fraction of a second. */ unsigned long usec2frac (long usec) { return (unsigned long) (((long long) usec << 32) / 1000000); } /* usec2frac: Convert from fraction of a second to microsecond return: microsecond. */ long frac2usec (unsigned long frac) { return (long) (((long long) frac * 1000000) >> 32); } /* xstrcpy: allocate enough memory, make a copy of the string, and handle errors. return: pointer to the destination string. */ char * xstrcpy (const char *src) { char *dest; dest = (char *) xmalloc (strlen (src) + 1); strcpy (dest, src); return dest; } /* xstrcat: allocate enough memory, concatenate the strings, and handle errors. return: pointer to the destination string. */ char * xstrcat (int n, ...) { int i; size_t len; va_list ap; char *s; /* Calculate the result size */ va_start (ap, n); for (i = 0, len = 0; i < n; i++) len += strlen (va_arg (ap, char *)); va_end (ap); /* Allocate the memory */ s = (char *) xmalloc (len + 1); /* Concatenate the strings */ va_start (ap, n); strcpy (s, va_arg (ap, char *)); for (i = 1; i < n; i++) strcat (s, va_arg (ap, char *)); va_end (ap); return s; } /* xmalloc: malloc() and handle errors. return: pointer to the allocated memory block. */ void * xmalloc (size_t size) { void *ptr; ptr = malloc (size); if (ptr == NULL) error (EXIT_SYSERR, "malloc: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return ptr; } /* xtime: time() and handle errors. return: current time. */ time_t xtime (time_t *t) { time_t r; r = time (t); if (r == -1) error (EXIT_SYSERR, "time: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return r; } /* xgettimeofday: gettimeofday() and handle errors. return: none. */ void xgettimeofday (struct timeval *tv, struct timezone *tz) { int r; r = gettimeofday (tv, tz); if (r == -1) error (EXIT_SYSERR, "gettimeofday: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return; } /* xsettimeofday: settimeofday() and handle errors. return: none. */ void xsettimeofday (const struct timeval *tv , const struct timezone *tz) { int r; r = settimeofday (tv, tz); if (r == -1) error (EXIT_SYSERR, "settimeofday: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return; } /* xchdir: chdir() and handle errors. return: none. */ void xchdir (const char *path) { int r; r = chdir (path); if (r == -1) error (EXIT_SYSERR, "chdir %s: %s at %s line %d.", path, strerror (errno), __FILE__, __LINE__); return; } /* xfork: fork() and handle errors. return: none. */ pid_t xfork (void) { pid_t pid; pid = fork (); if (pid == -1) error (EXIT_SYSERR, "fork: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return pid; } /* xsetsid: setsid() and handle errors. return: none. */ pid_t xsetsid (void) { pid_t pid; pid = setsid (); if (pid == -1) error (EXIT_SYSERR, "setsid: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return pid; } /* xsysconf: sysconf() and handle errors. return: none. */ long xsysconf (int name, const char *confname) { long r; r = sysconf (name); if (r == -1) error (EXIT_SYSERR, "sysconf %s: %s at %s line %d.", confname, strerror (errno), __FILE__, __LINE__); return r; } /* xfopen: fopen() and handle errors. return: file handler pointer. */ FILE * xfopen (const char *path, const char *mode) { FILE *fp; fp = fopen (path, mode); if (fp == NULL) error (EXIT_SYSERR, "fopen %s: %s at %s line %d.", path, strerror (errno), __FILE__, __LINE__); return fp; } /* xfclose: fclose() and handle errors. return: none. */ void xfclose (FILE *stream) { int r; r = fclose (stream); if (r == EOF) error (EXIT_SYSERR, "fclose: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return; } /* xfprintf: fprintf() and handle errors. return: length print so far. */ int xfprintf (FILE *stream, const char *format, ...) { int len; va_list ap; va_start (ap, format); len = vfprintf (stream, format, ap); va_end (ap); if (len < 0) error (EXIT_SYSERR, "vfprintf: %s at %s line %d.", strerror (errno), __FILE__, __LINE__); return len; } /* Main program */ int main (int argc, char *argv[]) { time_t now, next; unsigned int wait, ret; // Kaohj //double toff; int toff; /*ping_zhang:20081217 START:patch from telefonica branch to support WT-107*/ #ifdef _PRMT_WT107_ FILE *fp; fp=fopen("/tmp/timeStatus","w"); if(fp){ fprintf(fp,"%d",eTStatusUnsynchronized); fclose(fp); } #endif /*ping_zhang:20081217 END*/ /* Find this file's name */ set_this_file (argv[0]); parse_args (argc, argv); /* Synchronize for the first time, to ensure no obvious network errors */ /*ping_zhang:20081223 START:add to make each ntp server is used.*/ #ifdef SNTP_MULTI_SERVER udp=0; init_server_used(); #endif /*ping_zhang:20081223 END*/ toff = synctime (); /* Daemonize */ // Kaohj //daemonize (); /*ping_zhang:20081223 START:remove makepid() from parse_args() to avoid vsntp can't start up.*/ makepid(); /*ping_zhang:20081223 END*/ /* Set the way we exit */ setsigterm (); setsigusr1 (); /* Report the first synchronization */ // Kaohj //syslog (LOG_INFO, "Time adjusted %.6f seconds.", toff); //syslog (LOG_INFO, "Time adjusted %.6d seconds.", toff); /* Calculate the next time to synchronize */ now = xtime (NULL); wait = interval - (now % interval); next = now + wait; /* Wait until that time */ sleep (wait); /* Enter endless loop of synchronization */ while (1) { /*ping_zhang:20081223 START:add to make each ntp server is used.*/ #ifdef SNTP_MULTI_SERVER udp=0; init_server_used(); #endif /*ping_zhang:20081223 END*/ /* Synchronize the time */ synctime (); now = xtime (NULL); /* Find the next time line */ do next += interval; while (next <= now); wait = next - now; /* Wait until that time */ ret = sleep (wait); if (ret != 0) sleep(10); // interrupted by SIGUSR1, wait for interface up } return 0; }