📄 ntpdate.c
字号:
/* * Whew! What we should have by now is 0 to 5 candidates for * the job of syncing us. If we have none, we're out of luck. * If we have one, he's a winner. If we have more, do falseticker * detection. */ if (nlist == 0) sys_server = 0; else if (nlist == 1) { sys_server = server_list[0]; } else { /* * Re-sort by stratum, bdelay estimate quality and * server.delay. */ for (i = 0; i < nlist-1; i++) for (j = i+1; j < nlist; j++) { if (server_list[i]->stratum < server_list[j]->stratum) break; /* already sorted by stratum */ if (server_list[i]->delay < server_list[j]->delay) continue; server = server_list[i]; server_list[i] = server_list[j]; server_list[j] = server; } /* * Calculate the fixed part of the dispersion limit */ local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + NTP_MAXSKW; /* * Now drop samples until we're down to one. */ while (nlist > 1) { for (n = 0; n < nlist; n++) { server_badness[n] = 0; for (j = 0; j < nlist; j++) { if (j == n) /* with self? */ continue; d = server_list[j]->soffset - server_list[n]->soffset; if (d < 0) /* absolute value */ d = -d; /* * XXX This code *knows* that * NTP_SELECT is 3/4 */ for (i = 0; i < j; i++) d = (d>>1) + (d>>2); server_badness[n] += d; } } /* * We now have an array of nlist badness * coefficients. Find the badest. Find * the minimum precision while we're at * it. */ i = 0; n = server_list[0]->precision;; for (j = 1; j < nlist; j++) { if (server_badness[j] >= server_badness[i]) i = j; if (n > server_list[j]->precision) n = server_list[j]->precision; } /* * i is the index of the server with the worst * dispersion. If his dispersion is less than * the threshold, stop now, else delete him and * continue around again. */ if ( (s_fp) server_badness[i] < (local_threshold + (FP_SECOND >> (-n)))) break; for (j = i + 1; j < nlist; j++) server_list[j-1] = server_list[j]; nlist--; } /* * What remains is a list of less than 5 servers. Take * the best. */ sys_server = server_list[0]; } /* * That's it. Return our server. */ return sys_server;}/* * clock_adjust - process what we've received, and adjust the time * if we got anything decent. */static intclock_adjust(void){ register struct server *sp, *server; s_fp absoffset; int dostep; for (sp = sys_servers; sp != NULL; sp = sp->next_server) clock_filter(sp); server = clock_select(); if (debug || simple_query) { for (sp = sys_servers; sp != NULL; sp = sp->next_server) printserver(sp, stdout); } if (server == 0) { msyslog(LOG_ERR, "no server suitable for synchronization found"); return(1); } if (always_step) { dostep = 1; } else if (never_step) { dostep = 0; } else { absoffset = server->soffset; if (absoffset < 0) absoffset = -absoffset; dostep = (absoffset >= NTPDATE_THRESHOLD || absoffset < 0); } if (dostep) { if (simple_query || l_step_systime(&server->offset)) { msyslog(LOG_NOTICE, "step time server %s offset %s sec", stoa(&server->srcadr), lfptoa(&server->offset, 6)); } } else {#if !defined SYS_WINNT && !defined SYS_CYGWIN32 if (simple_query || l_adj_systime(&server->offset)) { msyslog(LOG_NOTICE, "adjust time server %s offset %s sec", stoa(&server->srcadr), lfptoa(&server->offset, 6)); }#else /* The NT SetSystemTimeAdjustment() call achieves slewing by * changing the clock frequency. This means that we cannot specify * it to slew the clock by a definite amount and then stop like * the Unix adjtime() routine. We can technically adjust the clock * frequency, have ntpdate sleep for a while, and then wake * up and reset the clock frequency, but this might cause some * grief if the user attempts to run ntpd immediately after * ntpdate and the socket is in use. */ printf("\nThe -b option is required by ntpdate on Windows NT platforms\n"); exit(1);#endif /* SYS_WINNT */ } return(0);}/* * is_unreachable - check to see if we have a route to given destination * (non-blocking). */static intis_reachable (struct sockaddr_storage *dst){ SOCKET sockfd; sockfd = socket(dst->ss_family, SOCK_DGRAM, 0); if (sockfd == -1) { return 0; } if(connect(sockfd, (struct sockaddr *)dst, SOCKLEN(dst))) { closesocket(sockfd); return 0; } closesocket(sockfd); return 1;}/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c *//* * addserver - determine a server's address and allocate a new structure * for it. */static voidaddserver( char *serv ){ register struct server *server; /* Address infos structure to store result of getaddrinfo */ struct addrinfo *addrResult, *ptr; /* Address infos structure to store hints for getaddrinfo */ struct addrinfo hints; /* Error variable for getaddrinfo */ int error; /* Service name */ char service[5]; strcpy(service, "ntp"); /* Get host address. Looking for UDP datagram connection. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = ai_fam_templ; hints.ai_socktype = SOCK_DGRAM;#ifdef DEBUG if (debug) printf("Looking for host %s and service %s\n", serv, service);#endif error = getaddrinfo(serv, service, &hints, &addrResult); if (error != 0) { fprintf(stderr, "Error : %s\n", gai_strerror(error)); msyslog(LOG_ERR, "can't find host %s\n", serv); return; }#ifdef DEBUG else if (debug) { fprintf(stderr, "host found : %s\n", stohost((struct sockaddr_storage*)addrResult->ai_addr)); }#endif /* We must get all returned server in case the first one fails */ for (ptr = addrResult; ptr != NULL; ptr = ptr->ai_next) { if (is_reachable ((struct sockaddr_storage *)ptr->ai_addr)) { server = (struct server *)emalloc(sizeof(struct server)); memset((char *)server, 0, sizeof(struct server)); memset(&(server->srcadr), 0, sizeof(struct sockaddr_storage)); memcpy(&(server->srcadr), ptr->ai_addr, ptr->ai_addrlen); server->event_time = ++sys_numservers; if (sys_servers == NULL) sys_servers = server; else { struct server *sp; for (sp = sys_servers; sp->next_server != NULL; sp = sp->next_server) ; sp->next_server = server; } } } freeaddrinfo(addrResult);}/* * findserver - find a server in the list given its address * ***(For now it isn't totally AF-Independant, to check later..) */static struct server *findserver( struct sockaddr_storage *addr ){ struct server *server; struct server *mc_server; isc_sockaddr_t laddr; isc_sockaddr_t saddr; if(addr->ss_family == AF_INET) { isc_sockaddr_fromin( &laddr, &((struct sockaddr_in*)addr)->sin_addr, 0); } else { isc_sockaddr_fromin6(&laddr, &((struct sockaddr_in6*)addr)->sin6_addr, 0); } mc_server = NULL; if (htons(((struct sockaddr_in*)addr)->sin_port) != NTP_PORT) return 0; for (server = sys_servers; server != NULL; server = server->next_server) { if(server->srcadr.ss_family == AF_INET) { isc_sockaddr_fromin(&saddr, &((struct sockaddr_in*)&server->srcadr)->sin_addr, 0); } else { isc_sockaddr_fromin6(&saddr, &((struct sockaddr_in6*)&server->srcadr)->sin6_addr, 0); } if (isc_sockaddr_eqaddr(&laddr, &saddr) == ISC_TRUE) return server; if(addr->ss_family == server->srcadr.ss_family) { if (isc_sockaddr_ismulticast(&saddr) == ISC_TRUE) mc_server = server; } } if (mc_server != NULL) { struct server *sp; if (mc_server->event_time != 0) { mc_server->event_time = 0; complete_servers++; } server = (struct server *)emalloc(sizeof(struct server)); memset((char *)server, 0, sizeof(struct server)); memcpy(&server->srcadr, &addr, sizeof(struct sockaddr_storage)); server->event_time = ++sys_numservers; for (sp = sys_servers; sp->next_server != NULL; sp = sp->next_server) ; sp->next_server = server; transmit(server); } return NULL;}/* * timer - process a timer interrupt */voidtimer(void){ struct server *server; /* * Bump the current idea of the time */ current_time++; /* * Search through the server list looking for guys * who's event timers have expired. Give these to * the transmit routine. */ for (server = sys_servers; server != NULL; server = server->next_server) { if (server->event_time != 0 && server->event_time <= current_time) transmit(server); }}/* * The code duplication in the following subroutine sucks, but * we need to appease ansi2knr. */#ifndef SYS_WINNT/* * alarming - record the occurance of an alarm interrupt */static RETSIGTYPEalarming( int sig ){ alarm_flag++;}#elsevoid CALLBACK alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2){ alarm_flag++;}#endif /* SYS_WINNT *//* * init_alarm - set up the timer interrupt */static voidinit_alarm(void){#ifndef SYS_WINNT# ifndef HAVE_TIMER_SETTIME struct itimerval itimer;# else struct itimerspec ntpdate_itimer;# endif#else TIMECAPS tc; UINT wTimerRes, wTimerID;# endif /* SYS_WINNT */#if defined SYS_CYGWIN32 || defined SYS_WINNT HANDLE hToken; TOKEN_PRIVILEGES tkp; DWORD dwUser = 0;#endif /* SYS_WINNT */ alarm_flag = 0;#ifndef SYS_WINNT# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) alarm_flag = 0; /* this code was put in as setitimer() is non existant this us the * POSIX "equivalents" setup - casey */ /* ntpdate_timerid is global - so we can kill timer later */ if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==# ifdef SYS_VXWORKS ERROR# else -1# endif ) { fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n"); return; } /* TIMER_HZ = (5) * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) * seconds from now and they continue on every 1/TIMER_HZ seconds. */ (void) signal_no_reset(SIGALRM, alarming); ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0; ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ; ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1); timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);# else /* * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) * seconds from now and they continue on every 1/TIMER_HZ seconds. */ (void) signal_no_reset(SIGALRM, alarming); itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; itimer.it_interval.tv_usec = 1000000/TIMER_HZ; itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1); setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);# endif#if defined SYS_CYGWIN32 /* * Get previleges needed for fiddling with the clock */ /* get the current process token handle */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { msyslog(LOG_ERR, "OpenProcessToken failed: %m"); exit(1); } /* get the LUID for system-time privilege. */ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); tkp.PrivilegeCount = 1; /* one privilege to set */ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; /* get set-time privilege for this process. */ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); /* cannot test return value of AdjustTokenPrivileges. */ if (GetLastError() != ERROR_SUCCESS) msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");#endif#else /* SYS_WINNT */ _tzset(); /* * Get previleges needed for fiddling with the clock */ /* get the current process token handle */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { msyslog(LOG_ERR, "OpenProcessToken failed: %m"); exit(1); } /* get the LUID for system-time privilege. */ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); tkp.PrivilegeCount = 1; /* one privilege to set */ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; /* get set-time privilege for this process. */ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); /* cannot test return value of AdjustTokenPrivileges. */ if (GetLastError() != ERROR_SUCCESS) msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); /* * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds * Under Win/NT, expiry of timer interval leads to invocation * of a callback function (on a different thread) rather than * generating an alarm signal */ /* determine max and min resolution supported */ if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { msyslog(LOG_ERR, "timeGetDevCaps failed: %m"); exit(1); } wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); /* establish the minimum timer resolution that we'll use */ timeBeginPeriod(wTimerRes); /* start the timer event */ wTimerID = timeSetEvent( (UINT) (1000/TIMER_HZ), /* Delay */ wTimerRes, /* Resolution */ (LPTIMECALLBACK) alarming, /* Callback function */ (DWORD) dwUser, /* User data */ TIME_PERIODIC); /* Event type (periodic) */ if (wTimerID == 0) { msyslog(LOG_ERR, "timeSetEvent failed: %m"); exit(1); }#endif /* SYS_WINNT */}/* * We do asynchronous input using the SIGIO facility. A number of * recvbuf buffers are preallocated for input. In the signal * handler we poll to see if the socket is ready and read the * packets from it into the recvbuf's along with a time stamp and * an indication of the source host and the interface it was received * through. This allows us to get as accurate receive time stamps * as possible independent of other processing going on. * * We allocate a number of recvbufs equal to the number of servers * plus 2. This should be plenty. *//* * init_io - initialize I/O data and open socket */static voidinit_io(void){ struct addrinfo *res, *ressave; struct addrinfo hints; char service[5]; int optval = 1; /* * Init buffer free list and stat counters */ init_recvbuff(sys_numservers + 2); /* * Open the socket */ strcpy(service, "ntp"); /* * Init hints addrinfo structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = ai_fam_templ; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_DGRAM; if(getaddrinfo(NULL, service, &hints, &res) != 0) { msyslog(LOG_ERR, "getaddrinfo() failed: %m"); exit(1); /*NOTREACHED*/ }#ifdef SYS_WINNT if (ntp_port_inuse(AF_INET, NTP_PORT) ){ netsyslog(LOG_ERR, "the NTP socket is in use, exiting: %m"); exit(1); }#endif /* Remember the address of the addrinfo structure chain */ ressave = res; /* * For each structure returned, open and bind socket
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -