/* * TTY initialization routines. */ int init_clock_sig( struct refclockio *rio ) { # ifdef USE_TTY_SIGPOLL { /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) { msyslog(LOG_ERR, "init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); return 1; } return 0; } # else /* * Special cases first! */ /* Was: defined(SYS_HPUX) */ # if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT) #define CLOCK_DONE { int pgrp, on = 1; /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ pgrp = getpid(); if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1) { msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m"); exit(1); /*NOTREACHED*/ } /* * set non-blocking, async I/O on the descriptor */ if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1) { msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m"); exit(1); /*NOTREACHED*/ } if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1) { msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m"); exit(1); /*NOTREACHED*/ } return 0; } # endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */ /* Was: defined(SYS_AIX) && !defined(_BSD) */ # if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN) /* * SYSV compatibility mode under AIX. */ #define CLOCK_DONE { int pgrp, on = 1; /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1) { msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m"); return 1; } pgrp = -getpid(); if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1) { msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m"); return 1; } if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) { msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); return 1; } return 0; } # endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */ # ifndef CLOCK_DONE { /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ # if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY) /* * there are, however, always exceptions to the rules * one is, that OSF accepts SETOWN on TTY fd's only, iff they are * CTTYs. SunOS and HPUX do not semm to have this restriction. * another question is: how can you do multiple SIGIO from several * ttys (as they all should be CTTYs), wondering... * * kd 95-07-16 */ if (ioctl(rio->fd, TIOCSCTTY, 0) == -1) { msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m"); return 1; } # endif /* TIOCSCTTY && USE_FSETOWNCTTY */ if (fcntl(rio->fd, F_SETOWN, getpid()) == -1) { msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m"); return 1; } if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) { msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); return 1; } return 0; } # endif /* CLOCK_DONE */ # endif /* !USE_TTY_SIGPOLL */ }
/* * Set the process priority */ static void set_process_priority(void) { #ifdef DEBUG if (debug > 1) msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>", ((priority_done) ? "Leave priority alone" : "Attempt to set priority" ), priority_done); #endif /* DEBUG */ #if defined(HAVE_SCHED_SETSCHEDULER) if (!priority_done) { extern int config_priority_override, config_priority; int pmax, pmin; struct sched_param sched; pmax = sched_get_priority_max(SCHED_FIFO); sched.sched_priority = pmax; if ( config_priority_override ) { pmin = sched_get_priority_min(SCHED_FIFO); if ( config_priority > pmax ) sched.sched_priority = pmax; else if ( config_priority < pmin ) sched.sched_priority = pmin; else sched.sched_priority = config_priority; } if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) msyslog(LOG_ERR, "sched_setscheduler(): %m"); else ++priority_done; } #endif /* HAVE_SCHED_SETSCHEDULER */ #if defined(HAVE_RTPRIO) # ifdef RTP_SET if (!priority_done) { struct rtprio srtp; srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */ srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */ if (rtprio(RTP_SET, getpid(), &srtp) < 0) msyslog(LOG_ERR, "rtprio() error: %m"); else ++priority_done; } # else /* not RTP_SET */ if (!priority_done) { if (rtprio(0, 120) < 0) msyslog(LOG_ERR, "rtprio() error: %m"); else ++priority_done; } # endif /* not RTP_SET */ #endif /* HAVE_RTPRIO */ #if defined(NTPD_PRIO) && NTPD_PRIO != 0 # ifdef HAVE_ATT_NICE if (!priority_done) { errno = 0; if (-1 == nice (NTPD_PRIO) && errno != 0) msyslog(LOG_ERR, "nice() error: %m"); else ++priority_done; } # endif /* HAVE_ATT_NICE */ # ifdef HAVE_BSD_NICE if (!priority_done) { if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO)) msyslog(LOG_ERR, "setpriority() error: %m"); else ++priority_done; } # endif /* HAVE_BSD_NICE */ #endif /* NTPD_PRIO && NTPD_PRIO != 0 */ if (!priority_done) msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority"); }
/* * authreadkeys - (re)read keys from a file. */ int authreadkeys( const char *file ) { FILE *fp; char *line; char *token; keyid_t keyno; int keytype; char buf[512]; /* lots of room for line */ u_char keystr[20]; size_t len; size_t j; /* * Open file. Complain and return if it can't be opened. */ fp = fopen(file, "r"); if (fp == NULL) { msyslog(LOG_ERR, "authreadkeys: file %s: %m", file); return (0); } INIT_SSL(); /* * Remove all existing keys */ auth_delkeys(); /* * Now read lines from the file, looking for key entries */ while ((line = fgets(buf, sizeof buf, fp)) != NULL) { token = nexttok(&line); if (token == NULL) continue; /* * First is key number. See if it is okay. */ keyno = atoi(token); if (keyno == 0) { msyslog(LOG_ERR, "authreadkeys: cannot change key %s", token); continue; } if (keyno > NTP_MAXKEY) { msyslog(LOG_ERR, "authreadkeys: key %s > %d reserved for Autokey", token, NTP_MAXKEY); continue; } /* * Next is keytype. See if that is all right. */ token = nexttok(&line); if (token == NULL) { msyslog(LOG_ERR, "authreadkeys: no key type for key %d", keyno); continue; } #ifdef OPENSSL /* * The key type is the NID used by the message digest * algorithm. There are a number of inconsistencies in * the OpenSSL database. We attempt to discover them * here and prevent use of inconsistent data later. */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { msyslog(LOG_ERR, "authreadkeys: invalid type for key %d", keyno); continue; } if (EVP_get_digestbynid(keytype) == NULL) { msyslog(LOG_ERR, "authreadkeys: no algorithm for key %d", keyno); continue; } #else /* !OPENSSL follows */ /* * The key type is unused, but is required to be 'M' or * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { msyslog(LOG_ERR, "authreadkeys: invalid type for key %d", keyno); continue; } keytype = KEY_TYPE_MD5; #endif /* !OPENSSL */ /* * Finally, get key and insert it. If it is longer than 20 * characters, it is a binary string encoded in hex; * otherwise, it is a text string of printable ASCII * characters. */ token = nexttok(&line); if (token == NULL) { msyslog(LOG_ERR, "authreadkeys: no key for key %d", keyno); continue; } len = strlen(token); if (len <= sizeof(keystr)) { MD5auth_setkey(keyno, keytype, (u_char *)token, len); } else { char hex[] = "0123456789abcdef"; u_char temp; char *ptr; size_t jlim; jlim = min(len, 2 * sizeof(keystr)); for (j = 0; j < jlim; j++) { ptr = strchr(hex, tolower((unsigned char)token[j])); if (ptr == NULL) break; /* abort decoding */ temp = (u_char)(ptr - hex); if (j & 1) keystr[j / 2] |= temp; else keystr[j / 2] = temp << 4; } if (j < jlim) { msyslog(LOG_ERR, "authreadkeys: invalid hex digit for key %d", keyno); continue; } MD5auth_setkey(keyno, keytype, keystr, jlim / 2); } } fclose(fp); return (1); }
static void neoclock4x_receive(struct recvbuf *rbufp) { struct neoclock4x_unit *up; struct refclockproc *pp; struct peer *peer; unsigned long calc_utc; int day; int month; /* ddd conversion */ int c; int dsec; unsigned char calc_chksum; int recv_chksum; peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; /* wait till poll interval is reached */ if(0 == up->recvnow) return; /* reset poll interval flag */ up->recvnow = 0; /* read last received timecode */ pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); pp->leap = LEAP_NOWARNING; if(NEOCLOCK4X_TIMECODELEN != pp->lencode) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s", up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode); refclock_report(peer, CEVNT_BADREPLY); return; } neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2); /* calculate checksum */ calc_chksum = 0; for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++) { calc_chksum += pp->a_lastcode[c]; } if(recv_chksum != calc_chksum) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s", up->unit, pp->a_lastcode); refclock_report(peer, CEVNT_BADREPLY); return; } /* Allow synchronization even is quartz clock is * never initialized. * WARNING: This is dangerous! */ up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS]; if(0==(pp->sloppyclockflag & CLK_FLAG2)) { if('I' != up->quarzstatus) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s", up->unit, pp->a_lastcode); pp->leap = LEAP_NOTINSYNC; refclock_report(peer, CEVNT_BADDATE); return; } } if('I' != up->quarzstatus) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s", up->unit, pp->a_lastcode); } /* * If NeoClock4X is not synchronized to a radio clock * check if we're allowed to synchronize with the quartz * clock. */ up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE]; if(0==(pp->sloppyclockflag & CLK_FLAG2)) { if('A' != up->timesource) { /* not allowed to sync with quartz clock */ if(0==(pp->sloppyclockflag & CLK_FLAG1)) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } } /* this should only used when first install is done */ if(pp->sloppyclockflag & CLK_FLAG4) { msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s", up->unit, pp->a_lastcode); } /* 123456789012345678901234567890123456789012345 */ /* S/N123456DCF1004021010001202ASX1213CR\r\n */ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2); #if defined(NTP_PRE_420) pp->msec = dsec * 10; /* convert 1/100s from neoclock to real miliseconds */ #else pp->nsec = dsec * 10 * NSEC_TO_MILLI; /* convert 1/100s from neoclock to nanoseconds */ #endif memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); up->radiosignal[3] = 0; memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); up->serial[6] = 0; up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS]; neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2); neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2); /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (day < 1) || (day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s", up->unit, pp->a_lastcode); refclock_report(peer, CEVNT_BADDATE); return; } /* Year-2000 check not needed anymore. Same problem * will arise at 2099 but what should we do...? * * wrap 2-digit date into 4-digit * * if(pp->year < YEAR_PIVOT) * { * pp->year += 100; * } */ pp->year += 2000; /* adjust NeoClock4X local time to UTC */ calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); calc_utc -= 3600; /* adjust NeoClock4X daylight saving time if needed */ if('S' == up->dststatus) calc_utc -= 3600; neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); /* some preparations */ pp->day = ymd2yd(pp->year, month, day); pp->leap = 0; if(pp->sloppyclockflag & CLK_FLAG4) { msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld", up->unit, pp->year, month, day, pp->hour, pp->minute, pp->second, #if defined(NTP_PRE_420) pp->msec #else pp->nsec/NSEC_TO_MILLI #endif ); } up->utc_year = pp->year; up->utc_month = month; up->utc_day = day; up->utc_hour = pp->hour; up->utc_minute = pp->minute; up->utc_second = pp->second; #if defined(NTP_PRE_420) up->utc_msec = pp->msec; #else up->utc_msec = pp->nsec/NSEC_TO_MILLI; #endif if(!refclock_process(pp)) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit); refclock_report(peer, CEVNT_FAULT); return; } refclock_receive(peer); /* report good status */ refclock_report(peer, CEVNT_NOMINAL); record_clock_stats(&peer->srcadr, pp->a_lastcode); }
static int neol_query_firmware(int fd, int unit, char *firmware, int maxlen) { char tmpbuf[256]; int len; int lastsearch; unsigned char c; int last_c_was_crlf; int last_crlf_conv_len; int init; int read_errors; int flag = 0; int chars_read; /* wait a little bit */ sleep(1); if(-1 != write(fd, "V", 1)) { /* wait a little bit */ sleep(1); memset(tmpbuf, 0x00, sizeof(tmpbuf)); len = 0; lastsearch = 0; last_c_was_crlf = 0; last_crlf_conv_len = 0; init = 1; read_errors = 0; chars_read = 0; for(;;) { if(read_errors > 5) { msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit); strlcpy(tmpbuf, "unknown due to timeout", sizeof(tmpbuf)); break; } if(chars_read > 500) { msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit); strlcpy(tmpbuf, "unknown due to garbage input", sizeof(tmpbuf)); break; } if(-1 == read(fd, &c, 1)) { if(EAGAIN != errno) { msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %m", unit); read_errors++; } else { sleep(1); } continue; } else { chars_read++; } if(init) { if(0xA9 != c) /* wait for (c) char in input stream */ continue; strlcpy(tmpbuf, "(c)", sizeof(tmpbuf)); len = 3; init = 0; continue; } #if 0 msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c); #endif if(0x0A == c || 0x0D == c) { if(last_c_was_crlf) { char *ptr; ptr = strstr(&tmpbuf[lastsearch], "S/N"); if(NULL != ptr) { tmpbuf[last_crlf_conv_len] = 0; flag = 1; break; } /* convert \n to / */ last_crlf_conv_len = len; tmpbuf[len++] = ' '; tmpbuf[len++] = '/'; tmpbuf[len++] = ' '; lastsearch = len; } last_c_was_crlf = 1; } else { last_c_was_crlf = 0; if(0x00 != c) tmpbuf[len++] = (char) c; } tmpbuf[len] = '\0'; if(len > sizeof(tmpbuf)-5) break; } } else { msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit); strlcpy(tmpbuf, "unknown error", sizeof(tmpbuf)); } if (strlcpy(firmware, tmpbuf, maxlen) >= maxlen) strlcpy(firmware, "buffer too small", maxlen); if(flag) { NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware); if(strstr(firmware, "/R2")) { msyslog(LOG_INFO, "NeoClock4X(%d): Your NeoClock4X uses the new R2 firmware release. Please note the changed LED behaviour.", unit); } } return (flag); }
/* * arc_start - open the devices and initialize data for processing */ static int arc_start( int unit, struct peer *peer ) { register struct arcunit *up; struct refclockproc *pp; int temp_fd; int fd; char device[20]; #ifdef HAVE_TERMIOS struct termios arg; #endif msyslog(LOG_NOTICE, "MSF_ARCRON %s: opening unit %d", arc_version, unit); DPRINTF(1, ("arc: %s: attempt to open unit %d.\n", arc_version, unit)); /* * Open serial port. Use CLK line discipline, if available. */ snprintf(device, sizeof(device), DEVICE, unit); temp_fd = refclock_open(device, SPEED, LDISC_CLK); if (temp_fd <= 0) return 0; DPRINTF(1, ("arc: unit %d using tty_open().\n", unit)); fd = tty_open(device, OPEN_FLAGS, 0777); if (fd < 0) { msyslog(LOG_ERR, "MSF_ARCRON(%d): failed second open(%s, 0777): %m.\n", unit, device); close(temp_fd); return 0; } close(temp_fd); temp_fd = -1; #ifndef SYS_WINNT fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ #endif DPRINTF(1, ("arc: opened RS232 port with file descriptor %d.\n", fd)); #ifdef HAVE_TERMIOS if (tcgetattr(fd, &arg) < 0) { msyslog(LOG_ERR, "MSF_ARCRON(%d): tcgetattr(%s): %m.\n", unit, device); close(fd); return 0; } arg.c_iflag = IGNBRK | ISTRIP; arg.c_oflag = 0; arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB; arg.c_lflag = 0; arg.c_cc[VMIN] = 1; arg.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &arg) < 0) { msyslog(LOG_ERR, "MSF_ARCRON(%d): tcsetattr(%s): %m.\n", unit, device); close(fd); return 0; } #else msyslog(LOG_ERR, "ARCRON: termios required by this driver"); (void)close(fd); return 0; #endif /* Set structure to all zeros... */ up = emalloc_zero(sizeof(*up)); pp = peer->procptr; pp->io.clock_recv = arc_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { close(fd); pp->io.fd = -1; free(up); return(0); } pp->unitptr = up; /* * Initialize miscellaneous variables */ peer->precision = PRECISION; peer->stratum = 2; /* Default to stratum 2 not 0. */ pp->clockdesc = DESCRIPTION; if (peer->MODE > 3) { msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); return 0; } #ifdef DEBUG if(debug) { printf("arc: mode = %d.\n", peer->MODE); } #endif switch (peer->MODE) { case 1: memcpy((char *)&pp->refid, REFID_MSF, 4); break; case 2: memcpy((char *)&pp->refid, REFID_DCF77, 4); break; case 3: memcpy((char *)&pp->refid, REFID_WWVB, 4); break; default: memcpy((char *)&pp->refid, REFID, 4); break; } /* Spread out resyncs so that they should remain separated. */ up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009; #if 0 /* Not needed because of zeroing of arcunit structure... */ up->resyncing = 0; /* Not resyncing yet. */ up->saved_flags = 0; /* Default is all flags off. */ /* Clear send buffer out... */ { int i; for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; } } #endif #ifdef ARCRON_KEEN up->quality = QUALITY_UNKNOWN; /* Trust the clock immediately. */ #else up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */ #endif peer->action = arc_event_handler; ENQUEUE(up); return(1); }
/* psc_poll: read, decode, and record device time */ static void psc_poll( int unit, struct peer *peer ) { struct refclockproc *pp = peer->procptr; struct psc_unit *up; unsigned tlo, thi; unsigned char status; up = (struct psc_unit *) pp->unitptr; tlo = regp[unit]->low_time; /* latch and read first 4 bytes */ thi = regp[unit]->high_time; /* read 4 higher order bytes */ status = regp[unit]->device_status; /* read device status byte */ if (!(status & PSC_SYNC_OK)) { refclock_report(peer, CEVNT_BADTIME); if (!up->msg_flag[unit]) { /* write once to system log */ msyslog(LOG_WARNING, "SYNCHRONIZATION LOST on unit %1d, status %02x\n", unit, status); up->msg_flag[unit] = 1; } return; } get_systime(&pp->lastrec); pp->polls++; tlo = SWAP(tlo); /* little to big endian swap on */ thi = SWAP(thi); /* copy of data */ /* convert the BCD time to broken down time used by refclockproc */ pp->day = BCD2INT3((thi & 0x0FFF0000) >> 16); pp->hour = BCD2INT2((thi & 0x0000FF00) >> 8); pp->minute = BCD2INT2(thi & 0x000000FF); pp->second = BCD2INT2(tlo >> 24); /* ntp_process() in ntp_refclock.c appears to use usec as fraction of second in microseconds if usec is nonzero. */ pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) + BCD2INT3(tlo & 0x00000FFF); snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day, pp->hour, pp->minute, pp->second, pp->nsec, status, thi, tlo); pp->lencode = strlen(pp->a_lastcode); /* compute the timecode timestamp */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } /* simulate the NTP receive and packet procedures */ refclock_receive(peer); /* write clock statistics to file */ record_clock_stats(&peer->srcadr, pp->a_lastcode); /* With the first timecode beginning the day, check for a GPS leap second notification. */ if (pp->hour < up->last_hour) { check_leap_sec(pp, unit); up->msg_flag[0] = up->msg_flag[1] = 0; /* reset flags */ } up->last_hour = pp->hour; }
static void check_leapsec( u_int32 now , const time_t * tpiv , int/*BOOL*/ reset) { static const char leapmsg_p_step[] = "Positive leap second, stepped backward."; static const char leapmsg_p_slew[] = "Positive leap second, no step correction. " "System clock will be inaccurate for a long time."; static const char leapmsg_n_step[] = "Negative leap second, stepped forward."; static const char leapmsg_n_slew[] = "Negative leap second, no step correction. " "System clock will be inaccurate for a long time."; leap_result_t lsdata; u_int32 lsprox; #ifdef AUTOKEY int/*BOOL*/ update_autokey = FALSE; #endif #ifndef SYS_WINNT /* WinNT port has its own leap second handling */ # ifdef KERNEL_PLL leapsec_electric(pll_control && kern_enable); # else leapsec_electric(0); # endif #endif #ifdef LEAP_SMEAR leap_smear.enabled = leap_smear_intv != 0; #endif if (reset) { lsprox = LSPROX_NOWARN; leapsec_reset_frame(); memset(&lsdata, 0, sizeof(lsdata)); } else { int fired = leapsec_query(&lsdata, now, tpiv); DPRINTF(1, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n", fired, now, now, lsdata.tai_diff, lsdata.ddist)); #ifdef LEAP_SMEAR leap_smear.in_progress = 0; leap_smear.doffset = 0.0; if (leap_smear.enabled) { if (lsdata.tai_diff) { if (leap_smear.interval == 0) { leap_smear.interval = leap_smear_intv; leap_smear.intv_end = lsdata.ttime.Q_s; leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end)); } } else { if (leap_smear.interval) DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n")); leap_smear.interval = 0; } if (leap_smear.interval) { double dtemp = now; if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { double leap_smear_time = dtemp - leap_smear.intv_start; /* * For now we just do a linear interpolation over the smear interval */ #if 0 // linear interpolation leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); #else // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; #endif /* * TODO see if we're inside an inserted leap second, so we need to compute * leap_smear.doffset = 1.0 - leap_smear.doffset */ leap_smear.in_progress = 1; #if 0 && defined( DEBUG ) msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, now, leap_smear_time, leap_smear.doffset); #else DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n", leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, now, leap_smear_time, leap_smear.doffset)); #endif } } } else leap_smear.interval = 0; /* * Update the current leap smear offset, eventually 0.0 if outside smear interval. */ DTOLFP(leap_smear.doffset, &leap_smear.offset); #endif /* LEAP_SMEAR */ if (fired) { /* Full hit. Eventually step the clock, but always * announce the leap event has happened. */ const char *leapmsg = NULL; if (lsdata.warped < 0) { if (clock_max_back > 0.0 && clock_max_back < abs(lsdata.warped)) { step_systime(lsdata.warped); leapmsg = leapmsg_p_step; } else { leapmsg = leapmsg_p_slew; } } else if (lsdata.warped > 0) { if (clock_max_fwd > 0.0 && clock_max_fwd < abs(lsdata.warped)) { step_systime(lsdata.warped); leapmsg = leapmsg_n_step; } else { leapmsg = leapmsg_n_slew; } } if (leapmsg) msyslog(LOG_NOTICE, "%s", leapmsg); report_event(EVNT_LEAP, NULL, NULL); #ifdef AUTOKEY update_autokey = TRUE; #endif lsprox = LSPROX_NOWARN; leapsec = LSPROX_NOWARN; sys_tai = lsdata.tai_offs; } else { #ifdef AUTOKEY update_autokey = (sys_tai != (u_int)lsdata.tai_offs); #endif lsprox = lsdata.proximity; sys_tai = lsdata.tai_offs; } } /* We guard against panic alarming during the red alert phase. * Strange and evil things might happen if we go from stone cold * to piping hot in one step. If things are already that wobbly, * we let the normal clock correction take over, even if a jump * is involved. * Also make sure the alarming events are edge-triggered, that is, * ceated only when the threshold is crossed. */ if ( (leapsec > 0 || lsprox < LSPROX_ALERT) && leapsec < lsprox ) { if ( leapsec < LSPROX_SCHEDULE && lsprox >= LSPROX_SCHEDULE) { if (lsdata.dynamic) report_event(PEVNT_ARMED, sys_peer, NULL); else report_event(EVNT_ARMED, NULL, NULL); } leapsec = lsprox; } if (leapsec > lsprox) { if ( leapsec >= LSPROX_SCHEDULE && lsprox < LSPROX_SCHEDULE) { report_event(EVNT_DISARMED, NULL, NULL); } leapsec = lsprox; } if (leapsec >= LSPROX_SCHEDULE) leapdif = lsdata.tai_diff; else leapdif = 0; check_leap_sec_in_progress(&lsdata); #ifdef AUTOKEY if (update_autokey) crypto_update_taichange(); #endif }
/* * refclock_newpeer - initialize and start a reference clock * * This routine allocates and initializes the interface structure which * supports a reference clock in the form of an ordinary NTP peer. A * driver-specific support routine completes the initialization, if * used. Default peer variables which identify the clock and establish * its reference ID and stratum are set here. It returns one if success * and zero if the clock address is invalid or already running, * insufficient resources are available or the driver declares a bum * rap. */ int refclock_newpeer( struct peer *peer /* peer structure pointer */ ) { struct refclockproc *pp; u_char clktype; int unit; /* * Check for valid clock address. If already running, shut it * down first. */ if (!ISREFCLOCKADR(&peer->srcadr)) { msyslog(LOG_ERR, "refclock_newpeer: clock address %s invalid", stoa(&peer->srcadr)); return (0); } clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); unit = REFCLOCKUNIT(&peer->srcadr); if (clktype >= num_refclock_conf || refclock_conf[clktype]->clock_start == noentry) { msyslog(LOG_ERR, "refclock_newpeer: clock type %d invalid\n", clktype); return (0); } /* * Allocate and initialize interface structure */ pp = emalloc_zero(sizeof(*pp)); peer->procptr = pp; /* * Initialize structures */ peer->refclktype = clktype; peer->refclkunit = (u_char)unit; peer->flags |= FLAG_REFCLOCK; peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_REFCLOCK; peer->ppoll = peer->maxpoll; pp->type = clktype; pp->conf = refclock_conf[clktype]; pp->timestarted = current_time; pp->io.fd = -1; /* * Set peer.pmode based on the hmode. For appearances only. */ switch (peer->hmode) { case MODE_ACTIVE: peer->pmode = MODE_PASSIVE; break; default: peer->pmode = MODE_SERVER; break; } /* * Do driver dependent initialization. The above defaults * can be wiggled, then finish up for consistency. */ if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { refclock_unpeer(peer); return (0); } peer->refid = pp->refid; return (1); }
/* * true_receive - receive data from the serial interface on a clock */ static void true_receive( struct recvbuf *rbufp ) { register struct true_unit *up; struct refclockproc *pp; struct peer *peer; u_short new_station; char synced; int i; int lat, lon, off; /* GOES Satellite position */ /* Use these variable to hold data until we decide its worth keeping */ char rd_lastcode[BMAX]; l_fp rd_tmp; u_short rd_lencode; /* * Get the clock this applies to and pointers to the data. */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct true_unit *)pp->unitptr; /* * Read clock output. Automatically handles STREAMS, CLKLDISC. */ rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp); rd_lastcode[rd_lencode] = '\0'; /* * There is a case where <cr><lf> generates 2 timestamps. */ if (rd_lencode == 0) return; pp->lencode = rd_lencode; strcpy(pp->a_lastcode, rd_lastcode); pp->lastrec = rd_tmp; true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode); up->pollcnt = 2; record_clock_stats(&peer->srcadr, pp->a_lastcode); /* * We get down to business, check the timecode format and decode * its contents. This code decodes a multitude of different * clock messages. Timecodes are processed if needed. All replies * will be run through the state machine to tweak driver options * and program the clock. */ /* * Clock misunderstood our last command? */ if (pp->a_lastcode[0] == '?' || strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) { true_doevent(peer, e_Huh); return; } /* * Timecode: "nnnnn+nnn-nnn" * (from GOES clock when asked about satellite position) */ if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') && (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') && sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3 ) { const char *label = "Botch!"; /* * This is less than perfect. Call the (satellite) * either EAST or WEST and adjust slop accodingly * Perfectionists would recalculate the exact delay * and adjust accordingly... */ if (lon > 7000 && lon < 14000) { if (lon < 10000) { new_station = GOES_EAST; label = "EAST"; } else { new_station = GOES_WEST; label = "WEST"; } if (new_station != up->station) { double dtemp; dtemp = pp->fudgetime1; pp->fudgetime1 = pp->fudgetime2; pp->fudgetime2 = dtemp; up->station = new_station; } } else { /*refclock_report(peer, CEVNT_BADREPLY);*/ label = "UNKNOWN"; } true_debug(peer, "GOES: station %s\n", label); true_doevent(peer, e_Satellite); return; } /* * Timecode: "Fnn" * (from TM/TMD clock when it wants to tell us what it's up to.) */ if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) { switch (i) { case 50: true_doevent(peer, e_F50); break; case 51: true_doevent(peer, e_F51); break; default: true_debug(peer, "got F%02d - ignoring\n", i); break; } return; } /* * Timecode: " TRUETIME Mk III" or " TRUETIME XL" * (from a TM/TMD/XL clock during initialization.) */ if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 || strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) { true_doevent(peer, e_F18); NLOG(NLOG_CLOCKSTATUS) { msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode); } return; }
/* * init_timer - initialize the timer data structures */ void init_timer(void) { /* * Initialize... */ alarm_flag = FALSE; alarm_overflow = 0; adjust_timer = 1; stats_timer = SECSPERHR; leapf_timer = SECSPERDAY; huffpuff_timer = 0; interface_timer = 0; current_time = 0; timer_overflows = 0; timer_xmtcalls = 0; timer_timereset = 0; #ifndef SYS_WINNT /* * Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT * seconds from now and they continue on every 2**EVENT_TIMEOUT * seconds. */ # ifndef VMS # ifdef HAVE_TIMER_CREATE if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) { msyslog(LOG_ERR, "timer_create failed, %m"); exit(1); } # endif signal_no_reset(SIGALRM, alarming); itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT); itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0; set_timer_or_die(&itimer); # else /* VMS follows */ vmsinc[0] = 10000000; /* 1 sec */ vmsinc[1] = 0; lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc); sys$gettim(&vmstimer); /* that's "now" as abstime */ lib$addx(&vmsinc, &vmstimer, &vmstimer); sys$setimr(0, &vmstimer, alarming, alarming, 0); # endif /* VMS */ #else /* SYS_WINNT follows */ /* * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds * Under Windows/NT, */ WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL); if (WaitableTimerHandle == NULL) { msyslog(LOG_ERR, "CreateWaitableTimer failed: %m"); exit(1); } else { DWORD Period; LARGE_INTEGER DueTime; BOOL rc; Period = (1 << EVENT_TIMEOUT) * 1000; DueTime.QuadPart = Period * 10000i64; rc = SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE); if (!rc) { msyslog(LOG_ERR, "SetWaitableTimer failed: %m"); exit(1); } } #endif /* SYS_WINNT */ }
static u_long convert_rawdcf( unsigned char *buffer, int size, struct dcfparam *dcfprm, clocktime_t *clock_time ) { unsigned char *s = buffer; const unsigned char *b = dcfprm->onebits; const unsigned char *c = dcfprm->zerobits; int i; parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer)); if (size < 57) { #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits", size); #endif return CVT_NONE; } for (i = 0; i < size; i++) { if ((*s != *b) && (*s != *c)) { /* * we only have two types of bytes (ones and zeros) */ #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion"); #endif return CVT_NONE; } if (*b) b++; if (*c) c++; s++; } /* * check Start and Parity bits */ if ((ext_bf(buffer, DCF_S, dcfprm->zerobits) == 1) && pcheck(buffer, DCF_P_P1, dcfprm->zerobits) && pcheck(buffer, DCF_P_P2, dcfprm->zerobits) && pcheck(buffer, DCF_P_P3, dcfprm->zerobits)) { /* * buffer OK */ parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n")); clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP; clock_time->utctime= 0; clock_time->usecond= 0; clock_time->second = 0; clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits); clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits); clock_time->hour = ext_bf(buffer, DCF_H10, dcfprm->zerobits); clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits); clock_time->day = ext_bf(buffer, DCF_D10, dcfprm->zerobits); clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits); clock_time->month = ext_bf(buffer, DCF_MO0, dcfprm->zerobits); clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits); clock_time->year = ext_bf(buffer, DCF_Y10, dcfprm->zerobits); clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits); switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits)) { case DCF_Z_MET: clock_time->utcoffset = -1*60*60; break; case DCF_Z_MED: clock_time->flags |= PARSEB_DST; clock_time->utcoffset = -2*60*60; break; default: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n")); return CVT_FAIL|CVT_BADFMT; } if (ext_bf(buffer, DCF_A1, dcfprm->zerobits)) clock_time->flags |= PARSEB_ANNOUNCE; if (ext_bf(buffer, DCF_A2, dcfprm->zerobits)) clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */ if (ext_bf(buffer, DCF_R, dcfprm->zerobits)) clock_time->flags |= PARSEB_CALLBIT; parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n", (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year, (u_long)clock_time->flags)); return CVT_OK; } else { /* * bad format - not for us */ #ifndef PARSEKERNEL msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"", buffer); #endif return CVT_FAIL|CVT_BADFMT; } }
/* ** Check if it's data for us and whether it's useable or not. ** ** If not, return a failure code so we can delete this server from our list ** and continue with another one. */ int process_pkt ( struct pkt *rpkt, sockaddr_u *sender, int pkt_len, int mode, struct pkt *spkt, const char * func_name ) { u_int key_id; struct key * pkt_key; int is_authentic; int mac_size; u_int exten_len; u_int32 * exten_end; u_int32 * packet_end; l_fp sent_xmt; l_fp resp_org; // key_id = 0; pkt_key = NULL; is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1; /* * Parse the extension field if present. We figure out whether * an extension field is present by measuring the MAC size. If * the number of words following the packet header is 0, no MAC * is present and the packet is not authenticated. If 1, the * packet is a crypto-NAK; if 3, the packet is authenticated * with DES; if 5, the packet is authenticated with MD5; if 6, * the packet is authenticated with SHA. If 2 or 4, the packet * is a runt and discarded forthwith. If greater than 6, an * extension field is present, so we subtract the length of the * field and go around again. */ if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) { msyslog(LOG_ERR, "%s: Incredible packet length: %d. Discarding.", func_name, pkt_len); return PACKET_UNUSEABLE; } /* HMS: the following needs a bit of work */ /* Note: pkt_len must be a multiple of 4 at this point! */ packet_end = (void*)((char*)rpkt + pkt_len); exten_end = skip_efields(rpkt->exten, packet_end); if (NULL == exten_end) { msyslog(LOG_ERR, "%s: Missing extension field. Discarding.", func_name); return PACKET_UNUSEABLE; } /* get size of MAC in cells; can be zero */ exten_len = (u_int)(packet_end - exten_end); /* deduce action required from remaining length */ switch (exten_len) { case 0: /* no Legacy MAC */ break; case 1: /* crypto NAK */ /* Only if the keyID is 0 and there were no EFs */ key_id = ntohl(*exten_end); printf("Crypto NAK = 0x%08x from %s\n", key_id, stoa(sender)); break; case 3: /* key ID + 3DES MAC -- unsupported! */ msyslog(LOG_ERR, "%s: Key ID + 3DES MAC is unsupported. Discarding.", func_name); return PACKET_UNUSEABLE; case 5: /* key ID + MD5 MAC */ case 6: /* key ID + SHA MAC */ /* ** Look for the key used by the server in the specified ** keyfile and if existent, fetch it or else leave the ** pointer untouched */ key_id = ntohl(*exten_end); get_key(key_id, &pkt_key); if (!pkt_key) { printf("unrecognized key ID = 0x%08x\n", key_id); break; } /* ** Seems like we've got a key with matching keyid. ** ** Generate a md5sum of the packet with the key from our ** keyfile and compare those md5sums. */ mac_size = exten_len << 2; if (!auth_md5(rpkt, pkt_len - mac_size, mac_size - 4, pkt_key)) { is_authentic = FALSE; break; } /* Yay! Things worked out! */ is_authentic = TRUE; TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n", func_name, stoa(sender), key_id)); break; default: msyslog(LOG_ERR, "%s: Unexpected extension length: %d. Discarding.", func_name, exten_len); return PACKET_UNUSEABLE; } switch (is_authentic) { case -1: /* unknown */ break; case 0: /* not authentic */ return SERVER_AUTH_FAIL; break; case 1: /* authentic */ break; default: /* error */ break; } /* Check for server's ntp version */ if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { msyslog(LOG_ERR, "%s: Packet shows wrong version (%d)", func_name, PKT_VERSION(rpkt->li_vn_mode)); return SERVER_UNUSEABLE; } /* We want a server to sync with */ if (PKT_MODE(rpkt->li_vn_mode) != mode && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) { msyslog(LOG_ERR, "%s: mode %d stratum %d", func_name, PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); return SERVER_UNUSEABLE; } /* Stratum is unspecified (0) check what's going on */ if (STRATUM_PKT_UNSPEC == rpkt->stratum) { char *ref_char; TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", func_name, rpkt->stratum)); ref_char = (char *) &rpkt->refid; TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name, ref_char[0], ref_char[1], ref_char[2], ref_char[3])); /* If it's a KOD packet we'll just use the KOD information */ if (ref_char[0] != 'X') { if (strncmp(ref_char, "DENY", 4) == 0) return KOD_DEMOBILIZE; if (strncmp(ref_char, "RSTR", 4) == 0) return KOD_DEMOBILIZE; if (strncmp(ref_char, "RATE", 4) == 0) return KOD_RATE; /* ** There are other interesting kiss codes which ** might be interesting for authentication. */ } } /* If the server is not synced it's not really useable for us */ if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) { msyslog(LOG_ERR, "%s: %s not in sync, skipping this server", func_name, stoa(sender)); return SERVER_UNUSEABLE; } /* * Decode the org timestamp and make sure we're getting a response * to our last request, but only if we're not in broadcast mode. */ if (MODE_BROADCAST == mode) return pkt_len; if (!L_ISEQU(&rpkt->org, &spkt->xmt)) { NTOHL_FP(&rpkt->org, &resp_org); NTOHL_FP(&spkt->xmt, &sent_xmt); msyslog(LOG_ERR, "%s response org expected to match sent xmt", stoa(sender)); msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org)); msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt)); return PACKET_UNUSEABLE; } return pkt_len; }
void init_socket_sig( int fd ) { # ifdef USE_UDP_SIGPOLL { if (ioctl(fd, I_SETSIG, S_INPUT) < 0) { msyslog(LOG_ERR, "init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); exit(1); } } # else /* USE_UDP_SIGPOLL */ { int pgrp; # ifdef FIOASYNC int on = 1; # endif # if defined(FIOASYNC) if (ioctl(fd, FIOASYNC, (char *)&on) == -1) { msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m"); exit(1); /*NOTREACHED*/ } # elif defined(FASYNC) { int flags; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m"); exit(1); /*NOTREACHED*/ } if (fcntl(fd, F_SETFL, flags|FASYNC) < 0) { msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m"); exit(1); /*NOTREACHED*/ } } # else # include "Bletch: Need asynchronous I/O!" # endif # ifdef UDP_BACKWARDS_SETOWN pgrp = -getpid(); # else pgrp = getpid(); # endif # if defined(SIOCSPGRP) if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1) { msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m"); exit(1); /*NOTREACHED*/ } # elif defined(FIOSETOWN) if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1) { msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m"); exit(1); /*NOTREACHED*/ } # elif defined(F_SETOWN) if (fcntl(fd, F_SETOWN, pgrp) == -1) { msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m"); exit(1); /*NOTREACHED*/ } # else # include "Bletch: Need to set process(group) to receive SIG(IO|POLL)" # endif } # endif /* USE_UDP_SIGPOLL */ }
/* * loop_config - configure the loop filter * * LOCKCLOCK: The LOOP_DRIFTINIT and LOOP_DRIFTCOMP cases are no-ops. */ void loop_config( int item, double freq ) { int i; #ifdef DEBUG if (debug > 1) printf("loop_config: item %d freq %f\n", item, freq); #endif switch (item) { /* * We first assume the kernel supports the ntp_adjtime() * syscall. If that syscall works, initialize the kernel time * variables. Otherwise, continue leaving no harm behind. */ case LOOP_DRIFTINIT: #ifndef LOCKCLOCK #ifdef KERNEL_PLL if (mode_ntpdate) break; pll_control = 1; memset(&ntv, 0, sizeof(ntv)); ntv.modes = MOD_BITS; ntv.status = STA_PLL; ntv.maxerror = MAXDISPERSE; ntv.esterror = MAXDISPERSE; ntv.constant = sys_poll; #ifdef SIGSYS /* * Use sigsetjmp() to save state and then call * ntp_adjtime(); if it fails, then siglongjmp() is used * to return control */ newsigsys.sa_handler = pll_trap; newsigsys.sa_flags = 0; if (sigaction(SIGSYS, &newsigsys, &sigsys)) { msyslog(LOG_ERR, "sigaction() fails to save SIGSYS trap: %m"); pll_control = 0; } if (sigsetjmp(env, 1) == 0) ntp_adjtime(&ntv); if ((sigaction(SIGSYS, &sigsys, (struct sigaction *)NULL))) { msyslog(LOG_ERR, "sigaction() fails to restore SIGSYS trap: %m"); pll_control = 0; } #else /* SIGSYS */ ntp_adjtime(&ntv); #endif /* SIGSYS */ /* * Save the result status and light up an external clock * if available. */ pll_status = ntv.status; if (pll_control) { #ifdef STA_NANO if (pll_status & STA_CLK) ext_enable = 1; #endif /* STA_NANO */ report_event(EVNT_KERN, NULL, "kernel time sync enabled"); } #endif /* KERNEL_PLL */ #endif /* LOCKCLOCK */ break; /* * Initialize the frequency. If the frequency file is missing or * broken, set the initial frequency to zero and set the state * to NSET. Otherwise, set the initial frequency to the given * value and the state to FSET. */ case LOOP_DRIFTCOMP: #ifndef LOCKCLOCK if (freq > NTP_MAXFREQ || freq < -NTP_MAXFREQ) { set_freq(0); rstclock(EVNT_NSET, 0); } else { set_freq(freq); rstclock(EVNT_FSET, 0); } #endif /* LOCKCLOCK */ break; /* * Disable the kernel at shutdown. The microkernel just abandons * ship. The nanokernel carefully cleans up so applications can * see this. Note the last programmed offset and frequency are * left in place. */ case LOOP_KERN_CLEAR: #ifndef LOCKCLOCK #ifdef KERNEL_PLL if (pll_control && kern_enable) { memset((char *)&ntv, 0, sizeof(ntv)); ntv.modes = MOD_STATUS; ntv.status = STA_UNSYNC; ntp_adjtime(&ntv); report_event(EVNT_KERN, NULL, "kernel time sync disabledx"); } #endif /* KERNEL_PLL */ #endif /* LOCKCLOCK */ break; /* * Tinker command variables for Ulrich Windl. Very dangerous. */ case LOOP_ALLAN: /* Allan intercept (log2) (allan) */ allan_xpt = (u_char)freq; break; case LOOP_CODEC: /* audio codec frequency (codec) */ clock_codec = freq / 1e6; break; case LOOP_PHI: /* dispersion threshold (dispersion) */ clock_phi = freq / 1e6; break; case LOOP_FREQ: /* initial frequency (freq) */ set_freq(freq / 1e6); rstclock(EVNT_FSET, 0); break; case LOOP_HUFFPUFF: /* huff-n'-puff length (huffpuff) */ if (freq < HUFFPUFF) freq = HUFFPUFF; sys_hufflen = (int)(freq / HUFFPUFF); sys_huffpuff = (double *)emalloc(sizeof(double) * sys_hufflen); for (i = 0; i < sys_hufflen; i++) sys_huffpuff[i] = 1e9; sys_mindly = 1e9; break; case LOOP_PANIC: /* panic threshold (panic) */ clock_panic = freq; break; case LOOP_MAX: /* step threshold (step) */ clock_max = freq; if (clock_max == 0 || clock_max > 0.5) kern_enable = 0; break; case LOOP_MINSTEP: /* stepout threshold (stepout) */ clock_minstep = freq; break; case LOOP_LEAP: /* not used */ default: msyslog(LOG_NOTICE, "loop_config: unsupported option %d", item); } }
/* * change_logfile() * * Used to change from syslog to a logfile, or from one logfile to * another, and to reopen logfiles after forking. On systems where * ntpd forks, deals with converting relative logfile paths to * absolute (root-based) because we reopen logfiles after the current * directory has changed. */ int change_logfile( const char * fname, int leave_crumbs ) { FILE * new_file; const char * log_fname; char * abs_fname; #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) char curdir[512]; size_t cd_octets; size_t octets; #endif /* POSIX */ NTP_REQUIRE(fname != NULL); log_fname = fname; /* * In a forked child of a parent which is logging to a file * instead of syslog, syslog_file will be NULL and both * syslog_fname and syslog_abs_fname will be non-NULL. * If we are given the same filename previously opened * and it's still open, there's nothing to do here. */ if (syslog_file != NULL && syslog_fname != NULL && 0 == strcmp(syslog_fname, log_fname)) return 0; if (0 == strcmp(log_fname, "stderr")) { new_file = stderr; abs_fname = estrdup(log_fname); } else if (0 == strcmp(log_fname, "stdout")) { new_file = stdout; abs_fname = estrdup(log_fname); } else { if (syslog_fname != NULL && 0 == strcmp(log_fname, syslog_fname)) log_fname = syslog_abs_fname; #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) if (log_fname != syslog_abs_fname && DIR_SEP != log_fname[0] && 0 != strcmp(log_fname, "stderr") && 0 != strcmp(log_fname, "stdout") && NULL != getcwd(curdir, sizeof(curdir))) { cd_octets = strlen(curdir); /* trim any trailing '/' */ if (cd_octets > 1 && DIR_SEP == curdir[cd_octets - 1]) cd_octets--; octets = cd_octets; octets += 1; /* separator '/' */ octets += strlen(log_fname); octets += 1; /* NUL terminator */ abs_fname = emalloc(octets); snprintf(abs_fname, octets, "%.*s%c%s", (int)cd_octets, curdir, DIR_SEP, log_fname); } else #endif abs_fname = estrdup(log_fname); TRACE(1, ("attempting to open log %s\n", abs_fname)); new_file = fopen(abs_fname, "a"); } if (NULL == new_file) { free(abs_fname); return -1; } /* leave a pointer in the old log */ if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname)) msyslog(LOG_NOTICE, "switching logging to file %s", abs_fname); if (syslog_file != NULL && syslog_file != stderr && syslog_file != stdout && fileno(syslog_file) != fileno(new_file)) fclose(syslog_file); syslog_file = new_file; if (log_fname == syslog_abs_fname) { free(abs_fname); } else { if (syslog_abs_fname != NULL && syslog_abs_fname != syslog_fname) free(syslog_abs_fname); if (syslog_fname != NULL) free(syslog_fname); syslog_fname = estrdup(log_fname); syslog_abs_fname = abs_fname; } syslogit = FALSE; return 0; }
/* * arc_poll - called by the transmit procedure */ static void arc_poll( int unit, struct peer *peer ) { register struct arcunit *up; struct refclockproc *pp; int resync_needed; /* Should we start a resync? */ pp = peer->procptr; up = pp->unitptr; #if 0 pp->lencode = 0; memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode)); #endif #if 0 /* Flush input. */ tcflush(pp->io.fd, TCIFLUSH); #endif /* Resync if our next scheduled resync time is here or has passed. */ resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) && (up->next_resync <= current_time) ); #ifdef ARCRON_LEAPSECOND_KEEN /* Try to catch a potential leap-second insertion or deletion quickly. In addition to the normal NTP fun of clocks that don't report leap-seconds spooking their hosts, this clock does not even sample the radio sugnal the whole time, so may miss a leap-second insertion or deletion for up to a whole sample time. To try to minimise this effect, if in the first few minutes of the day immediately following a leap-second-insertion point (ie in the first hour of the first day of the first and sixth months), and if the last resync was in the previous day, and a resync is not already in progress, resync the clock immediately. */ if((possible_leap > 0) && /* Must be 00:XX 01/0{1,7}/XXXX. */ (!up->resyncing)) { /* No resync in progress yet. */ resync_needed = 1; possible_leap = -1; /* Prevent multiple resyncs. */ msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit); } #endif /* Do a resync if required... */ if(resync_needed) { /* First, reset quality value to `unknown' so we can detect */ /* when a quality message has been responded to by this */ /* being set to some other value. */ up->quality = QUALITY_UNKNOWN; /* Note that we are resyncing... */ up->resyncing = 1; /* Now actually send the resync command and an immediate poll. */ #ifdef DEBUG if(debug) { printf("arc: sending resync command (h\\r).\n"); } #endif msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit); send_slow(up, pp->io.fd, "h\r"); /* Schedule our next resync... */ up->next_resync = current_time + DEFAULT_RESYNC_TIME; /* Drop through to request time if appropriate. */ } /* If clock quality is too poor to trust, indicate a fault. */ /* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/ /* we'll cross our fingers and just hope that the thing */ /* synced so quickly we did not catch it---we'll */ /* double-check the clock is OK elsewhere. */ if( #ifdef ARCRON_KEEN (up->quality != QUALITY_UNKNOWN) && #else (up->quality == QUALITY_UNKNOWN) || #endif (up->quality < MIN_CLOCK_QUALITY_OK)) { #ifdef DEBUG if(debug) { printf("arc: clock quality %d too poor.\n", up->quality); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } /* This is the normal case: request a timestamp. */ request_time(unit, peer); }
/* * audio_init - open and initialize audio device * * This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is * believed generic and applicable to other systems with a minor twid * or two. All it does is open the device, set the buffer size (Solaris * only), preset the gain and set the input port. It assumes that the * codec sample rate (8000 Hz), precision (8 bits), number of channels * (1) and encoding (ITU-T G.711 mu-law companded) have been set by * default. */ int audio_init( const char *dname, /* device name */ int bufsiz, /* buffer size */ int unit /* device unit (0-3) */ ) { #ifdef PCM_STYLE_SOUND # define ACTL_DEV "/dev/mixer%d" char actl_dev[30]; # ifdef HAVE_STRUCT_SND_SIZE struct snd_size s_size; # endif # ifdef AIOGFMT snd_chan_param s_c_p; # endif #endif int fd; int rval; const char *actl = #ifdef PCM_STYLE_SOUND actl_dev #else "/dev/audioctl" #endif ; #ifdef PCM_STYLE_SOUND snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit); audio_config_read(unit, &actl, &dname); /* If we have values for cf_c_dev or cf_i_dev, use them. */ if (*cf_c_dev) actl = cf_c_dev; if (*cf_i_dev) dname = cf_i_dev; #endif /* * Open audio device */ fd = open(dname, O_RDWR | O_NONBLOCK, 0777); if (fd < 0) { msyslog(LOG_ERR, "audio_init: %s %m\n", dname); return (fd); } /* * Open audio control device. */ ctl_fd = open(actl, O_RDWR); if (ctl_fd < 0) { msyslog(LOG_ERR, "audio_init: invalid control device <%s>\n", actl); close(fd); return(ctl_fd); } /* * Set audio device parameters. */ #ifdef PCM_STYLE_SOUND printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz); rval = fd; # ifdef HAVE_STRUCT_SND_SIZE if (ioctl(fd, AIOGSIZE, &s_size) == -1) printf("audio_init: AIOGSIZE: %s\n", strerror(errno)); else printf("audio_init: orig: play_size %d, rec_size %d\n", s_size.play_size, s_size.rec_size); s_size.play_size = s_size.rec_size = bufsiz; printf("audio_init: want: play_size %d, rec_size %d\n", s_size.play_size, s_size.rec_size); if (ioctl(fd, AIOSSIZE, &s_size) == -1) printf("audio_init: AIOSSIZE: %s\n", strerror(errno)); else printf("audio_init: set: play_size %d, rec_size %d\n", s_size.play_size, s_size.rec_size); # endif /* HAVE_STRUCT_SND_SIZE */ # ifdef SNDCTL_DSP_SETFRAGMENT { int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */ if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno)); } # endif /* SNDCTL_DSP_SETFRAGMENT */ # ifdef AIOGFMT if (ioctl(fd, AIOGFMT, &s_c_p) == -1) printf("audio_init: AIOGFMT: %s\n", strerror(errno)); else printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n", s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format); # endif /* Grab the device and record masks */ if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno)); if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno)); /* validate and set any specified config file stuff */ if (cf_agc[0] != '\0') { int i; i = mixer_name(cf_agc, devmask); if (i >= 0) agc = MIXER_WRITE(i); else printf("input %s not in recmask %#x\n", cf_agc, recmask); } if (cf_monitor[0] != '\0') { int i; /* devmask */ i = mixer_name(cf_monitor, devmask); if (i >= 0) monitor = MIXER_WRITE(i); else printf("monitor %s not in devmask %#x\n", cf_monitor, devmask); } #else /* not PCM_STYLE_SOUND */ AUDIO_INITINFO(&info); info.play.gain = AUDIO_MAX_GAIN; info.play.port = AUDIO_SPEAKER; # ifdef HAVE_SYS_AUDIOIO_H info.record.buffer_size = bufsiz; # endif /* HAVE_SYS_AUDIOIO_H */ rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info); if (rval < 0) { msyslog(LOG_ERR, "audio: invalid control device parameters\n"); close(ctl_fd); close(fd); return(rval); } rval = fd; #endif /* not PCM_STYLE_SOUND */ return (rval); }
/* * arc_receive - receive data from the serial interface */ static void arc_receive( struct recvbuf *rbufp ) { register struct arcunit *up; struct refclockproc *pp; struct peer *peer; char c; int i, n, wday, month, flags, status; int arc_last_offset; static int quality_average = 0; static int quality_sum = 0; static int quality_polls = 0; /* * Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = pp->unitptr; /* If the command buffer is empty, and we are resyncing, insert a g\r quality request into it to poll for signal quality again. */ if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) { #ifdef DEBUG if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); } #endif send_slow(up, pp->io.fd, "g\r"); } /* The `arc_last_offset' is the offset in lastcode[] of the last byte received, and which we assume actually received the input timestamp. (When we get round to using tty_clk and it is available, we assume that we will receive the whole timecode with the trailing \r, and that that \r will be timestamped. But this assumption also works if receive the characters one-by-one.) */ arc_last_offset = pp->lencode+rbufp->recv_length - 1; /* We catch a timestamp iff: * The command code is `o' for a timestamp. * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have exactly char in the buffer (the command code) so that we only sample the first character of the timecode as our `on-time' character. * The first character in the buffer is not the echoed `\r' from the `o` command (so if we are to timestamp an `\r' it must not be first in the receive buffer with lencode==1. (Even if we had other characters following it, we probably would have a premature timestamp on the '\r'.) * We have received at least one character (I cannot imagine how it could be otherwise, but anyway...). */ c = rbufp->recv_buffer[0]; if((pp->a_lastcode[0] == 'o') && #ifndef ARCRON_MULTIPLE_SAMPLES (pp->lencode == 1) && #endif ((pp->lencode != 1) || (c != '\r')) && (arc_last_offset >= 1)) { /* Note that the timestamp should be corrected if >1 char rcvd. */ l_fp timestamp; timestamp = rbufp->recv_time; #ifdef DEBUG if(debug) { /* Show \r as `R', other non-printing char as `?'. */ printf("arc: stamp -->%c<-- (%d chars rcvd)\n", ((c == '\r') ? 'R' : (isgraph((unsigned char)c) ? c : '?')), rbufp->recv_length); } #endif /* Now correct timestamp by offset of last byte received---we subtract from the receive time the delay implied by the extra characters received. Reject the input if the resulting code is too long, but allow for the trailing \r, normally not used but a good handle for tty_clk or somesuch kernel timestamper. */ if(arc_last_offset > LENARC) { #ifdef DEBUG if(debug) { printf("arc: input code too long (%d cf %d); rejected.\n", arc_last_offset, LENARC); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } L_SUBUF(×tamp, charoffsets[arc_last_offset]); #ifdef DEBUG if(debug > 1) { printf( "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", ((rbufp->recv_length > 1) ? "*** " : ""), rbufp->recv_length, arc_last_offset, mfptoms((unsigned long)0, charoffsets[arc_last_offset], 1)); } #endif #ifdef ARCRON_MULTIPLE_SAMPLES /* If taking multiple samples, capture the current adjusted sample iff: * No timestamp has yet been captured (it is zero), OR * This adjusted timestamp is earlier than the one already captured, on the grounds that this one suffered less delay in being delivered to us and is more accurate. */ if(L_ISZERO(&(up->lastrec)) || L_ISGEQ(&(up->lastrec), ×tamp)) #endif { #ifdef DEBUG if(debug > 1) { printf("arc: system timestamp captured.\n"); #ifdef ARCRON_MULTIPLE_SAMPLES if(!L_ISZERO(&(up->lastrec))) { l_fp diff; diff = up->lastrec; L_SUB(&diff, ×tamp); printf("arc: adjusted timestamp by -%sms.\n", mfptoms(diff.l_i, diff.l_f, 3)); } #endif } #endif up->lastrec = timestamp; } } /* Just in case we still have lots of rubbish in the buffer... */ /* ...and to avoid the same timestamp being reused by mistake, */ /* eg on receipt of the \r coming in on its own after the */ /* timecode. */ if(pp->lencode >= LENARC) { #ifdef DEBUG if(debug && (rbufp->recv_buffer[0] != '\r')) { printf("arc: rubbish in pp->a_lastcode[].\n"); } #endif pp->lencode = 0; return; } /* Append input to code buffer, avoiding overflow. */ for(i = 0; i < rbufp->recv_length; i++) { if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */ c = rbufp->recv_buffer[i]; /* Drop trailing '\r's and drop `h' command echo totally. */ if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; } /* If we've just put an `o' in the lastcode[0], clear the timestamp in anticipation of a timecode arriving soon. We would expect to get to process this before any of the timecode arrives. */ if((c == 'o') && (pp->lencode == 1)) { L_CLR(&(up->lastrec)); #ifdef DEBUG if(debug > 1) { printf("arc: clearing timestamp.\n"); } #endif } } if (pp->lencode == 0) return; /* Handle a quality message. */ if(pp->a_lastcode[0] == 'g') { int r, q; if(pp->lencode < 3) { return; } /* Need more data... */ r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */ q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */ if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || ((r & 0x70) != 0x30)) { /* Badly formatted response. */ #ifdef DEBUG if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); } #endif return; } if(r == '3') { /* Only use quality value whilst sync in progress. */ if (up->quality_stamp < current_time) { struct calendar cal; l_fp new_stamp; get_systime (&new_stamp); caljulian (new_stamp.l_ui, &cal); up->quality_stamp = current_time + 60 - cal.second + 5; quality_sum = 0; quality_polls = 0; } quality_sum += (q & 0xf); quality_polls++; quality_average = (quality_sum / quality_polls); #ifdef DEBUG if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); } #endif } else if( /* (r == '2') && */ up->resyncing) { up->quality = quality_average; #ifdef DEBUG if(debug) { printf("arc: sync finished, signal quality %d: %s\n", up->quality, quality_action(up->quality)); } #endif msyslog(LOG_NOTICE, "ARCRON: sync finished, signal quality %d: %s", up->quality, quality_action(up->quality)); up->resyncing = 0; /* Resync is over. */ quality_average = 0; quality_sum = 0; quality_polls = 0; #ifdef ARCRON_KEEN /* Clock quality dubious; resync earlier than usual. */ if((up->quality == QUALITY_UNKNOWN) || (up->quality < MIN_CLOCK_QUALITY_OK)) { up->next_resync = current_time + RETRY_RESYNC_TIME; } #endif } pp->lencode = 0; return; } /* Stop now if this is not a timecode message. */ if(pp->a_lastcode[0] != 'o') { pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } /* If we don't have enough data, wait for more... */ if(pp->lencode < LENARC) { return; } /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ #ifdef DEBUG if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); } #endif /* But check that we actually captured a system timestamp on it. */ if(L_ISZERO(&(up->lastrec))) { #ifdef DEBUG if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } /* Append a mark of the clock's received signal quality for the benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown' quality value to `6' for his s/w) and terminate the string for sure. This should not go off the buffer end. */ pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? '6' : ('0' + up->quality)); pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ #ifdef PRE_NTP420 /* We don't use the micro-/milli- second part... */ pp->usec = 0; pp->msec = 0; #else /* We don't use the nano-second part... */ pp->nsec = 0; #endif /* Validate format and numbers. */ if (pp->a_lastcode[0] != 'o' || !get2(pp->a_lastcode + 1, &pp->hour) || !get2(pp->a_lastcode + 3, &pp->minute) || !get2(pp->a_lastcode + 5, &pp->second) || !get1(pp->a_lastcode + 7, &wday) || !get2(pp->a_lastcode + 8, &pp->day) || !get2(pp->a_lastcode + 10, &month) || !get2(pp->a_lastcode + 12, &pp->year)) { #ifdef DEBUG /* Would expect to have caught major problems already... */ if(debug) { printf("arc: badly formatted data.\n"); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } flags = pp->a_lastcode[14]; status = pp->a_lastcode[15]; #ifdef DEBUG if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); } #endif n = 9; /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (wday < 1) || (wday > 7) || (pp->day < 1) || (pp->day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } if(peer->MODE == 0) { /* compatiblity to original version */ int bst = flags; /* Check that BST/UTC bits are the complement of one another. */ if(!(bst & 2) == !(bst & 4)) { pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } } if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); } /* Year-2000 alert! */ /* Attempt to wrap 2-digit date into sensible window. */ if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* Y2KFixes */ pp->year += 1900; /* use full four-digit year */ /* Y2KFixes */ /* Attempt to do the right thing by screaming that the code will soon break when we get to the end of its useful life. What a hero I am... PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X! */ if(pp->year >= YEAR_PIVOT+2000-2 ) { /* Y2KFixes */ /*This should get attention B^> */ msyslog(LOG_NOTICE, "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!"); } #ifdef DEBUG if(debug) { printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n", n, pp->hour, pp->minute, pp->second, pp->day, month, pp->year, flags, status); } #endif /* The status value tested for is not strictly supported by the clock spec since the value of bit 2 (0x4) is claimed to be undefined for MSF, yet does seem to indicate if the last resync was successful or not. */ pp->leap = LEAP_NOWARNING; status &= 0x7; if(status == 0x3) { if(status != up->status) { msyslog(LOG_NOTICE, "ARCRON: signal acquired"); } } else { if(status != up->status) { msyslog(LOG_NOTICE, "ARCRON: signal lost"); pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */ up->status = status; pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } } up->status = status; if (peer->MODE == 0) { /* compatiblity to original version */ int bst = flags; pp->day += moff[month - 1]; if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */ /* Convert to UTC if required */ if(bst & 2) { pp->hour--; if (pp->hour < 0) { pp->hour = 23; pp->day--; /* If we try to wrap round the year * (BST on 1st Jan), reject.*/ if(pp->day < 0) { pp->lencode = 0; refclock_report(peer, CEVNT_BADTIME); return; } } } } if(peer->MODE > 0) { if(pp->sloppyclockflag & CLK_FLAG1) { struct tm local; struct tm *gmtp; time_t unixtime; /* * Convert to GMT for sites that distribute localtime. * This means we have to do Y2K conversion on the * 2-digit year; otherwise, we get the time wrong. */ memset(&local, 0, sizeof(local)); local.tm_year = pp->year-1900; local.tm_mon = month-1; local.tm_mday = pp->day; local.tm_hour = pp->hour; local.tm_min = pp->minute; local.tm_sec = pp->second; switch (peer->MODE) { case 1: local.tm_isdst = (flags & 2); break; case 2: local.tm_isdst = (flags & 2); break; case 3: switch (flags & 3) { case 0: /* It is unclear exactly when the Arcron changes from DST->ST and ST->DST. Testing has shown this to be irregular. For the time being, let the OS decide. */ local.tm_isdst = 0; #ifdef DEBUG if (debug) printf ("arc: DST = 00 (0)\n"); #endif break; case 1: /* dst->st time */ local.tm_isdst = -1; #ifdef DEBUG if (debug) printf ("arc: DST = 01 (1)\n"); #endif break; case 2: /* st->dst time */ local.tm_isdst = -1; #ifdef DEBUG if (debug) printf ("arc: DST = 10 (2)\n"); #endif break; case 3: /* dst time */ local.tm_isdst = 1; #ifdef DEBUG if (debug) printf ("arc: DST = 11 (3)\n"); #endif break; } break; default: msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); return; break; } unixtime = mktime (&local); if ((gmtp = gmtime (&unixtime)) == NULL) { pp->lencode = 0; refclock_report (peer, CEVNT_FAULT); return; } pp->year = gmtp->tm_year+1900; month = gmtp->tm_mon+1; pp->day = ymd2yd(pp->year,month,gmtp->tm_mday); /* pp->day = gmtp->tm_yday; */ pp->hour = gmtp->tm_hour; pp->minute = gmtp->tm_min; pp->second = gmtp->tm_sec; #ifdef DEBUG if (debug) { printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", pp->year,month,gmtp->tm_mday,pp->hour,pp->minute, pp->second); } #endif } else { /* * For more rational sites distributing UTC */ pp->day = ymd2yd(pp->year,month,pp->day); } } if (peer->MODE == 0) { /* compatiblity to original version */ /* If clock signal quality is * unknown, revert to default PRECISION...*/ if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } else { /* ...else improve precision if flag3 is set... */ peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } } else { if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) { peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } else if (up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } else { peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } } /* Notice and log any change (eg from initial defaults) for flags. */ if(up->saved_flags != pp->sloppyclockflag) { #ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."), ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); /* Note effects of flags changing... */ if(debug) { printf("arc: PRECISION = %d.\n", peer->precision); } #endif up->saved_flags = pp->sloppyclockflag; } /* Note time of last believable timestamp. */ pp->lastrec = up->lastrec; #ifdef ARCRON_LEAPSECOND_KEEN /* Find out if a leap-second might just have happened... (ie is this the first hour of the first day of Jan or Jul?) */ if((pp->hour == 0) && (pp->day == 1) && ((month == 1) || (month == 7))) { if(possible_leap >= 0) { /* A leap may have happened, and no resync has started yet...*/ possible_leap = 1; } } else { /* Definitely not leap-second territory... */ possible_leap = 0; } #endif if (!refclock_process(pp)) { pp->lencode = 0; refclock_report(peer, CEVNT_BADTIME); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); }
/* * audio_gain - adjust codec gains and port */ int audio_gain( int gain, /* volume level (gain) 0-255 */ int mongain, /* input to output mix (monitor gain) 0-255 */ int port /* selected I/O port: 1 mic/2 line in */ ) { int rval; static int o_mongain = -1; static int o_port = -1; #ifdef PCM_STYLE_SOUND int l, r; rval = 0; r = l = 100 * gain / 255; /* Normalize to 0-100 */ # ifdef DEBUG if (debug > 1) printf("audio_gain: gain %d/%d\n", gain, l); # endif #if 0 /* not a good idea to do this; connector wiring dependency */ /* figure out what channel(s) to use. just nuke right for now. */ r = 0 ; /* setting to zero nicely mutes the channel */ #endif l |= r << 8; if (cf_agc[0] != '\0') rval = ioctl(ctl_fd, agc, &l); else if (2 == port) rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_LINE, &l); else rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_MIC, &l); if (-1 == rval) { printf("audio_gain: agc write: %s\n", strerror(errno)); return rval; } if (o_mongain != mongain) { r = l = 100 * mongain / 255; /* Normalize to 0-100 */ # ifdef DEBUG if (debug > 1) printf("audio_gain: mongain %d/%d\n", mongain, l); # endif l |= r << 8; if (cf_monitor[0] != '\0') rval = ioctl(ctl_fd, monitor, &l ); else rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME, &l); if (-1 == rval) { printf("audio_gain: mongain write: %s\n", strerror(errno)); return (rval); } o_mongain = mongain; } if (o_port != port) { # ifdef DEBUG if (debug > 1) printf("audio_gain: port %d\n", port); # endif l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC)); rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l); if (rval == -1) { printf("SOUND_MIXER_WRITE_RECSRC: %s\n", strerror(errno)); return (rval); } # ifdef DEBUG if (debug > 1) { if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1) printf("SOUND_MIXER_WRITE_RECSRC: %s\n", strerror(errno)); else printf("audio_gain: recsrc is %d\n", l); } # endif o_port = port; } #else /* not PCM_STYLE_SOUND */ ioctl(ctl_fd, (int)AUDIO_GETINFO, (char *)&info); info.record.encoding = AUDIO_ENCODING_ULAW; info.record.error = 0; info.record.gain = gain; if (o_mongain != mongain) o_mongain = info.monitor_gain = mongain; if (o_port != port) o_port = info.record.port = port; rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info); if (rval < 0) { msyslog(LOG_ERR, "audio_gain: %m"); return (rval); } rval = info.record.error; #endif /* not PCM_STYLE_SOUND */ return (rval); }
static int neoclock4x_start(int unit, struct peer *peer) { struct neoclock4x_unit *up; struct refclockproc *pp; int fd; char dev[20]; int sl232; #if defined(HAVE_TERMIOS) struct termios termsettings; #endif #if !defined(NEOCLOCK4X_FIRMWARE) int tries; #endif (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit); /* LDISC_STD, LDISC_RAW * Open serial port. Use CLK line discipline, if available. */ fd = refclock_open(dev, B2400, LDISC_STD); if(fd <= 0) { return (0); } #if defined(HAVE_TERMIOS) #if 1 if(tcgetattr(fd, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); (void) close(fd); return (0); } /* 2400 Baud 8N2 */ termsettings.c_iflag = IGNBRK | IGNPAR | ICRNL; termsettings.c_oflag = 0; termsettings.c_cflag = CS8 | CSTOPB | CLOCAL | CREAD; (void)cfsetispeed(&termsettings, (u_int)B2400); (void)cfsetospeed(&termsettings, (u_int)B2400); if(tcsetattr(fd, TCSANOW, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); (void) close(fd); return (0); } #else if(tcgetattr(fd, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit); (void) close(fd); return (0); } /* 2400 Baud 8N2 */ termsettings.c_cflag &= ~PARENB; termsettings.c_cflag |= CSTOPB; termsettings.c_cflag &= ~CSIZE; termsettings.c_cflag |= CS8; if(tcsetattr(fd, TCSANOW, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit); (void) close(fd); return (0); } #endif #elif defined(HAVE_SYSV_TTYS) if(ioctl(fd, TCGETA, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit); (void) close(fd); return (0); } /* 2400 Baud 8N2 */ termsettings.c_cflag &= ~PARENB; termsettings.c_cflag |= CSTOPB; termsettings.c_cflag &= ~CSIZE; termsettings.c_cflag |= CS8; if(ioctl(fd, TCSETA, &termsettings) < 0) { msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit); (void) close(fd); return (0); } #else msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit); (void) close(fd); return (0); #endif #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) /* turn on RTS, and DTR for power supply */ /* NeoClock4x is powered from serial line */ if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1) { msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit); (void) close(fd); return (0); } #ifdef TIOCM_RTS sl232 = sl232 | TIOCM_DTR | TIOCM_RTS; /* turn on RTS, and DTR for power supply */ #else sl232 = sl232 | CIOCM_DTR | CIOCM_RTS; /* turn on RTS, and DTR for power supply */ #endif if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) { msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit); (void) close(fd); return (0); } #else msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!", unit); (void) close(fd); return (0); #endif up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit)); if(!(up)) { msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit); (void) close(fd); return (0); } memset((char *)up, 0, sizeof(struct neoclock4x_unit)); pp = peer->procptr; pp->clockdesc = "NeoClock4X"; pp->unitptr = up; pp->io.clock_recv = neoclock4x_receive; pp->io.srcclock = peer; pp->io.datalen = 0; pp->io.fd = fd; /* * no fudge time is given by user! * use 169.583333 ms to compensate the serial line delay * formula is: * 2400 Baud / 11 bit = 218.18 charaters per second * (NeoClock4X timecode len) */ pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0; /* * Initialize miscellaneous variables */ peer->precision = -10; memcpy((char *)&pp->refid, "neol", 4); up->leap_status = 0; up->unit = unit; strlcpy(up->firmware, "?", sizeof(up->firmware)); up->firmwaretag = '?'; strlcpy(up->serial, "?", sizeof(up->serial)); strlcpy(up->radiosignal, "?", sizeof(up->radiosignal)); up->timesource = '?'; up->dststatus = '?'; up->quarzstatus = '?'; up->antenna1 = -1; up->antenna2 = -1; up->utc_year = 0; up->utc_month = 0; up->utc_day = 0; up->utc_hour = 0; up->utc_minute = 0; up->utc_second = 0; up->utc_msec = 0; #if defined(NEOCLOCK4X_FIRMWARE) #if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A strlcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)", sizeof(up->firmware)); up->firmwaretag = 'A'; #else msyslog(LOG_EMERG, "NeoClock4X(%d): unknown firmware defined at compile time for NeoClock4X", unit); (void) close(fd); pp->io.fd = -1; free(pp->unitptr); pp->unitptr = NULL; return (0); #endif #else for(tries=0; tries < 5; tries++) { NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries); /* wait 3 seconds for receiver to power up */ sleep(3); if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware))) { break; } } /* can I handle this firmware version? */ if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag)) { (void) close(fd); pp->io.fd = -1; free(pp->unitptr); pp->unitptr = NULL; return (0); } #endif if(!io_addclock(&pp->io)) { msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit); (void) close(fd); pp->io.fd = -1; free(pp->unitptr); pp->unitptr = NULL; return (0); } NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit); return (1); }
int handle_pkt ( int rpktl, struct pkt *rpkt, struct addrinfo *host ) { struct timeval tv_dst; int sw_case, digits; char *hostname = NULL, *ref, *ts_str = NULL; double offset, precision, root_dispersion; char addr_buf[INET6_ADDRSTRLEN]; char *p_SNTP_PRETEND_TIME; time_t pretend_time; if(rpktl > 0) sw_case = 1; else sw_case = rpktl; switch(sw_case) { case SERVER_UNUSEABLE: return -1; break; case PACKET_UNUSEABLE: break; case SERVER_AUTH_FAIL: break; case KOD_DEMOBILIZE: /* Received a DENY or RESTR KOD packet */ hostname = addrinfo_to_str(host); ref = (char *)&rpkt->refid; add_entry(hostname, ref); if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp handle_pkt: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n", ref[0], ref[1], ref[2], ref[3], hostname); msyslog(LOG_WARNING, "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections", ref[0], ref[1], ref[2], ref[3], hostname); break; case KOD_RATE: /* Hmm... probably we should sleep a bit here */ break; case 1: if (ENABLED_OPT(NORMALVERBOSE)) { getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); printf("sntp handle_pkt: Received %i bytes from %s\n", rpktl, addr_buf); } GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL); p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME"); if (p_SNTP_PRETEND_TIME) { #if SIZEOF_TIME_T == 4 sscanf(p_SNTP_PRETEND_TIME, "%ld", &pretend_time); #elif SIZEOF_TIME_T == 8 sscanf(p_SNTP_PRETEND_TIME, "%lld", &pretend_time); #else # include "GRONK: unexpected value for SIZEOF_TIME_T" #endif tv_dst.tv_sec = pretend_time; } offset_calculation(rpkt, rpktl, &tv_dst, &offset, &precision, &root_dispersion); for (digits = 0; (precision *= 10.) < 1.; ++digits) /* empty */ ; if (digits > 6) digits = 6; ts_str = tv_to_str(&tv_dst); printf("%s ", ts_str); if (offset > 0) printf("+"); printf("%.*f", digits, offset); if (root_dispersion > 0.) printf(" +/- %f secs", root_dispersion); printf("\n"); free(ts_str); if (p_SNTP_PRETEND_TIME) return 0; if (ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME)) return set_time(offset); return 0; } return 1; }
static void neoclock4x_control(int unit, const struct refclockstat *in, struct refclockstat *out, struct peer *peer) { struct neoclock4x_unit *up; struct refclockproc *pp; if(NULL == peer) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } pp = peer->procptr; if(NULL == pp) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } up = pp->unitptr; if(NULL == up) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } if(NULL != in) { /* check to see if a user supplied time offset is given */ if(in->haveflags & CLK_HAVETIME1) { pp->fudgetime1 = in->fudgetime1; NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.", unit, pp->fudgetime1); } /* notify */ if(pp->sloppyclockflag & CLK_FLAG1) { NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit); } else { NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit); } } if(NULL != out) { char *tt; char tmpbuf[80]; out->kv_list = (struct ctl_var *)0; out->type = REFCLK_NEOCLOCK4X; snprintf(tmpbuf, sizeof(tmpbuf)-1, "%04d-%02d-%02d %02d:%02d:%02d.%03d", up->utc_year, up->utc_month, up->utc_day, up->utc_hour, up->utc_minute, up->utc_second, up->utc_msec); tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF); snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2); tt = add_var(&out->kv_list, 40, RO|DEF); if('A' == up->timesource) snprintf(tt, 39, "timesource=\"radio\""); else if('C' == up->timesource) snprintf(tt, 39, "timesource=\"quartz\""); else snprintf(tt, 39, "timesource=\"unknown\""); tt = add_var(&out->kv_list, 40, RO|DEF); if('I' == up->quarzstatus) snprintf(tt, 39, "quartzstatus=\"synchronized\""); else if('X' == up->quarzstatus) snprintf(tt, 39, "quartzstatus=\"not synchronized\""); else snprintf(tt, 39, "quartzstatus=\"unknown\""); tt = add_var(&out->kv_list, 40, RO|DEF); if('S' == up->dststatus) snprintf(tt, 39, "dststatus=\"summer\""); else if('W' == up->dststatus) snprintf(tt, 39, "dststatus=\"winter\""); else snprintf(tt, 39, "dststatus=\"unknown\""); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "firmware=\"%s\"", up->firmware); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "serialnumber=\"%s\"", up->serial); } }
/* * The actual main function. */ int sntp_main ( int argc, char **argv ) { register int c; struct kod_entry *reason = NULL; int optct; /* boolean, u_int quiets gcc4 signed overflow warning */ u_int sync_data_suc; struct addrinfo **bcastaddr = NULL; struct addrinfo **resh = NULL; struct addrinfo *ai; int resc; int kodc; int ow_ret; int bcast = 0; char *hostname; optct = optionProcess(&sntpOptions, argc, argv); argc -= optct; argv += optct; /* Initialize logging system */ init_logging(); if (HAVE_OPT(LOGFILE)) open_logfile(OPT_ARG(LOGFILE)); msyslog(LOG_NOTICE, "Started sntp"); /* IPv6 available? */ if (isc_net_probeipv6() != ISC_R_SUCCESS) { ai_fam_pref = AF_INET; #ifdef DEBUG printf("No ipv6 support available, forcing ipv4\n"); #endif } else { /* Check for options -4 and -6 */ if (HAVE_OPT(IPV4)) ai_fam_pref = AF_INET; else if (HAVE_OPT(IPV6)) ai_fam_pref = AF_INET6; } /* Parse config file if declared TODO */ /* * If there's a specified KOD file init KOD system. If not use * default file. For embedded systems with no writable * filesystem, -K /dev/null can be used to disable KoD storage. */ if (HAVE_OPT(KOD)) kod_init_kod_db(OPT_ARG(KOD)); else kod_init_kod_db("/var/db/ntp-kod"); if (HAVE_OPT(KEYFILE)) auth_init(OPT_ARG(KEYFILE), &keys); #ifdef EXERCISE_KOD_DB add_entry("192.168.169.170", "DENY"); add_entry("192.168.169.171", "DENY"); add_entry("192.168.169.172", "DENY"); add_entry("192.168.169.173", "DENY"); add_entry("192.168.169.174", "DENY"); delete_entry("192.168.169.174", "DENY"); delete_entry("192.168.169.172", "DENY"); delete_entry("192.168.169.170", "DENY"); if ((kodc = search_entry("192.168.169.173", &reason)) == 0) printf("entry for 192.168.169.173 not found but should have been!\n"); else free(reason); #endif /* Considering employing a variable that prevents functions of doing anything until * everything is initialized properly */ resc = resolve_hosts((const char **)argv, argc, &resh, ai_fam_pref); if (resc < 1) { printf("Unable to resolve hostname(s)\n"); return -1; } bcast = ENABLED_OPT(BROADCAST); if (bcast) { const char * myargv[2]; myargv[0] = OPT_ARG(BROADCAST); myargv[1] = NULL; bcast = resolve_hosts(myargv, 1, &bcastaddr, ai_fam_pref); } /* Select a certain ntp server according to simple criteria? For now * let's just pay attention to previous KoDs. */ sync_data_suc = FALSE; for (c = 0; c < resc && !sync_data_suc; c++) { ai = resh[c]; do { hostname = addrinfo_to_str(ai); if ((kodc = search_entry(hostname, &reason)) == 0) { if (is_reachable(ai)) { ow_ret = on_wire(ai, bcast ? bcastaddr[0] : NULL); if (0 == ow_ret) sync_data_suc = TRUE; } } else { printf("%d prior KoD%s for %s, skipping.\n", kodc, (kodc > 1) ? "s" : "", hostname); free(reason); } free(hostname); ai = ai->ai_next; } while (NULL != ai); freeaddrinfo(resh[c]); } free(resh); if (!sync_data_suc) return 1; return 0; }
/* * getCmdOpts - get command line options */ void getCmdOpts( int argc, char *argv[] ) { extern const char *config_file; int errflg; tOptions *myOptions = &ntpdOptions; /* * Initialize, initialize */ errflg = 0; if (HAVE_OPT( IPV4 )) default_ai_family = AF_INET; else if (HAVE_OPT( IPV6 )) default_ai_family = AF_INET6; if (HAVE_OPT( AUTHREQ )) proto_config(PROTO_AUTHENTICATE, 1, 0., NULL); else if (HAVE_OPT( AUTHNOREQ )) proto_config(PROTO_AUTHENTICATE, 0, 0., NULL); if (HAVE_OPT( BCASTSYNC )) proto_config(PROTO_BROADCLIENT, 1, 0., NULL); if (HAVE_OPT( CONFIGFILE )) { config_file = OPT_ARG( CONFIGFILE ); #ifdef HAVE_NETINFO check_netinfo = 0; #endif } if (HAVE_OPT( DRIFTFILE )) stats_config(STATS_FREQ_FILE, OPT_ARG( DRIFTFILE )); if (HAVE_OPT( PANICGATE )) allow_panic = TRUE; #ifdef HAVE_DROPROOT if (HAVE_OPT( JAILDIR )) { droproot = 1; chrootdir = OPT_ARG( JAILDIR ); } #endif if (HAVE_OPT( KEYFILE )) getauthkeys(OPT_ARG( KEYFILE )); if (HAVE_OPT( PIDFILE )) stats_config(STATS_PID_FILE, OPT_ARG( PIDFILE )); if (HAVE_OPT( QUIT )) mode_ntpdate = TRUE; if (HAVE_OPT( PROPAGATIONDELAY )) do { double tmp; const char *my_ntp_optarg = OPT_ARG( PROPAGATIONDELAY ); if (sscanf(my_ntp_optarg, "%lf", &tmp) != 1) { msyslog(LOG_ERR, "command line broadcast delay value %s undecodable", my_ntp_optarg); } else { proto_config(PROTO_BROADDELAY, 0, tmp, NULL); } } while (0); if (HAVE_OPT( STATSDIR )) stats_config(STATS_STATSDIR, OPT_ARG( STATSDIR )); if (HAVE_OPT( TRUSTEDKEY )) { int ct = STACKCT_OPT( TRUSTEDKEY ); const char** pp = STACKLST_OPT( TRUSTEDKEY ); do { u_long tkey; const char* p = *pp++; tkey = (int)atol(p); if (tkey == 0 || tkey > NTP_MAXKEY) { msyslog(LOG_ERR, "command line trusted key %s is invalid", p); } else { authtrust(tkey, 1); } } while (--ct > 0); } #ifdef HAVE_DROPROOT if (HAVE_OPT( USER )) { droproot = 1; user = estrdup(OPT_ARG( USER )); group = rindex(user, ':'); if (group) *group++ = '\0'; /* get rid of the ':' */ } #endif if (HAVE_OPT( VAR )) { int ct = STACKCT_OPT( VAR ); const char** pp = STACKLST_OPT( VAR ); do { const char* my_ntp_optarg = *pp++; set_sys_var(my_ntp_optarg, strlen(my_ntp_optarg)+1, (u_short) (RW)); } while (--ct > 0); } if (HAVE_OPT( DVAR )) { int ct = STACKCT_OPT( DVAR ); const char** pp = STACKLST_OPT( DVAR ); do { const char* my_ntp_optarg = *pp++; set_sys_var(my_ntp_optarg, strlen(my_ntp_optarg)+1, (u_short) (RW | DEF)); } while (--ct > 0); } if (HAVE_OPT( SLEW )) { clock_max = 600; kern_enable = 0; } if (HAVE_OPT( UPDATEINTERVAL )) { long val = OPT_VALUE_UPDATEINTERVAL; if (val >= 0) interface_interval = val; else { fprintf(stderr, "command line interface update interval %ld must not be negative\n", val); msyslog(LOG_ERR, "command line interface update interval %ld must not be negative", val); errflg++; } } #ifdef SIM /* SK: * The simulator no longer takes any command line arguments. Hence, * all the code that was here has been removed. */ #endif /* SIM */ if (errflg || argc) { if (argc) fprintf(stderr, "argc after processing is <%d>\n", argc); optionUsage(myOptions, 2); } return; }
/* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */ int on_wire ( struct addrinfo *host, struct addrinfo *bcast ) { char addr_buf[INET6_ADDRSTRLEN]; register int try; SOCKET sock; struct key *pkt_key = NULL; int key_id = 0; struct timeval tv_xmt; struct pkt x_pkt; int error, rpktl, handle_pkt_res; if (ENABLED_OPT(AUTHENTICATION)) { key_id = (int) OPT_ARG(AUTHENTICATION); get_key(key_id, &pkt_key); } for (try=0; try<5; try++) { memset(&r_pkt, 0, sizeof rbuf); error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL); tv_xmt.tv_sec += JAN_1970; #ifdef DEBUG printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec, (unsigned int) tv_xmt.tv_usec); #endif if (bcast) { create_socket(&sock, (sockaddr_u *)bcast->ai_addr); rpktl = recv_bcst_pkt(sock, &r_pkt, sizeof rbuf, (sockaddr_u *)bcast->ai_addr); closesocket(sock); } else { int pkt_len = generate_pkt(&x_pkt, &tv_xmt, key_id, pkt_key); create_socket(&sock, (sockaddr_u *)host->ai_addr); sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, pkt_len); rpktl = recvpkt(sock, &r_pkt, sizeof rbuf, &x_pkt); closesocket(sock); } handle_pkt_res = handle_pkt(rpktl, &r_pkt, host); if (handle_pkt_res < 1) return handle_pkt_res; } getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); msyslog(LOG_DEBUG, "Received no useable packet from %s!", addr_buf); return -1; } /* Compute the 8 bits for li_vn_mode */ void set_li_vn_mode ( struct pkt *spkt, char leap, char version, char mode ) { if (leap > 3) { msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3 using max. 3"); leap = 3; } if (mode > 7) { msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3"); mode = 3; } spkt->li_vn_mode = leap << 6; spkt->li_vn_mode |= version << 3; spkt->li_vn_mode |= mode; } /* set_time corrects the local clock by offset with either settimeofday() or by default * with adjtime()/adjusttimeofday(). */ int set_time( double offset ) { struct timeval tp; if (ENABLED_OPT(SETTOD)) { GETTIMEOFDAY(&tp, NULL); tp.tv_sec += (long)offset; tp.tv_usec += 1e6 * (offset - (long)offset); NORMALIZE_TIMEVAL(tp); if (SETTIMEOFDAY(&tp, NULL) < 0) { msyslog(LOG_ERR, "Time not set: settimeofday(): %m"); return -1; } return 0; } tp.tv_sec = (long)offset; tp.tv_usec = 1e6 * (offset - (long)offset); NORMALIZE_TIMEVAL(tp); if (ADJTIMEOFDAY(&tp, NULL) < 0) { msyslog(LOG_ERR, "Time not set: adjtime(): %m"); return -1; } return 0; }
/* * Main program. Initialize us, disconnect us from the tty if necessary, * and loop waiting for I/O and/or timer expiries. */ int ntpdmain( int argc, char *argv[] ) { l_fp now; struct recvbuf *rbuf; #ifdef _AIX /* HMS: ifdef SIGDANGER? */ struct sigaction sa; #endif progname = argv[0]; initializing = 1; /* mark that we are initializing */ process_commandline_opts(&argc, &argv); init_logging(progname, 1); /* Open the log file */ char *error = NULL; if (sandbox_init("ntpd", SANDBOX_NAMED, &error) == -1) { msyslog(LOG_ERR, "sandbox_init(ntpd, SANDBOX_NAMED) failed: %s", error); sandbox_free_error(error); } #ifdef HAVE_UMASK { mode_t uv; uv = umask(0); if(uv) (void) umask(uv); else (void) umask(022); } #endif #if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */ { uid_t uid; uid = getuid(); if (uid && !HAVE_OPT( SAVECONFIGQUIT )) { msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid); printf("must be run as root, not uid %ld\n", (long)uid); exit(1); } } #endif /* getstartup(argc, argv); / * startup configuration, may set debug */ #ifdef DEBUG debug = DESC(DEBUG_LEVEL).optOccCt; DPRINTF(1, ("%s\n", Version)); #endif /* honor -l/--logfile option to log to a file */ setup_logfile(); /* * Enable the Multi-Media Timer for Windows? */ #ifdef SYS_WINNT if (HAVE_OPT( MODIFYMMTIMER )) set_mm_timer(MM_TIMER_HIRES); #endif if (HAVE_OPT( NOFORK ) || HAVE_OPT( QUIT ) #ifdef DEBUG || debug #endif || HAVE_OPT( SAVECONFIGQUIT )) nofork = 1; if (HAVE_OPT( NOVIRTUALIPS )) listen_to_virtual_ips = 0; /* * --interface, listen on specified interfaces */ if (HAVE_OPT( INTERFACE )) { int ifacect = STACKCT_OPT( INTERFACE ); const char** ifaces = STACKLST_OPT( INTERFACE ); isc_netaddr_t netaddr; while (ifacect-- > 0) { add_nic_rule( is_ip_address(*ifaces, &netaddr) ? MATCH_IFADDR : MATCH_IFNAME, *ifaces, -1, ACTION_LISTEN); ifaces++; } } if (HAVE_OPT( NICE )) priority_done = 0; #if defined(HAVE_SCHED_SETSCHEDULER) if (HAVE_OPT( PRIORITY )) { config_priority = OPT_VALUE_PRIORITY; config_priority_override = 1; priority_done = 0; } #endif #ifdef SYS_WINNT /* * Start interpolation thread, must occur before first * get_systime() */ init_winnt_time(); #endif /* * Initialize random generator and public key pair */ get_systime(&now); ntp_srandom((int)(now.l_i * now.l_uf)); #if !defined(VMS) # ifndef NODETACH /* * Detach us from the terminal. May need an #ifndef GIZMO. */ if (!nofork) { /* * Install trap handlers to log errors and assertion * failures. Default handlers print to stderr which * doesn't work if detached. */ isc_assertion_setcallback(assertion_failed); isc_error_setfatal(library_fatal_error); isc_error_setunexpected(library_unexpected_error); # ifndef SYS_WINNT # ifdef HAVE_DAEMON daemon(0, 0); # else /* not HAVE_DAEMON */ if (fork()) /* HMS: What about a -1? */ exit(0); { #if !defined(F_CLOSEM) u_long s; int max_fd; #endif /* !FCLOSEM */ if (syslog_file != NULL) { fclose(syslog_file); syslog_file = NULL; } #if defined(F_CLOSEM) /* * From 'Writing Reliable AIX Daemons,' SG24-4946-00, * by Eric Agar (saves us from doing 32767 system * calls) */ if (fcntl(0, F_CLOSEM, 0) == -1) msyslog(LOG_ERR, "ntpd: failed to close open files(): %m"); #else /* not F_CLOSEM */ # if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) max_fd = sysconf(_SC_OPEN_MAX); # else /* HAVE_SYSCONF && _SC_OPEN_MAX */ max_fd = getdtablesize(); # endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ for (s = 0; s < max_fd; s++) (void) close((int)s); #endif /* not F_CLOSEM */ (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); init_logging(progname, 0); /* we lost our logfile (if any) daemonizing */ setup_logfile(); #ifdef SYS_DOMAINOS { uid_$t puid; status_$t st; proc2_$who_am_i(&puid); proc2_$make_server(&puid, &st); } #endif /* SYS_DOMAINOS */ #if defined(HAVE_SETPGID) || defined(HAVE_SETSID) # ifdef HAVE_SETSID if (setsid() == (pid_t)-1) msyslog(LOG_ERR, "ntpd: setsid(): %m"); # else if (setpgid(0, 0) == -1) msyslog(LOG_ERR, "ntpd: setpgid(): %m"); # endif #else /* HAVE_SETPGID || HAVE_SETSID */ { # if defined(TIOCNOTTY) int fid; fid = open("/dev/tty", 2); if (fid >= 0) { (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); (void) close(fid); } # endif /* defined(TIOCNOTTY) */ # ifdef HAVE_SETPGRP_0 (void) setpgrp(); # else /* HAVE_SETPGRP_0 */ (void) setpgrp(0, getpid()); # endif /* HAVE_SETPGRP_0 */ } #endif /* HAVE_SETPGID || HAVE_SETSID */ #ifdef _AIX /* Don't get killed by low-on-memory signal. */ sa.sa_handler = catch_danger; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; (void) sigaction(SIGDANGER, &sa, NULL); #endif /* _AIX */ } # endif /* not HAVE_DAEMON */ # endif /* SYS_WINNT */ } # endif /* NODETACH */ #endif /* VMS */ #ifdef SCO5_CLOCK /* * SCO OpenServer's system clock offers much more precise timekeeping * on the base CPU than the other CPUs (for multiprocessor systems), * so we must lock to the base CPU. */ { int fd = open("/dev/at1", O_RDONLY); if (fd >= 0) { int zero = 0; if (ioctl(fd, ACPU_LOCK, &zero) < 0) msyslog(LOG_ERR, "cannot lock to base CPU: %m"); close( fd ); } /* else ... * If we can't open the device, this probably just isn't * a multiprocessor system, so we're A-OK. */ } #endif #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE) # ifdef HAVE_SETRLIMIT /* * Set the stack limit to something smaller, so that we don't lock a lot * of unused stack memory. */ { struct rlimit rl; /* HMS: must make the rlim_cur amount configurable */ if (getrlimit(RLIMIT_STACK, &rl) != -1 && (rl.rlim_cur = 50 * 4096) < rl.rlim_max) { if (setrlimit(RLIMIT_STACK, &rl) == -1) { msyslog(LOG_ERR, "Cannot adjust stack limit for mlockall: %m"); } } # ifdef RLIMIT_MEMLOCK /* * The default RLIMIT_MEMLOCK is very low on Linux systems. * Unless we increase this limit malloc calls are likely to * fail if we drop root privlege. To be useful the value * has to be larger than the largest ntpd resident set size. */ rl.rlim_cur = rl.rlim_max = 32*1024*1024; if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) { msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m"); } # endif /* RLIMIT_MEMLOCK */ } # endif /* HAVE_SETRLIMIT */ /* * lock the process into memory */ if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) msyslog(LOG_ERR, "mlockall(): %m"); #else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ # ifdef HAVE_PLOCK # ifdef PROCLOCK # ifdef _AIX /* * set the stack limit for AIX for plock(). * see get_aix_stack() for more info. */ if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0) { msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m"); } # endif /* _AIX */ /* * lock the process into memory */ if (plock(PROCLOCK) < 0) msyslog(LOG_ERR, "plock(PROCLOCK): %m"); # else /* not PROCLOCK */ # ifdef TXTLOCK /* * Lock text into ram */ if (plock(TXTLOCK) < 0) msyslog(LOG_ERR, "plock(TXTLOCK) error: %m"); # else /* not TXTLOCK */ msyslog(LOG_ERR, "plock() - don't know what to lock!"); # endif /* not TXTLOCK */ # endif /* not PROCLOCK */ # endif /* HAVE_PLOCK */ #endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */ /* * Set up signals we pay attention to locally. */ #ifdef SIGDIE1 (void) signal_no_reset(SIGDIE1, finish); #endif /* SIGDIE1 */ #ifdef SIGDIE2 (void) signal_no_reset(SIGDIE2, finish); #endif /* SIGDIE2 */ #ifdef SIGDIE3 (void) signal_no_reset(SIGDIE3, finish); #endif /* SIGDIE3 */ #ifdef SIGDIE4 (void) signal_no_reset(SIGDIE4, finish); #endif /* SIGDIE4 */ #ifdef SIGBUS (void) signal_no_reset(SIGBUS, finish); #endif /* SIGBUS */ #if !defined(SYS_WINNT) && !defined(VMS) # ifdef DEBUG (void) signal_no_reset(MOREDEBUGSIG, moredebug); (void) signal_no_reset(LESSDEBUGSIG, lessdebug); # else (void) signal_no_reset(MOREDEBUGSIG, no_debug); (void) signal_no_reset(LESSDEBUGSIG, no_debug); # endif /* DEBUG */ #endif /* !SYS_WINNT && !VMS */ /* * Set up signals we should never pay attention to. */ #if defined SIGPIPE (void) signal_no_reset(SIGPIPE, SIG_IGN); #endif /* SIGPIPE */ /* * Call the init_ routines to initialize the data structures. * * Exactly what command-line options are we expecting here? */ init_auth(); init_util(); init_restrict(); init_mon(); init_timer(); init_lib(); init_request(); init_control(); init_peer(); #ifdef REFCLOCK init_refclock(); #endif set_process_priority(); init_proto(); /* Call at high priority */ init_io(); init_loopfilter(); mon_start(MON_ON); /* monitor on by default now */ /* turn off in config if unwanted */ /* * Get the configuration. This is done in a separate module * since this will definitely be different for the gizmo board. */ getconfig(argc, argv); NLOG(NLOG_SYSINFO) /* 'if' clause for syslog */ msyslog(LOG_NOTICE, "%s", Version); report_event(EVNT_SYSRESTART, NULL, NULL); loop_config(LOOP_DRIFTCOMP, old_drift); initializing = 0; #ifdef HAVE_DROPROOT if( droproot ) { /* Drop super-user privileges and chroot now if the OS supports this */ #ifdef HAVE_LINUX_CAPABILITIES /* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */ if (prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1) { msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" ); exit(-1); } #else /* we need a user to switch to */ if (user == NULL) { msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" ); exit(-1); } #endif /* HAVE_LINUX_CAPABILITIES */ if (user != NULL) { if (isdigit((unsigned char)*user)) { sw_uid = (uid_t)strtoul(user, &endp, 0); if (*endp != '\0') goto getuser; if ((pw = getpwuid(sw_uid)) != NULL) { user = strdup(pw->pw_name); if (NULL == user) { msyslog(LOG_ERR, "strdup() failed: %m"); exit (-1); } sw_gid = pw->pw_gid; } else { errno = 0; msyslog(LOG_ERR, "Cannot find user ID %s", user); exit (-1); } } else { getuser: errno = 0; if ((pw = getpwnam(user)) != NULL) { sw_uid = pw->pw_uid; sw_gid = pw->pw_gid; } else { if (errno) msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user); else msyslog(LOG_ERR, "Cannot find user `%s'", user); exit (-1); } } } if (group != NULL) { if (isdigit((unsigned char)*group)) { sw_gid = (gid_t)strtoul(group, &endp, 0); if (*endp != '\0') goto getgroup; } else { getgroup: if ((gr = getgrnam(group)) != NULL) { sw_gid = gr->gr_gid; } else { errno = 0; msyslog(LOG_ERR, "Cannot find group `%s'", group); exit (-1); } } } if (chrootdir ) { /* make sure cwd is inside the jail: */ if (chdir(chrootdir)) { msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir); exit (-1); } if (chroot(chrootdir)) { msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir); exit (-1); } if (chdir("/")) { msyslog(LOG_ERR, "Cannot chdir() to`root after chroot(): %m"); exit (-1); } } if (user && initgroups(user, sw_gid)) { msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user); exit (-1); } if (group && setgid(sw_gid)) { msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group); exit (-1); } if (group && setegid(sw_gid)) { msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group); exit (-1); } if (user && setuid(sw_uid)) { msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user); exit (-1); } if (user && seteuid(sw_uid)) { msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user); exit (-1); } #ifndef HAVE_LINUX_CAPABILITIES /* * for now assume that the privilege to bind to privileged ports * is associated with running with uid 0 - should be refined on * ports that allow binding to NTP_PORT with uid != 0 */ disable_dynamic_updates |= (sw_uid != 0); /* also notifies routing message listener */ #endif if (disable_dynamic_updates && interface_interval) { interface_interval = 0; msyslog(LOG_INFO, "running in unprivileged mode disables dynamic interface tracking"); } #ifdef HAVE_LINUX_CAPABILITIES do { /* * We may be running under non-root uid now, but we still hold full root privileges! * We drop all of them, except for the crucial one or two: cap_sys_time and * cap_net_bind_service if doing dynamic interface tracking. */ cap_t caps; char *captext = (interface_interval) ? "cap_sys_time,cap_net_bind_service=ipe" : "cap_sys_time=ipe"; if( ! ( caps = cap_from_text( captext ) ) ) { msyslog( LOG_ERR, "cap_from_text() failed: %m" ); exit(-1); } if( cap_set_proc( caps ) == -1 ) { msyslog( LOG_ERR, "cap_set_proc() failed to drop root privileges: %m" ); exit(-1); } cap_free( caps ); } while(0); #endif /* HAVE_LINUX_CAPABILITIES */ } /* if( droproot ) */ #endif /* HAVE_DROPROOT */ /* * Use select() on all on all input fd's for unlimited * time. select() will terminate on SIGALARM or on the * reception of input. Using select() means we can't do * robust signal handling and we get a potential race * between checking for alarms and doing the select(). * Mostly harmless, I think. */ /* On VMS, I suspect that select() can't be interrupted * by a "signal" either, so I take the easy way out and * have select() time out after one second. * System clock updates really aren't time-critical, * and - lacking a hardware reference clock - I have * yet to learn about anything else that is. */ #if defined(HAVE_IO_COMPLETION_PORT) for (;;) { GetReceivedBuffers(); #else /* normal I/O */ BLOCK_IO_AND_ALARM(); was_alarmed = 0; for (;;) { # if !defined(HAVE_SIGNALED_IO) extern fd_set activefds; extern int maxactivefd; fd_set rdfdes; int nfound; # endif if (alarm_flag) /* alarmed? */ { was_alarmed = 1; alarm_flag = 0; } if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE) { /* * Nothing to do. Wait for something. */ # ifndef HAVE_SIGNALED_IO rdfdes = activefds; # if defined(VMS) || defined(SYS_VXWORKS) /* make select() wake up after one second */ { struct timeval t1; t1.tv_sec = 1; t1.tv_usec = 0; nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, (fd_set *)0, &t1); } # else nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0, (fd_set *)0, (struct timeval *)0); # endif /* VMS */ if (nfound > 0) { l_fp ts; get_systime(&ts); (void)input_handler(&ts); } else if (nfound == -1 && errno != EINTR) msyslog(LOG_ERR, "select() error: %m"); # ifdef DEBUG else if (debug > 5) msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); # endif /* DEBUG */ # else /* HAVE_SIGNALED_IO */ wait_for_signal(); # endif /* HAVE_SIGNALED_IO */ if (alarm_flag) /* alarmed? */ { was_alarmed = 1; alarm_flag = 0; } } if (was_alarmed) { UNBLOCK_IO_AND_ALARM(); /* * Out here, signals are unblocked. Call timer routine * to process expiry. */ timer(); was_alarmed = 0; BLOCK_IO_AND_ALARM(); } #endif /* ! HAVE_IO_COMPLETION_PORT */ #ifdef DEBUG_TIMING { l_fp pts; l_fp tsa, tsb; int bufcount = 0; get_systime(&pts); tsa = pts; #endif rbuf = get_full_recv_buffer(); while (rbuf != NULL) { if (alarm_flag) { was_alarmed = 1; alarm_flag = 0; } UNBLOCK_IO_AND_ALARM(); if (was_alarmed) { /* avoid timer starvation during lengthy I/O handling */ timer(); was_alarmed = 0; } /* * Call the data procedure to handle each received * packet. */ if (rbuf->receiver != NULL) /* This should always be true */ { #ifdef DEBUG_TIMING l_fp dts = pts; L_SUB(&dts, &rbuf->recv_time); DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9))); collect_timing(rbuf, "buffer processing delay", 1, &dts); bufcount++; #endif (rbuf->receiver)(rbuf); } else { msyslog(LOG_ERR, "receive buffer corruption - receiver found to be NULL - ABORTING"); abort(); } BLOCK_IO_AND_ALARM(); freerecvbuf(rbuf); rbuf = get_full_recv_buffer(); } #ifdef DEBUG_TIMING get_systime(&tsb); L_SUB(&tsb, &tsa); if (bufcount) { collect_timing(NULL, "processing", bufcount, &tsb); DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9))); } } #endif /* * Go around again */ #ifdef HAVE_DNSREGISTRATION if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) { mdnsreg = current_time; msyslog(LOG_INFO, "Attemping to register mDNS"); if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) { if (!--mdnstries) { msyslog(LOG_ERR, "Unable to register mDNS, giving up."); } else { msyslog(LOG_INFO, "Unable to register mDNS, will try later."); } } else { msyslog(LOG_INFO, "mDNS service registered."); mdnsreg = 0; } } #endif /* HAVE_DNSREGISTRATION */ } UNBLOCK_IO_AND_ALARM(); return 1; } #ifdef SIGDIE2 /* * finish - exit gracefully */ static RETSIGTYPE finish( int sig ) { msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig); #ifdef HAVE_DNSREGISTRATION if (mdns != NULL) DNSServiceRefDeallocate(mdns); #endif switch (sig) { # ifdef SIGBUS case SIGBUS: printf("\nfinish(SIGBUS)\n"); exit(0); # endif case 0: /* Should never happen... */ return; default: exit(0); } }
/* * local_clock - the NTP logical clock loop filter. * * Return codes: * -1 update ignored: exceeds panic threshold * 0 update ignored: popcorn or exceeds step threshold * 1 clock was slewed * 2 clock was stepped * * LOCKCLOCK: The only thing this routine does is set the * sys_rootdisp variable equal to the peer dispersion. */ int local_clock( struct peer *peer, /* synch source peer structure */ double fp_offset /* clock offset (s) */ ) { int rval; /* return code */ int osys_poll; /* old system poll */ double mu; /* interval since last update */ double clock_frequency; /* clock frequency */ double dtemp, etemp; /* double temps */ char tbuf[80]; /* report buffer */ /* * If the loop is opened or the NIST LOCKCLOCK is in use, * monitor and record the offsets anyway in order to determine * the open-loop response and then go home. */ #ifdef LOCKCLOCK return (0); #else /* LOCKCLOCK */ if (!ntp_enable) { record_loop_stats(fp_offset, drift_comp, clock_jitter, clock_stability, sys_poll); return (0); } /* * If the clock is way off, panic is declared. The clock_panic * defaults to 1000 s; if set to zero, the panic will never * occur. The allow_panic defaults to FALSE, so the first panic * will exit. It can be set TRUE by a command line option, in * which case the clock will be set anyway and time marches on. * But, allow_panic will be set FALSE when the update is less * than the step threshold; so, subsequent panics will exit. */ if (fabs(fp_offset) > clock_panic && clock_panic > 0 && !allow_panic) { snprintf(tbuf, sizeof(tbuf), "%+.0f s; set clock manually within %.0f s.", fp_offset, clock_panic); report_event(EVNT_SYSFAULT, NULL, tbuf); return (-1); } /* * This section simulates ntpdate. If the offset exceeds the * step threshold (128 ms), step the clock to that time and * exit. Othewise, slew the clock to that time and exit. Note * that the slew will persist and eventually complete beyond the * life of this program. Note that while ntpdate is active, the * terminal does not detach, so the termination message prints * directly to the terminal. */ if (mode_ntpdate) { if (fabs(fp_offset) > clock_max && clock_max > 0) { step_systime(fp_offset); msyslog(LOG_NOTICE, "ntpd: time set %+.6f s", fp_offset); printf("ntpd: time set %+.6fs\n", fp_offset); } else { adj_systime(fp_offset); msyslog(LOG_NOTICE, "ntpd: time slew %+.6f s", fp_offset); printf("ntpd: time slew %+.6fs\n", fp_offset); } record_loop_stats(fp_offset, drift_comp, clock_jitter, clock_stability, sys_poll); exit (0); } /* * The huff-n'-puff filter finds the lowest delay in the recent * interval. This is used to correct the offset by one-half the * difference between the sample delay and minimum delay. This * is most effective if the delays are highly assymetric and * clockhopping is avoided and the clock frequency wander is * relatively small. */ if (sys_huffpuff != NULL) { if (peer->delay < sys_huffpuff[sys_huffptr]) sys_huffpuff[sys_huffptr] = peer->delay; if (peer->delay < sys_mindly) sys_mindly = peer->delay; if (fp_offset > 0) dtemp = -(peer->delay - sys_mindly) / 2; else dtemp = (peer->delay - sys_mindly) / 2; fp_offset += dtemp; #ifdef DEBUG if (debug) printf( "local_clock: size %d mindly %.6f huffpuff %.6f\n", sys_hufflen, sys_mindly, dtemp); #endif } /* * Clock state machine transition function which defines how the * system reacts to large phase and frequency excursion. There * are two main regimes: when the offset exceeds the step * threshold (128 ms) and when it does not. Under certain * conditions updates are suspended until the stepout theshold * (900 s) is exceeded. See the documentation on how these * thresholds interact with commands and command line options. * * Note the kernel is disabled if step is disabled or greater * than 0.5 s or in ntpdate mode. */ osys_poll = sys_poll; if (sys_poll < peer->minpoll) sys_poll = peer->minpoll; if (sys_poll > peer->maxpoll) sys_poll = peer->maxpoll; mu = current_time - clock_epoch; clock_frequency = drift_comp; rval = 1; if (fabs(fp_offset) > clock_max && clock_max > 0) { switch (state) { /* * In SYNC state we ignore the first outlyer and switch * to SPIK state. */ case EVNT_SYNC: snprintf(tbuf, sizeof(tbuf), "%+.6f s", fp_offset); report_event(EVNT_SPIK, NULL, tbuf); state = EVNT_SPIK; return (0); /* * In FREQ state we ignore outlyers and inlyers. At the * first outlyer after the stepout threshold, compute * the apparent frequency correction and step the phase. */ case EVNT_FREQ: if (mu < clock_minstep) return (0); clock_frequency = direct_freq(fp_offset); /* fall through to S_SPIK */ /* * In SPIK state we ignore succeeding outlyers until * either an inlyer is found or the stepout threshold is * exceeded. */ case EVNT_SPIK: if (mu < clock_minstep) return (0); /* fall through to default */ /* * We get here by default in NSET and FSET states and * from above in FREQ or SPIK states. * * In NSET state an initial frequency correction is not * available, usually because the frequency file has not * yet been written. Since the time is outside the step * threshold, the clock is stepped. The frequency will * be set directly following the stepout interval. * * In FSET state the initial frequency has been set from * the frequency file. Since the time is outside the * step threshold, the clock is stepped immediately, * rather than after the stepout interval. Guys get * nervous if it takes 15 minutes to set the clock for * the first time. * * In FREQ and SPIK states the stepout threshold has * expired and the phase is still above the step * threshold. Note that a single spike greater than the * step threshold is always suppressed, even with a * long time constant. */ default: snprintf(tbuf, sizeof(tbuf), "%+.6f s", fp_offset); report_event(EVNT_CLOCKRESET, NULL, tbuf); step_systime(fp_offset); reinit_timer(); tc_counter = 0; clock_jitter = LOGTOD(sys_precision); rval = 2; if (state == EVNT_NSET || (current_time - last_step) < clock_minstep * 2) { rstclock(EVNT_FREQ, 0); return (rval); } last_step = current_time; break; } rstclock(EVNT_SYNC, 0); } else { /* * The offset is less than the step threshold. Calculate * the jitter as the exponentially weighted offset * differences. */ etemp = SQUARE(clock_jitter); dtemp = SQUARE(max(fabs(fp_offset - last_offset), LOGTOD(sys_precision))); clock_jitter = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG); switch (state) { /* * In NSET state this is the first update received and * the frequency has not been initialized. Adjust the * phase, but do not adjust the frequency until after * the stepout threshold. */ case EVNT_NSET: rstclock(EVNT_FREQ, fp_offset); break; /* * In FSET state this is the first update received and * the frequency has been initialized. Adjust the phase, * but do not adjust the frequency until the next * update. */ case EVNT_FSET: rstclock(EVNT_SYNC, fp_offset); break; /* * In FREQ state ignore updates until the stepout * threshold. After that, compute the new frequency, but * do not adjust the phase or frequency until the next * update. */ case EVNT_FREQ: if (mu < clock_minstep) return (0); clock_frequency = direct_freq(fp_offset); rstclock(EVNT_SYNC, 0); break; /* * We get here by default in SYNC and SPIK states. Here * we compute the frequency update due to PLL and FLL * contributions. */ default: allow_panic = FALSE; /* * The FLL and PLL frequency gain constants * depend on the time constant and Allan * intercept. The PLL is always used, but * becomes ineffective above the Allan intercept * where the FLL becomes effective. */ if (sys_poll >= allan_xpt) clock_frequency += (fp_offset - clock_offset) / max(ULOGTOD(sys_poll), mu) * CLOCK_FLL; /* * The PLL frequency gain (numerator) depends on * the minimum of the update interval and Allan * intercept. This reduces the PLL gain when the * FLL becomes effective. */ etemp = min(ULOGTOD(allan_xpt), mu); dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll); clock_frequency += fp_offset * etemp / (dtemp * dtemp); rstclock(EVNT_SYNC, fp_offset); break; } } #ifdef KERNEL_PLL /* * This code segment works when clock adjustments are made using * precision time kernel support and the ntp_adjtime() system * call. This support is available in Solaris 2.6 and later, * Digital Unix 4.0 and later, FreeBSD, Linux and specially * modified kernels for HP-UX 9 and Ultrix 4. In the case of the * DECstation 5000/240 and Alpha AXP, additional kernel * modifications provide a true microsecond clock and nanosecond * clock, respectively. * * Important note: The kernel discipline is used only if the * step threshold is less than 0.5 s, as anything higher can * lead to overflow problems. This might occur if some misguided * lad set the step threshold to something ridiculous. */ if (pll_control && kern_enable) { /* * We initialize the structure for the ntp_adjtime() * system call. We have to convert everything to * microseconds or nanoseconds first. Do not update the * system variables if the ext_enable flag is set. In * this case, the external clock driver will update the * variables, which will be read later by the local * clock driver. Afterwards, remember the time and * frequency offsets for jitter and stability values and * to update the frequency file. */ memset(&ntv, 0, sizeof(ntv)); if (ext_enable) { ntv.modes = MOD_STATUS; } else { #ifdef STA_NANO ntv.modes = MOD_BITS | MOD_NANO; #else /* STA_NANO */ ntv.modes = MOD_BITS; #endif /* STA_NANO */ if (clock_offset < 0) dtemp = -.5; else dtemp = .5; #ifdef STA_NANO ntv.offset = (int32)(clock_offset * 1e9 + dtemp); ntv.constant = sys_poll; #else /* STA_NANO */ ntv.offset = (int32)(clock_offset * 1e6 + dtemp); ntv.constant = sys_poll - 4; #endif /* STA_NANO */ ntv.esterror = (u_int32)(clock_jitter * 1e6); ntv.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); ntv.status = STA_PLL; /* * Enable/disable the PPS if requested. */ if (pps_enable) { if (!(pll_status & STA_PPSTIME)) report_event(EVNT_KERN, NULL, "PPS enabled"); ntv.status |= STA_PPSTIME | STA_PPSFREQ; } else { if (pll_status & STA_PPSTIME) report_event(EVNT_KERN, NULL, "PPS disabled"); ntv.status &= ~(STA_PPSTIME | STA_PPSFREQ); } if (sys_leap == LEAP_ADDSECOND) ntv.status |= STA_INS; else if (sys_leap == LEAP_DELSECOND) ntv.status |= STA_DEL; } /* * Pass the stuff to the kernel. If it squeals, turn off * the pps. In any case, fetch the kernel offset, * frequency and jitter. */ if (ntp_adjtime(&ntv) == TIME_ERROR) { if (!(ntv.status & STA_PPSSIGNAL)) report_event(EVNT_KERN, NULL, "PPS no signal"); } pll_status = ntv.status; #ifdef STA_NANO clock_offset = ntv.offset / 1e9; #else /* STA_NANO */ clock_offset = ntv.offset / 1e6; #endif /* STA_NANO */ clock_frequency = FREQTOD(ntv.freq); /* * If the kernel PPS is lit, monitor its performance. */ if (ntv.status & STA_PPSTIME) { #ifdef STA_NANO clock_jitter = ntv.jitter / 1e9; #else /* STA_NANO */ clock_jitter = ntv.jitter / 1e6; #endif /* STA_NANO */ } #if defined(STA_NANO) && NTP_API == 4 /* * If the TAI changes, update the kernel TAI. */ if (loop_tai != sys_tai) { loop_tai = sys_tai; ntv.modes = MOD_TAI; ntv.constant = sys_tai; ntp_adjtime(&ntv); } #endif /* STA_NANO */ } #endif /* KERNEL_PLL */ /* * Clamp the frequency within the tolerance range and calculate * the frequency difference since the last update. */ if (fabs(clock_frequency) > NTP_MAXFREQ) msyslog(LOG_NOTICE, "frequency error %.0f PPM exceeds tolerance %.0f PPM", clock_frequency * 1e6, NTP_MAXFREQ * 1e6); dtemp = SQUARE(clock_frequency - drift_comp); if (clock_frequency > NTP_MAXFREQ) drift_comp = NTP_MAXFREQ; else if (clock_frequency < -NTP_MAXFREQ) drift_comp = -NTP_MAXFREQ; else drift_comp = clock_frequency; /* * Calculate the wander as the exponentially weighted RMS * frequency differences. Record the change for the frequency * file update. */ etemp = SQUARE(clock_stability); clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG); drift_file_sw = TRUE; /* * Here we adjust the timeconstan by comparing the current * offset with the clock jitter. If the offset is less than the * clock jitter times a constant, then the averaging interval is * increased, otherwise it is decreased. A bit of hysteresis * helps calm the dance. Works best using burst mode. */ if (fabs(clock_offset) < CLOCK_PGATE * clock_jitter) { tc_counter += sys_poll; if (tc_counter > CLOCK_LIMIT) { tc_counter = CLOCK_LIMIT; if (sys_poll < peer->maxpoll) { tc_counter = 0; sys_poll++; } } } else { tc_counter -= sys_poll << 1; if (tc_counter < -CLOCK_LIMIT) { tc_counter = -CLOCK_LIMIT; if (sys_poll > peer->minpoll) { tc_counter = 0; sys_poll--; } } } /* * If the time constant has changed, update the poll variables. */ if (osys_poll != sys_poll) poll_update(peer, sys_poll); /* * Yibbidy, yibbbidy, yibbidy; that'h all folks. */ record_loop_stats(clock_offset, drift_comp, clock_jitter, clock_stability, sys_poll); #ifdef DEBUG if (debug) printf( "local_clock: offset %.9f jit %.9f freq %.3f stab %.3f poll %d\n", clock_offset, clock_jitter, drift_comp * 1e6, clock_stability * 1e6, sys_poll); #endif /* DEBUG */ return (rval); #endif /* LOCKCLOCK */ }
static void fork_blocking_child( blocking_child * c ) { static int atexit_installed; static int blocking_pipes[4] = { -1, -1, -1, -1 }; int rc; int was_pipe; int is_pipe; int saved_errno = 0; int childpid; int keep_fd; int fd; /* * parent and child communicate via a pair of pipes. * * 0 child read request * 1 parent write request * 2 parent read response * 3 child write response */ if (-1 == c->req_write_pipe) { rc = pipe_socketpair(&blocking_pipes[0], &was_pipe); if (0 != rc) { saved_errno = errno; } else { rc = pipe_socketpair(&blocking_pipes[2], &is_pipe); if (0 != rc) { saved_errno = errno; close(blocking_pipes[0]); close(blocking_pipes[1]); } else { INSIST(was_pipe == is_pipe); } } if (0 != rc) { errno = saved_errno; msyslog(LOG_ERR, "unable to create worker pipes: %m"); exit(1); } /* * Move the descriptors the parent will keep open out of the * low descriptors preferred by C runtime buffered FILE *. */ c->req_write_pipe = move_fd(blocking_pipes[1]); c->resp_read_pipe = move_fd(blocking_pipes[2]); /* * wake any worker child on orderly shutdown of the * daemon so that it can notice the broken pipes and * go away promptly. */ if (!atexit_installed) { atexit(&send_worker_home_atexit); atexit_installed = TRUE; } } #if defined(HAVE_DROPROOT) && !defined(NEED_EARLY_FORK) /* defer the fork until after root is dropped */ if (droproot && !root_dropped) return; #endif if (syslog_file != NULL) fflush(syslog_file); fflush(stdout); fflush(stderr); /* [BUG 3050] setting SIGCHLD to SIG_IGN likely causes unwanted * or undefined effects. We don't do it and leave SIGCHLD alone. */ /* signal_no_reset(SIGCHLD, SIG_IGN); */ childpid = fork(); if (-1 == childpid) { msyslog(LOG_ERR, "unable to fork worker: %m"); exit(1); } if (childpid) { /* this is the parent */ TRACE(1, ("forked worker child (pid %d)\n", childpid)); c->pid = childpid; c->ispipe = is_pipe; /* close the child's pipe descriptors. */ close(blocking_pipes[0]); close(blocking_pipes[3]); memset(blocking_pipes, -1, sizeof(blocking_pipes)); /* wire into I/O loop */ (*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE); return; /* parent returns */ } /* * The parent gets the child pid as the return value of fork(). * The child must work for it. */ c->pid = getpid(); worker_process = TRUE; /* * In the child, close all files except stdin, stdout, stderr, * and the two child ends of the pipes. */ DEBUG_INSIST(-1 == c->req_read_pipe); DEBUG_INSIST(-1 == c->resp_write_pipe); c->req_read_pipe = blocking_pipes[0]; c->resp_write_pipe = blocking_pipes[3]; kill_asyncio(0); closelog(); if (syslog_file != NULL) { fclose(syslog_file); syslog_file = NULL; syslogit = TRUE; } keep_fd = max(c->req_read_pipe, c->resp_write_pipe); for (fd = 3; fd < keep_fd; fd++) if (fd != c->req_read_pipe && fd != c->resp_write_pipe) close(fd); close_all_beyond(keep_fd); /* * We get signals from refclock serial I/O on NetBSD in the * worker if we do not reset SIGIO's handler to the default. * It is not conditionalized for NetBSD alone because on * systems where it is not needed, it is harmless, and that * allows us to handle unknown others with NetBSD behavior. * [Bug 1386] */ #if defined(USE_SIGIO) signal_no_reset(SIGIO, SIG_DFL); #elif defined(USE_SIGPOLL) signal_no_reset(SIGPOLL, SIG_DFL); #endif signal_no_reset(SIGHUP, worker_sighup); init_logging("ntp_intres", 0, FALSE); setup_logfile(NULL); /* * And now back to the portable code */ exit_worker(blocking_child_common(c)); }
static void hopfserial_receive ( struct recvbuf *rbufp ) { struct hopfclock_unit *up; struct refclockproc *pp; struct peer *peer; int synch; /* synchhronization indicator */ int DoW; /* Dow */ int day, month; /* ddd conversion */ /* * Initialize pointers and read the timecode and timestamp. */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct hopfclock_unit *)pp->unitptr; if (up->rpt_next == 0 ) return; up->rpt_next = 0; /* wait until next poll interval occur */ pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); if (pp->lencode == 0) return; sscanf(pp->a_lastcode, #if 1 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ #else "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ #endif &synch, &DoW, &pp->hour, &pp->minute, &pp->second, &day, &month, &pp->year); /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (day < 1) || (day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ refclock_report(peer, CEVNT_BADREPLY); return; } /* some preparations */ pp->day = ymd2yd(pp->year,month,day); pp->leap=0; /* Year-2000 check! */ /* wrap 2-digit date into 4-digit */ if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ pp->year += 1900; /* preparation for timecode ntpq rl command ! */ #if 0 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", synch, DoW, day, month, pp->year, pp->hour, pp->minute, pp->second); pp->lencode = strlen(pp->a_lastcode); if ((synch && 0xc) == 0 ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } #endif /* * If clock has no valid status then report error and exit */ if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } /* * Test if time is running on internal quarz * if CLK_FLAG1 is set, sychronize even if no radio operation */ if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); #if 0 msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); #endif record_clock_stats(&peer->srcadr, pp->a_lastcode); return; }