diff options
Diffstat (limited to 'contrib/ntp/ntpd/refclock_acts.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_acts.c | 906 |
1 files changed, 443 insertions, 463 deletions
diff --git a/contrib/ntp/ntpd/refclock_acts.c b/contrib/ntp/ntpd/refclock_acts.c index 57f2ca7..f62cc46 100644 --- a/contrib/ntp/ntpd/refclock_acts.c +++ b/contrib/ntp/ntpd/refclock_acts.c @@ -6,7 +6,7 @@ #include <config.h> #endif -#if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS)) +#if defined(REFCLOCK) && defined(CLOCK_ACTS) #include "ntpd.h" #include "ntp_io.h" @@ -21,6 +21,12 @@ # include <sys/ioctl.h> #endif /* HAVE_SYS_IOCTL_H */ +#ifdef SYS_WINNT +#undef write /* ports/winnt/include/config.h: #define write _write */ +extern int async_write(int, const void *, unsigned int); +#define write(fd, data, octets) async_write(fd, data, octets) +#endif + /* * This driver supports the US (NIST, USNO) and European (PTB, NPL, * etc.) modem time services, as well as Spectracom GPS and WWVB @@ -33,20 +39,19 @@ * This driver requires a modem with a Hayes-compatible command set and * control over the modem data terminal ready (DTR) control line. The * modem setup string is hard-coded in the driver and may require - * changes for nonstandard modems or special circumstances. For reasons - * unrelated to this driver, the data set ready (DSR) control line - * should not be set when this driver is first started. + * changes for nonstandard modems or special circumstances. * - * The calling program is initiated by setting fudge flag1, either - * manually or automatically. When flag1 is set, the calling program - * dials the first number in the phone command of the configuration - * file. If that call fails, the calling program dials the second number - * and so on. The number is specified by the Hayes ATDT prefix followed - * by the number itself, including the prefix and long-distance digits - * and delay code, if necessary. The flag1 is reset and the calling - * program terminated if (a) a valid clock update has been determined, - * (b) no more numbers remain in the list, (c) a device fault or timeout - * occurs or (d) fudge flag1 is reset manually. + * When enabled, the calling program dials the first number in the + * phones file. If that call fails, it dials the second number and + * so on. The phone number is specified by the Hayes ATDT prefix + * followed by the number itself, including the long-distance prefix + * and delay code, if necessary. The calling program is enabled + * when (a) fudge flag1 is set by ntpdc, (b) at each poll interval + * when no other synchronization sources are present, and (c) at each + * poll interval whether or not other synchronization sources are + * present. The calling program disconnects if (a) the called party + * is busy or does not answer, (b) the called party disconnects + * before a sufficient nuimber of timecodes have been received. * * The driver is transparent to each of the modem time services and * Spectracom radios. It selects the parsing algorithm depending on the @@ -59,18 +64,17 @@ * * flag1 force a call in manual mode * flag2 enable port locking (not verified) - * flag3 no modem; port is directly connected to device + * flag3 not used * flag4 not used * * time1 offset adjustment (s) * - * Ordinarily, the serial port is connected to a modem; however, it can - * be connected directly to a device or another computer for testing and - * calibration. In this case set fudge flag3 and the driver will send a - * single character 'T' at each poll event. In principle, fudge flag2 - * enables port locking, allowing the modem to be shared when not in use - * by this driver. At least on Solaris with the current NTP I/O - * routines, this results only in lots of ugly error messages. + * Ordinarily, the serial port is connected to a modem and the phones + * list is defined. If no phones list is defined, the port can be + * connected directly to a device or another computer. In this case the + * driver will send a single character 'T' at each poll event. If + * fudge flag2 is enabled, port locking allows the modem to be shared + * when not in use by this driver. */ /* * National Institute of Science and Technology (NIST) @@ -89,7 +93,9 @@ * * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is * the on-time markers echoed by the driver and used by NIST to measure - * and correct for the propagation delay. + * and correct for the propagation delay. Note: the ACTS timecode has + * recently been changed to eliminate the * on-time indicator. The + * reason for this and the long term implications are not clear. * * US Naval Observatory (USNO) * @@ -129,26 +135,26 @@ * Interface definitions */ #define DEVICE "/dev/acts%d" /* device name and unit */ -#define SPEED232 B9600 /* uart speed (9600 baud) */ +#define SPEED232 B19200 /* uart speed (19200 bps) */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ -#define LOCKFILE "/var/spool/locks/LCK..cua%d" +#define LOCKFILE "/var/spool/lock/LCK..cua%d" #define DESCRIPTION "Automated Computer Time Service" /* WRU */ #define REFID "NONE" /* default reference ID */ #define MSGCNT 20 /* max message count */ -#define SMAX 256 /* max clockstats line length */ +#define MAXPHONE 10 /* max number of phone numbers */ /* - * Calling program modes + * Calling program modes (mode) */ -#define MODE_AUTO 0 /* automatic mode */ -#define MODE_BACKUP 1 /* backup mode */ +#define MODE_BACKUP 0 /* backup mode */ +#define MODE_AUTO 1 /* automatic mode */ #define MODE_MANUAL 2 /* manual mode */ /* - * Service identifiers. + * Service identifiers (message length) */ #define REFACTS "NIST" /* NIST reference ID */ -#define LENACTS 50 /* NIST format */ +#define LENACTS 50 /* NIST format A */ #define REFUSNO "USNO" /* USNO reference ID */ #define LENUSNO 20 /* USNO */ #define REFPTB "PTB\0" /* PTB/NPL reference ID */ @@ -159,40 +165,41 @@ #define LF 0x0a /* ASCII LF */ /* - * Modem setup strings. These may have to be changed for some modems. + * Modem setup strings. These may have to be changed for + * some modems. * * AT command prefix * B1 US answer tone * &C0 disable carrier detect * &D2 hang up and return to command mode on DTR transition * E0 modem command echo disabled - * l1 set modem speaker volume to low level + * L1 set modem speaker volume to low level * M1 speaker enabled until carrier detect * Q0 return result codes * V1 return result codes as English words + * Y1 enable long-space disconnect */ -#define MODEM_SETUP "ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */ -#define MODEM_HANGUP "ATH\r" /* modem disconnect */ +const char def_modem_setup[] = "ATB1&C0&D2E0L1M1Q0V1Y1"; +const char *modem_setup = def_modem_setup; /* * Timeouts (all in seconds) */ #define SETUP 3 /* setup timeout */ -#define DTR 1 /* DTR timeout */ +#define REDIAL 30 /* redial timeout */ #define ANSWER 60 /* answer timeout */ -#define CONNECT 20 /* first valid message timeout */ -#define TIMECODE 30 /* all valid messages timeout */ +#define TIMECODE 60 /* message timeout */ +#define MAXCODE 20 /* max timecodes */ /* * State machine codes */ -#define S_IDLE 0 /* wait for poll */ -#define S_OK 1 /* wait for modem setup */ -#define S_DTR 2 /* wait for modem DTR */ -#define S_CONNECT 3 /* wait for answer*/ -#define S_FIRST 4 /* wait for first valid message */ -#define S_MSG 5 /* wait for all messages */ -#define S_CLOSE 6 /* wait after sending disconnect */ +typedef enum { + S_IDLE, /* wait for poll */ + S_SETUP, /* send modem setup */ + S_CONNECT, /* wait for answer */ + S_MSG /* wait for timecode */ +} teModemState; /* * Unit control structure @@ -204,26 +211,27 @@ struct actsunit { int retry; /* retry index */ int msgcnt; /* count of messages received */ l_fp tstamp; /* on-time timestamp */ - char *bufptr; /* buffer pointer */ + char *bufptr; /* next incoming char stored here */ + char buf[BMAX]; /* bufptr roams within buf[] */ }; /* * Function prototypes */ -static int acts_start P((int, struct peer *)); -static void acts_shutdown P((int, struct peer *)); -static void acts_receive P((struct recvbuf *)); -static void acts_message P((struct peer *)); -static void acts_timecode P((struct peer *, char *)); -static void acts_poll P((int, struct peer *)); -static void acts_timeout P((struct peer *)); -static void acts_disc P((struct peer *)); -static void acts_timer P((int, struct peer *)); +static int acts_start (int, struct peer *); +static void acts_shutdown (int, struct peer *); +static void acts_receive (struct recvbuf *); +static void acts_message (struct peer *, const char *); +static void acts_timecode (struct peer *, const char *); +static void acts_poll (int, struct peer *); +static void acts_timeout (struct peer *, teModemState); +static void acts_timer (int, struct peer *); +static void acts_close (struct peer *); /* * Transfer vector (conditional structure name) */ -struct refclock refclock_acts = { +struct refclock refclock_acts = { acts_start, /* start up driver */ acts_shutdown, /* shut down driver */ acts_poll, /* transmit poll message */ @@ -233,44 +241,45 @@ struct refclock refclock_acts = { acts_timer /* housekeeping timer */ }; -struct refclock refclock_ptb; - /* * Initialize data for processing */ static int -acts_start ( +acts_start( int unit, struct peer *peer ) { struct actsunit *up; struct refclockproc *pp; + const char *setup; /* * Allocate and initialize unit structure */ - up = emalloc(sizeof(struct actsunit)); - if (up == NULL) - return (0); - - memset(up, 0, sizeof(struct actsunit)); + up = emalloc_zero(sizeof(struct actsunit)); up->unit = unit; pp = peer->procptr; - pp->unitptr = (caddr_t)up; + pp->unitptr = up; pp->io.clock_recv = acts_receive; - pp->io.srcclock = (caddr_t)peer; + pp->io.srcclock = peer; pp->io.datalen = 0; + pp->io.fd = -1; /* * Initialize miscellaneous variables */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); + memcpy(&pp->refid, REFID, 4); peer->sstclktype = CTL_SST_TS_TELEPHONE; - peer->flags &= ~FLAG_FIXPOLL; - up->bufptr = pp->a_lastcode; + up->bufptr = up->buf; + if (def_modem_setup == modem_setup) { + setup = get_ext_sys_var("modemsetup"); + if (setup != NULL) + modem_setup = estrdup(setup); + } + return (1); } @@ -279,7 +288,7 @@ acts_start ( * acts_shutdown - shut down the clock */ static void -acts_shutdown ( +acts_shutdown( int unit, struct peer *peer ) @@ -291,7 +300,8 @@ acts_shutdown ( * Warning: do this only when a call is not in progress. */ pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; + up = pp->unitptr; + acts_close(peer); free(up); } @@ -300,15 +310,16 @@ acts_shutdown ( * acts_receive - receive data from the serial interface */ static void -acts_receive ( +acts_receive( struct recvbuf *rbufp ) { struct actsunit *up; struct refclockproc *pp; struct peer *peer; - char tbuf[BMAX]; - char *tptr; + char tbuf[sizeof(up->buf)]; + char * tptr; + int octets; /* * Initialize pointers and read the timecode and timestamp. Note @@ -317,27 +328,27 @@ acts_receive ( * arbitrary fragments. Capture the timecode at the beginning of * the message and at the '*' and '#' on-time characters. */ - peer = (struct peer *)rbufp->recv_srcclock; + peer = rbufp->recv_peer; pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr - - pp->a_lastcode), &pp->lastrec); + up = pp->unitptr; + octets = sizeof(up->buf) - (up->bufptr - up->buf); + refclock_gtraw(rbufp, tbuf, octets, &pp->lastrec); for (tptr = tbuf; *tptr != '\0'; tptr++) { if (*tptr == LF) { - if (up->bufptr == pp->a_lastcode) { + if (up->bufptr == up->buf) { up->tstamp = pp->lastrec; continue; - } else { *up->bufptr = '\0'; - acts_message(peer); - up->bufptr = pp->a_lastcode; + up->bufptr = up->buf; + acts_message(peer, up->buf); } - } else if (!iscntrl(*tptr)) { + } else if (!iscntrl((unsigned char)*tptr)) { *up->bufptr++ = *tptr; if (*tptr == '*' || *tptr == '#') { up->tstamp = pp->lastrec; - write(pp->io.fd, tptr, 1); + if (write(pp->io.fd, tptr, 1) < 0) + msyslog(LOG_ERR, "acts: write echo fails %m"); } } } @@ -349,74 +360,361 @@ acts_receive ( */ void acts_message( - struct peer *peer + struct peer *peer, + const char *msg ) { struct actsunit *up; struct refclockproc *pp; - int dtr = TIOCM_DTR; - char tbuf[SMAX]; -#ifdef DEBUG - u_int modem; -#endif + char tbuf[BMAX]; + int dtr = TIOCM_DTR; + + DPRINTF(1, ("acts: %d %s\n", (int)strlen(msg), msg)); /* * What to do depends on the state and the first token in the - * message. A NO token sends the message to the clockstats. + * message. */ pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; -#ifdef DEBUG - ioctl(pp->io.fd, TIOCMGET, (char *)&modem); - sprintf(tbuf, "acts: %04x (%d %d) %lu %s", modem, up->state, - up->timer, strlen(pp->a_lastcode), pp->a_lastcode); - if (debug) - printf("%s\n", tbuf); -#endif - strncpy(tbuf, pp->a_lastcode, SMAX); + up = pp->unitptr; + + /* + * Extract the first token in the line. + */ + strlcpy(tbuf, msg, sizeof(tbuf)); strtok(tbuf, " "); - if (strcmp(tbuf, "NO") == 0) - record_clock_stats(&peer->srcadr, pp->a_lastcode); - switch(up->state) { + switch (up->state) { /* * We are waiting for the OK response to the modem setup - * command. When this happens, raise DTR and dial the number - * followed by \r. + * command. When this happens, dial the number followed. + * If anything other than OK is received, just ignore it + * and wait for timeoue. */ - case S_OK: + case S_SETUP: if (strcmp(tbuf, "OK") != 0) { - msyslog(LOG_ERR, "acts: setup error %s", - pp->a_lastcode); - acts_disc(peer); - return; + /* + * We disable echo with MODEM_SETUP's E0 but + * if the modem was previously E1, we will + * see MODEM_SETUP echoed before the OK/ERROR. + * Ignore it. + */ + if (!strcmp(tbuf, modem_setup)) + return; + break; } - ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr); - up->state = S_DTR; - up->timer = DTR; + + mprintf_event(PEVNT_CLOCK, peer, "DIAL #%d %s", + up->retry, sys_phone[up->retry]); + if (ioctl(pp->io.fd, TIOCMBIS, &dtr) < 0) + msyslog(LOG_ERR, "acts: ioctl(TIOCMBIS) failed: %m"); + if (write(pp->io.fd, sys_phone[up->retry], + strlen(sys_phone[up->retry])) < 0) + msyslog(LOG_ERR, "acts: write DIAL fails %m"); + write(pp->io.fd, "\r", 1); + up->retry++; + up->state = S_CONNECT; + up->timer = ANSWER; return; /* - * We are waiting for the call to be answered. All we care about - * here is token CONNECT. Send the message to the clockstats. + * We are waiting for the CONNECT response to the dial + * command. When this happens, listen for timecodes. If + * somthing other than CONNECT is received, like BUSY + * or NO CARRIER, abort the call. */ case S_CONNECT: - record_clock_stats(&peer->srcadr, pp->a_lastcode); - if (strcmp(tbuf, "CONNECT") != 0) { - acts_disc(peer); + if (strcmp(tbuf, "CONNECT") != 0) + break; + + report_event(PEVNT_CLOCK, peer, msg); + up->state = S_MSG; + up->timer = TIMECODE; + return; + + /* + * We are waiting for a timecode response. Pass it to + * the parser. If NO CARRIER is received, save the + * messages and abort the call. + */ + case S_MSG: + if (strcmp(tbuf, "NO") == 0) + report_event(PEVNT_CLOCK, peer, msg); + if (up->msgcnt < MAXCODE) + acts_timecode(peer, msg); + else + acts_timeout(peer, S_MSG); + return; + } + + /* + * Other response. Tell us about it. + */ + report_event(PEVNT_CLOCK, peer, msg); + acts_close(peer); +} + + +/* + * acts_timeout - called on timeout + */ +static void +acts_timeout( + struct peer *peer, + teModemState dstate + ) +{ + struct actsunit *up; + struct refclockproc *pp; + int fd; + int rc; + char device[20]; + char lockfile[128], pidbuf[8]; + + /* + * The state machine is driven by messages from the modem, + * when first started and at timeout. + */ + pp = peer->procptr; + up = pp->unitptr; + switch (dstate) { + + /* + * System poll event. Lock the modem port, open the device + * and send the setup command. + */ + case S_IDLE: + if (-1 != pp->io.fd) + return; /* port is already open */ + + /* + * Lock the modem port. If busy, retry later. Note: if + * something fails between here and the close, the lock + * file may not be removed. + */ + if (pp->sloppyclockflag & CLK_FLAG2) { + snprintf(lockfile, sizeof(lockfile), LOCKFILE, + up->unit); + fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, + 0644); + if (fd < 0) { + report_event(PEVNT_CLOCK, peer, "acts: port busy"); + return; + } + snprintf(pidbuf, sizeof(pidbuf), "%d\n", + (u_int)getpid()); + if (write(fd, pidbuf, strlen(pidbuf)) < 0) + msyslog(LOG_ERR, "acts: write lock fails %m"); + close(fd); + } + + /* + * Open the device in raw mode and link the I/O. + */ + snprintf(device, sizeof(device), DEVICE, + up->unit); + fd = refclock_open(device, SPEED232, LDISC_ACTS | + LDISC_RAW | LDISC_REMOTE); + if (fd < 0) { + msyslog(LOG_ERR, "acts: open fails %m"); + return; + } + pp->io.fd = fd; + if (!io_addclock(&pp->io)) { + msyslog(LOG_ERR, "acts: addclock fails"); + close(fd); + pp->io.fd = -1; + return; + } + up->msgcnt = 0; + up->bufptr = up->buf; + + /* + * If the port is directly connected to the device, skip + * the modem business and send 'T' for Spectrabum. + */ + if (sys_phone[up->retry] == NULL) { + if (write(pp->io.fd, "T", 1) < 0) + msyslog(LOG_ERR, "acts: write T fails %m"); + up->state = S_MSG; + up->timer = TIMECODE; return; } - up->state = S_FIRST; - up->timer = CONNECT; + + /* + * Initialize the modem. This works with Hayes- + * compatible modems. + */ + mprintf_event(PEVNT_CLOCK, peer, "SETUP %s", + modem_setup); + rc = write(pp->io.fd, modem_setup, strlen(modem_setup)); + if (rc < 0) + msyslog(LOG_ERR, "acts: write SETUP fails %m"); + write(pp->io.fd, "\r", 1); + up->state = S_SETUP; + up->timer = SETUP; return; /* - * We are waiting for a timecode. Pass it to the parser. + * In SETUP state the modem did not respond OK to setup string. + */ + case S_SETUP: + report_event(PEVNT_CLOCK, peer, "no modem"); + break; + + /* + * In CONNECT state the call did not complete. Abort the call. + */ + case S_CONNECT: + report_event(PEVNT_CLOCK, peer, "no answer"); + break; + + /* + * In MSG states no further timecodes are expected. If any + * timecodes have arrived, update the clock. In any case, + * terminate the call. */ - case S_FIRST: case S_MSG: - acts_timecode(peer, pp->a_lastcode); + if (up->msgcnt == 0) { + report_event(PEVNT_CLOCK, peer, "no timecodes"); + } else { + pp->lastref = pp->lastrec; + record_clock_stats(&peer->srcadr, pp->a_lastcode); + refclock_receive(peer); + } + break; + } + acts_close(peer); +} + + +/* + * acts_close - close and prepare for next call. + * + * In ClOSE state no further protocol actions are required + * other than to close and release the device and prepare to + * dial the next number if necessary. + */ +void +acts_close( + struct peer *peer + ) +{ + struct actsunit *up; + struct refclockproc *pp; + char lockfile[128]; + int dtr; + + pp = peer->procptr; + up = pp->unitptr; + if (pp->io.fd != -1) { + report_event(PEVNT_CLOCK, peer, "close"); + dtr = TIOCM_DTR; + if (ioctl(pp->io.fd, TIOCMBIC, &dtr) < 0) + msyslog(LOG_ERR, "acts: ioctl(TIOCMBIC) failed: %m"); + io_closeclock(&pp->io); + pp->io.fd = -1; + } + if (pp->sloppyclockflag & CLK_FLAG2) { + snprintf(lockfile, sizeof(lockfile), + LOCKFILE, up->unit); + unlink(lockfile); + } + if (up->msgcnt == 0 && up->retry > 0) { + if (sys_phone[up->retry] != NULL) { + up->state = S_IDLE; + up->timer = REDIAL; + return; + } + } + up->state = S_IDLE; + up->timer = 0; +} + + +/* + * acts_poll - called by the transmit routine + */ +static void +acts_poll( + int unit, + struct peer *peer + ) +{ + struct actsunit *up; + struct refclockproc *pp; + + /* + * This routine is called at every system poll. All it does is + * set flag1 under certain conditions. The real work is done by + * the timeout routine and state machine. + */ + pp = peer->procptr; + up = pp->unitptr; + switch (peer->ttl) { + + /* + * In manual mode the calling program is activated by the ntpdc + * program using the enable flag (fudge flag1), either manually + * or by a cron job. + */ + case MODE_MANUAL: + return; + + /* + * In automatic mode the calling program runs continuously at + * intervals determined by the poll event or specified timeout. + */ + case MODE_AUTO: break; + + /* + * In backup mode the calling program runs continuously as long + * as either no peers are available or this peer is selected. + */ + case MODE_BACKUP: + if (!(sys_peer == NULL || sys_peer == peer)) + return; + + break; + } + pp->polls++; + if (S_IDLE == up->state) { + up->retry = 0; + acts_timeout(peer, S_IDLE); + } +} + + +/* + * acts_timer - called at one-second intervals + */ +static void +acts_timer( + int unit, + struct peer *peer + ) +{ + struct actsunit *up; + struct refclockproc *pp; + + /* + * This routine implments a timeout which runs for a programmed + * interval. The counter is initialized by the state machine and + * counts down to zero. Upon reaching zero, the state machine is + * called. If flag1 is set while timer is zero, force a call. + */ + pp = peer->procptr; + up = pp->unitptr; + if (up->timer == 0) { + if (pp->sloppyclockflag & CLK_FLAG1) { + pp->sloppyclockflag &= ~CLK_FLAG1; + acts_timeout(peer, S_IDLE); + } + } else { + up->timer--; + if (up->timer == 0) + acts_timeout(peer, up->state); } } @@ -425,8 +723,8 @@ acts_message( */ void acts_timecode( - struct peer *peer, /* peer structure pointer */ - char *str /* timecode string */ + struct peer * peer, /* peer structure pointer */ + const char * str /* timecode string */ ) { struct actsunit *up; @@ -448,7 +746,7 @@ acts_timecode( char dstchar; /* WWVB daylight/savings indicator */ int tz; /* WWVB timezone */ - u_int leapmonth; /* PTB/NPL month of leap */ + int leapmonth; /* PTB/NPL month of leap */ char leapdir; /* PTB/NPL leap direction */ /* @@ -457,9 +755,9 @@ acts_timecode( * errors due noise are forgivable. */ pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; + up = pp->unitptr; pp->nsec = 0; - switch(strlen(str)) { + switch (strlen(str)) { /* * For USNO format on-time character '*', which is on a line by @@ -472,8 +770,8 @@ acts_timecode( return; /* - * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa - * UTC(NIST) *" + * ACTS format A: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa + * UTC(NIST) *". */ case LENACTS: if (sscanf(str, @@ -484,25 +782,17 @@ acts_timecode( refclock_report(peer, CEVNT_BADREPLY); return; } - - /* - * Wait until ACTS has calculated the roundtrip delay. - * We don't need to do anything, as ACTS adjusts the - * on-time epoch. - */ - if (flag != '#') - return; - pp->day = ymd2yd(pp->year, month, day); pp->leap = LEAP_NOWARNING; if (leap == 1) - pp->leap = LEAP_ADDSECOND; - else if (pp->leap == 2) - pp->leap = LEAP_DELSECOND; + pp->leap = LEAP_ADDSECOND; + else if (leap == 2) + pp->leap = LEAP_DELSECOND; memcpy(&pp->refid, REFACTS, 4); - if (up->msgcnt == 0) - record_clock_stats(&peer->srcadr, str); up->msgcnt++; + if (flag != '#' && up->msgcnt < 10) + return; + break; /* @@ -523,10 +813,8 @@ acts_timecode( */ pp->leap = LEAP_NOWARNING; memcpy(&pp->refid, REFUSNO, 4); - if (up->msgcnt == 0) - record_clock_stats(&peer->srcadr, str); up->msgcnt++; - return; + break; /* * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" @@ -543,14 +831,12 @@ acts_timecode( pp->leap = LEAP_NOWARNING; if (leapmonth == month) { if (leapdir == '+') - pp->leap = LEAP_ADDSECOND; + pp->leap = LEAP_ADDSECOND; else if (leapdir == '-') - pp->leap = LEAP_DELSECOND; + pp->leap = LEAP_DELSECOND; } pp->day = ymd2yd(pp->year, month, day); memcpy(&pp->refid, REFPTB, 4); - if (up->msgcnt == 0) - record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; @@ -569,8 +855,6 @@ acts_timecode( if (synchar != ' ') pp->leap = LEAP_NOTINSYNC; memcpy(&pp->refid, REFWWVB, 4); - if (up->msgcnt == 0) - record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; @@ -592,8 +876,6 @@ acts_timecode( else if (leapchar == 'L') pp->leap = LEAP_ADDSECOND; memcpy(&pp->refid, REFWWVB, 4); - if (up->msgcnt == 0) - record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; @@ -613,319 +895,17 @@ acts_timecode( */ peer->refid = pp->refid; pp->lastrec = up->tstamp; - if (!refclock_process(pp)) { - refclock_report(peer, CEVNT_BADTIME); - return; - } - pp->lastref = pp->lastrec; - if (peer->disp > MAXDISTANCE) - refclock_receive(peer); - if (up->state != S_MSG) { - up->state = S_MSG; - up->timer = TIMECODE; - } -} - - -/* - * acts_poll - called by the transmit routine - */ -static void -acts_poll ( - int unit, - struct peer *peer - ) -{ - struct actsunit *up; - struct refclockproc *pp; - - /* - * This routine is called at every system poll. All it does is - * set flag1 under certain conditions. The real work is done by - * the timeout routine and state machine. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - switch (peer->ttl) { - - /* - * In manual mode the calling program is activated by the ntpdc - * program using the enable flag (fudge flag1), either manually - * or by a cron job. - */ - case MODE_MANUAL: - /* fall through */ - break; - - /* - * In automatic mode the calling program runs continuously at - * intervals determined by the poll event or specified timeout. - */ - case MODE_AUTO: - pp->sloppyclockflag |= CLK_FLAG1; - break; - - /* - * In backup mode the calling program runs continuously as long - * as either no peers are available or this peer is selected. - */ - case MODE_BACKUP: - if (sys_peer == NULL || sys_peer == peer) - pp->sloppyclockflag |= CLK_FLAG1; - break; - } -} - - -/* - * acts_timer - called at one-second intervals - */ -static void -acts_timer( - int unit, - struct peer *peer - ) -{ - struct actsunit *up; - struct refclockproc *pp; - - /* - * This routine implments a timeout which runs for a programmed - * interval. The counter is initialized by the state machine and - * counts down to zero. Upon reaching zero, the state machine is - * called. If flag1 is set while in S_IDLE state, force a - * timeout. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) { - acts_timeout(peer); - return; - } - if (up->timer == 0) - return; - - up->timer--; - if (up->timer == 0) - acts_timeout(peer); -} - - -/* - * acts_timeout - called on timeout - */ -static void -acts_timeout( - struct peer *peer - ) -{ - struct actsunit *up; - struct refclockproc *pp; - int fd; - char device[20]; - char lockfile[128], pidbuf[8]; - char tbuf[BMAX]; - - /* - * The state machine is driven by messages from the modem, when - * first stated and at timeout. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - pp->sloppyclockflag &= ~CLK_FLAG1; - if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag & - CLK_FLAG3)) { - msyslog(LOG_ERR, "acts: no phones"); - return; - } - switch(up->state) { - - /* - * System poll event. Lock the modem port and open the device. - */ - case S_IDLE: - - /* - * Lock the modem port. If busy, retry later. Note: if - * something fails between here and the close, the lock - * file may not be removed. - */ - if (pp->sloppyclockflag & CLK_FLAG2) { - sprintf(lockfile, LOCKFILE, up->unit); - fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, - 0644); - if (fd < 0) { - msyslog(LOG_ERR, "acts: port busy"); - return; - } - sprintf(pidbuf, "%d\n", (u_int)getpid()); - write(fd, pidbuf, strlen(pidbuf)); - close(fd); - } - - /* - * Open the device in raw mode and link the I/O. - */ - if (!pp->io.fd) { - sprintf(device, DEVICE, up->unit); - fd = refclock_open(device, SPEED232, - LDISC_ACTS | LDISC_RAW | LDISC_REMOTE); - if (fd == 0) { - return; - } - pp->io.fd = fd; - if (!io_addclock(&pp->io)) { - msyslog(LOG_ERR, - "acts: addclock fails"); - close(fd); - pp->io.fd = 0; - return; - } - } - - /* - * If the port is directly connected to the device, skip - * the modem business and send 'T' for Spectrabum. - */ - if (pp->sloppyclockflag & CLK_FLAG3) { - if (write(pp->io.fd, "T", 1) < 0) { - msyslog(LOG_ERR, "acts: write %m"); - return; - } - up->state = S_FIRST; - up->timer = CONNECT; - return; - } - - /* - * Initialize the modem. This works with Hayes commands. - */ -#ifdef DEBUG - if (debug) - printf("acts: setup %s\n", MODEM_SETUP); -#endif - if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) < - 0) { - msyslog(LOG_ERR, "acts: write %m"); - return; - } - up->state = S_OK; - up->timer = SETUP; - return; - - /* - * In OK state the modem did not respond to setup. - */ - case S_OK: - msyslog(LOG_ERR, "acts: no modem"); - break; - - /* - * In DTR state we are waiting for the modem to settle down - * before hammering it with a dial command. - */ - case S_DTR: - sprintf(tbuf, "DIAL #%d %s", up->retry, - sys_phone[up->retry]); - record_clock_stats(&peer->srcadr, tbuf); -#ifdef DEBUG - if (debug) - printf("%s\n", tbuf); -#endif - write(pp->io.fd, sys_phone[up->retry], - strlen(sys_phone[up->retry])); - write(pp->io.fd, "\r", 1); - up->state = S_CONNECT; - up->timer = ANSWER; + if (up->msgcnt == 0) return; - /* - * In CONNECT state the call did not complete. - */ - case S_CONNECT: - msyslog(LOG_ERR, "acts: no answer"); - break; - - /* - * In FIRST state no messages were received. - */ - case S_FIRST: - msyslog(LOG_ERR, "acts: no messages"); - break; - - /* - * In CLOSE state hangup is complete. Close the doors and - * windows and get some air. - */ - case S_CLOSE: - - /* - * Close the device and unlock a shared modem. - */ - if (pp->io.fd) { - io_closeclock(&pp->io); - close(pp->io.fd); - if (pp->sloppyclockflag & CLK_FLAG2) { - sprintf(lockfile, LOCKFILE, up->unit); - unlink(lockfile); - } - pp->io.fd = 0; - } - - /* - * If messages were received, fold the tent and wait for - * the next poll. If no messages and there are more - * numbers to dial, retry after a short wait. - */ - up->bufptr = pp->a_lastcode; - up->timer = 0; - up->state = S_IDLE; - if ( up->msgcnt == 0) { - up->retry++; - if (sys_phone[up->retry] == NULL) - up->retry = 0; - else - up->timer = SETUP; - } else { - up->retry = 0; - } - up->msgcnt = 0; + strlcpy(pp->a_lastcode, str, sizeof(pp->a_lastcode)); + pp->lencode = strlen(pp->a_lastcode); + if (!refclock_process(pp)) { + refclock_report(peer, CEVNT_BADTIME); return; } - acts_disc(peer); -} - - -/* - * acts_disc - disconnect the call and clean the place up. - */ -static void -acts_disc ( - struct peer *peer - ) -{ - struct actsunit *up; - struct refclockproc *pp; - int dtr = TIOCM_DTR; - - /* - * We get here if the call terminated successfully or if an - * error occured. If the median filter has something in it,feed - * the data to the clock filter. If a modem port, drop DTR to - * force command mode and send modem hangup. - */ - pp = peer->procptr; - up = (struct actsunit *)pp->unitptr; - if (up->msgcnt > 0) - refclock_receive(peer); - if (!(pp->sloppyclockflag & CLK_FLAG3)) { - ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr); - write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP)); - } - up->timer = SETUP; - up->state = S_CLOSE; + pp->lastref = pp->lastrec; } - #else int refclock_acts_bs; #endif /* REFCLOCK */ |