/* * Module DTSS$PROVIDER.C * Version V1.0-2 *//* * Copyright (c) 1990,1991,1992 by * Digital Equipment Corporation, Maynard, Mass. * * This software is furnished under a license and may be used and copied * only in accordance with the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * The information in this software is subject to change without notice * and should not be construed as a commitment by Digitial Equipment * Corporation. * * Digital assumes no responsibility for the use or reliablity of its * software on equipment which is not supplied by Digital. * * FACILITY: Distributed Time Synchronization Service (DTSS) * * ABSTRACT: * Implements a DECdts time provider which obtains time from * the following list of radio receivers, connected thru a * RS232 terminal interface. Please refer to the DECdts * Concepts Manual for information about the geographical * coverage of these radio providers. * * * * ==================================================================== * NTP time provider | TP_NTP * ==================================================================== * * TO COMPILE: * * $! * $! This DCL Command Procedure will compile and link some * $! of the DTSS NTP time provider example. * $! * $ BUILD_NTP: * $ CC/OBJ='name/G_FLOAT DTSS$PROVIDER.C * $ LINK/EXE='name 'name, - * SYS$INPUT:/OPTIONS * SYS$LIBRARY:UCX$IPC.OLB/LIB * SYS$LIBRARY:VAXCRTLG.OLB/LIB * SYS$SHARE:DTSS$SHR.EXE/SHARE * $ RETURN * * * * TO RUN: * * Four logical names are translated at program start from * the system logical name table which control the characteristics * of the time provider's operation, they are: * * DTSS$_TP_HOSTNAME : NTP Host from which we import the time. * This is set to the hostname that is running the NTP * provider which we want to use. * This logical is ignored by all but the NTP provider. * * Format: Any ASCII string. * * DTSS$_TP_INACCURACY : Systematic inaccuracy in ms. * Each radio clock specifies the amount of systematic * inaccuracy which is returned with each time-stamp. * This is usually proportional to the number of miles * the device is physically located from the transmission * center from which time is read. The inaccuracy specified * by this parameter is added to the times returned to the * time server. * * Format: a non-negative integer. * * DTSS$_TP_POLL_RATE : Rate in seconds that the device is * polled. This value will override the DTSS management * parameter 'synchronization hold down'. * * Format: an integer (seconds) in the range 1 second to 31 days; * * DTSS$_TP_TIME_STAMPS : This parameter specifies the number * of timestamps which are read and returned to the * time server at each synchronization. * * Format: an integer in the range 1 to 6; * * DTSS$_TP_MAXERROR : If the difference between the time * provider and the local clock differs more than * maxerror, then the timeprovider is considered faulty, * and its timestamp is ignored. * * Format: a non-negative integer (seconds) Recommended: 600 * * DTSS$_TP_FIRSTSYNC : If this value is TRUE, then the * DTSS$TP_MAXERROR parameter is ignored on the first * synchronization. * * Format: 0 , false; otherwise TRUE. * * DTSS$_TP_VERBOSE : Display info to std out * * Format: 0, false; otherwise TRUE. * * This is an example session, only setting the dtss$_tp_hostname * logical is required, all others are optional: * * ENVIRONMENT: VAX/VMS V5.5 * * AUTHOR: * * Distributed Processing Engineering - DPE/DTSS * */#pragma nostandard /* A VMS only Module */#include /* standard I/O definitions */#include iodef /* I/O definitions */#include ssdef /* error return value (SS$) definitions */#include descrip /* descriptor definitions */#include lnmdef /* Logical name definitions */#include ctype /* isxxx macros, etc. */#include /* tm structure definition */#include /* utc library routines & dtss tpi defs */#include #include #include #include #include #include #include #define NOSERVER 0 /* DTSS Server will not be used when this symbol */ /* is set to 1. The provider will "loop", poling */ /* the external device. *//* * Constants */#define BUFSIZE 40 /* Length of ascii time string */#define K_NS_PER_SEC (1000000000)#define K_MS_PER_SEC (1000)#define K_NS_PER_MS (K_NS_PER_SEC / K_MS_PER_SEC)typedef struct IOsb { /* IO status Block */ unsigned short status; unsigned short byteCount; unsigned long devStatus; } IOsb;/* * Forward Definitions */InitIPC( unsigned short *tstpChan, unsigned short *tptsChan );SendReply( unsigned short tptsChan, TPrspMsg *timeResponse );ReadRequest( unsigned short tstpChan, TPreqMsg *timeRequest );void InitializeTPdefaults(int *pollrate, int *timestamps, int *inaccuracy, int *tmorate, int *clockSet, int *retries, int *firstsynch, int *maxtperror, int *isverbose);int QueryProvider(int ttchan, struct utc *beforeTime, struct utc *TPtime, struct utc *afterTime);int ValidateTime(struct utc *systemTime, struct utc *externalTime);/* * Global Variables */static int ttchan; /* channel number of term */$DESCRIPTOR(TSTPLOG, "DTSS$_TSTP_MBX"); /* tpts mailbox */$DESCRIPTOR(TPTSLOG, "DTSS$_TPTS_MBX"); /* tstp mailbox */$DESCRIPTOR(TPINACC, "DTSS$_TP_INACCURACY"); /* Inaccuracy parameter */$DESCRIPTOR(TPRATE, "DTSS$_TP_POLL_RATE"); /* Poll rate parameter */$DESCRIPTOR(TPSTAMPS, "DTSS$_TP_TIME_STAMPS"); /* Time stamps parameter */$DESCRIPTOR(MAXERROR, "DTSS$_TP_MAXERROR"); /* Max error allowed on TP */$DESCRIPTOR(FIRSTSYNC,"DTSS$_TP_FIRSTSYNC"); /* Always synch first time */$DESCRIPTOR(VERBOSE, "DTSS$_TP_VERBOSE"); /* Print info out. */#define K_MAX_HOSTNAME (255) /* largest hostname user can use*/char hostname[K_MAX_HOSTNAME+1]; /* Host name */$DESCRIPTOR(NTP_HOSTNAME,"DTSS$_TP_HOSTNAME"); /* For NTP, a remote server */$DESCRIPTOR(PROCESS_NAME, "DTSS$PROVIDER"); /* Process name when OK */$DESCRIPTOR(LNM_TABLE,"LNM$SYSTEM_TABLE") ; /* Table to search */unsigned long INACCURACY; /* base inaccuracy of TP */unsigned long POLLRATE; /* seconds between TP syncs */unsigned long TIMESTAMP; /* time stamps at each sync */unsigned long TMORATE; /* timeout */unsigned long CLOCKSET; /* allow clock sets? */unsigned long RETRIES; /* retries allowed. */unsigned long FIRSTSYNCH; /* always synch first time */unsigned long MAXTPERROR; /* Max error on TP. */unsigned long ISVERBOSE; /* Print info. */unsigned long SYNCHCOUNT; /* current synch. number */ /* *++ * ReadTimes() * * Functional Description: * * Parse out time stamps from the radio clock input. * * Inputs: * * timeStamps - the number of timestamps to read * fd - radio clock file descriptor * * Outputs: * * tpTimeMsg - buffer to return the timestamp data. * * Value Returned: * * 1 - Success * 0 - Failure * *-- */int ReadTimes( timeStamps, retries, ttchan, tpTimeMsg )unsigned long timeStamps;unsigned long retries;int ttchan;TPtimeMsg *tpTimeMsg;{ int i; /* temp, index */ int retry; int status; retry = retries; /* * Now Read The Time Stamps. * Note that this loop will terminate having read timeStamps timestamps * or exhusting retry retries. and thus is non-infinite. */ i = 0; while ( i < timeStamps ) { status = QueryProvider((int)ttchan, &tpTimeMsg->timeStampList[i].beforeTime, &tpTimeMsg->timeStampList[i].TPtime, &tpTimeMsg->timeStampList[i].afterTime ); if (status & 1) { status = ValidateTime(&tpTimeMsg->timeStampList[i].afterTime, &tpTimeMsg->timeStampList[i].TPtime); if (!(status & 1)) PrintValidationError(&tpTimeMsg->timeStampList[i].afterTime, &tpTimeMsg->timeStampList[i].TPtime); } if (status & 1) { i += 1; } else { if (retry-- == 0) return(0); } } return(1);} /* *++ * main() * * Functional Description: * * The Time Provider program communicates with the Distributed * Time Synchronization Service and with a time provider * device. This module implements the DECdts TP interface. * * * Inputs: * * None. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * IPC with DTSS$SERVICE. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */main( argc, argv )int argc;char *argv[];{ TPreqMsg timeServiceRequest; TPrspMsg TMOresponse; TPrspMsg timeResponse; unsigned long status; unsigned short tstpChan; unsigned short tptsChan; char value[255]; int i; short size; unsigned long attr = LNM$M_CASE_BLIND; /* attributes mask */ struct { short bufln ; short itmcd ; long *bufad ; long *rtnln ; long term; } itmlst = { 255, LNM$_STRING, &value, &size, 0 }; /* * read the startup parameters */ InitializeTPdefaults(&POLLRATE, &TIMESTAMP, &INACCURACY, &TMORATE, &CLOCKSET, &RETRIES, &FIRSTSYNCH, &MAXTPERROR, &ISVERBOSE); /* * keep count of synchs attempted. */ SYNCHCOUNT = 0; /* * Set the process name to dtss$provider */ if (!(status = SYS$SETPRN( &PROCESS_NAME ))&1) exit(status); status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPRATE, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; POLLRATE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPSTAMPS, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; TIMESTAMP = atoi( value ); if (TIMESTAMP > K_MAX_TIMESTAMPS || TIMESTAMP < K_MIN_TIMESTAMPS ) { fprintf(stderr,"The time stamp value is out of legal range\n"); fprintf(stderr,"Legal Range is %d to %d\n", K_MIN_TIMESTAMPS,K_MAX_TIMESTAMPS); exit(1); } } status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPINACC, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; INACCURACY = atoi( value ) ; } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &TPRATE, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; POLLRATE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &MAXERROR, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; MAXTPERROR = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &VERBOSE, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; ISVERBOSE = atoi( value ); } ; status = SYS$TRNLNM(&attr, &LNM_TABLE, &FIRSTSYNC, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; FIRSTSYNCH = atoi( value ); } ; value[0] = '\0'; status = SYS$TRNLNM(&attr, &LNM_TABLE, &NTP_HOSTNAME, 0, &itmlst ); if ((status & 1)) { value[size] = '\0'; strcpy(hostname,value); } ; /* * Echo back the input parameters. */ fprintf(stderr,"PARAMETERS SET:\n"); fprintf(stderr,"TP_HOSTNAME: %s\n", hostname); fprintf(stderr,"TP_INACCURACY: %d milliseconds\n", INACCURACY); fprintf(stderr,"TP_POLL_RATE: %d seconds\n", POLLRATE); fprintf(stderr,"TP_TIME_STAMPS: %d timestamps\n", TIMESTAMP); fprintf(stderr,"TP_MAXERROR: %d seconds\n", MAXTPERROR); fprintf(stderr,"TP_FIRSTSYNC: %s\n", FIRSTSYNCH?"TRUE":"FALSE"); fprintf(stderr,"TP_VERBOSE: %s\n\n\n", ISVERBOSE?"TRUE":"FALSE"); /* * Initialize the interprocess communication. * Die if this fails. */ status = InitIPC( &tstpChan, &tptsChan ); if ( !(status & 1) ) exit( status ); /* * Prepare a time out response message to issue to the service * which will identify this process as active, and * tell the service how long it must wait for the time response. */ TMOresponse.version_major = K_TPI_VERSION_MAJOR; TMOresponse.version_minor = K_TPI_VERSION_MINOR; TMOresponse.status = K_TPI_SUCCESS; TMOresponse.TPmsgType = K_TPI_CTL_MESSAGE; TMOresponse.TPdata.TPctlMsg.nextPoll = POLLRATE; TMOresponse.TPdata.TPctlMsg.timeout = TMORATE; TMOresponse.TPdata.TPctlMsg.noClockSet = CLOCKSET; /* * Goto Work! * Issue a synchronous IO request to the server request * mailbox. When the the server responds, Reply to the * response mailbox with the set of TP times. Exit the * program if there is any error associated with the * IPC. * */ for (;;) { status = ReadRequest( tstpChan, &timeServiceRequest ); if ( !(status & 1) ) exit( status ); /* * increment the synchcount, * make sure it doesn't loop around to 1 again * since on synch #1 the MAX TP ERROR value * is ignored. */ SYNCHCOUNT++; SYNCHCOUNT = (SYNCHCOUNT==0)?2:SYNCHCOUNT; timeResponse.version_major = K_TPI_VERSION_MAJOR; timeResponse.version_minor = K_TPI_VERSION_MINOR; timeResponse.TPsyncID = timeServiceRequest.TPsyncID; timeResponse.TPdata.TimeMsg.timeStampCount = 0; timeResponse.status = K_TPI_SUCCESS; timeResponse.TPmsgType = K_TPI_TIME_MESSAGE; /* * Initialize the time provider hardware. */ status = InitNTP(); if ( !( status & 1 ) ) { timeResponse.status = K_TPI_FAILURE; if (!(status = SendReply ( tptsChan, &timeResponse ))&1) exit(status); } else { /* * Send the initial repsonse, informing the * the time service that we are alive and well, * and that it should wait for the time stamps * to arrive. */ TMOresponse.TPsyncID = timeServiceRequest.TPsyncID; status = SendReply( tptsChan, &TMOresponse ); if ( !(status & 1) ) exit( status ); status = ReadTimes(TIMESTAMP, RETRIES, ttchan, &timeResponse.TPdata.TimeMsg); if ( status & 1 ) { timeResponse.TPdata.TimeMsg.timeStampCount = TIMESTAMP; timeResponse.status = K_TPI_SUCCESS; } else { timeResponse.status = K_TPI_FAILURE; } status = SendReply( tptsChan, &timeResponse ); if ( !(status & 1) ) exit( status ); /* * Debugging output. */ if (ISVERBOSE) PrintTimes( &timeResponse ); /* * Call for the Time Provider Hardware to do any necessary * cleanup by calling ExitTP. */ CleanupNTP(); } } }/* End of main program*/ /* *++ * ValidateTime() * * Functional Description: * * This routine confirms that the time returned from the system, is * within MAXTPERROR seconds of the time returned by the external * device. * * Inputs: * * systemTime - time returned by the system. * externalTime- time returned by the external device. * * Implicit Inputs: * * SYNCHCOUNT - current synch number. * FIRSTSYNCH - allow first synch to always validate. * MAXTPERROR - greatest difference between two times. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * Returns TRUE iff * (abs(externalTime - systemTime) <= MAXTPERROR) || * (FIRSTSYNCH && SYNCHCOUNT == 1) * * Side Effects: * * None. * *-- */int ValidateTime(systemTime,externalTime)struct utc *systemTime;struct utc *externalTime;{struct utc result;struct timespec inaccsp;struct reltimespec timesp; /* * find the difference between the system time and the * time reported by the external clock. */ if (utc_subtime(&result,systemTime,externalTime) || utc_abstime(&result,&result) || utc_binreltime(×p,&inaccsp,&result)) exit(0); /* * if the difference is less than the max error, or * if first synch is enabled, return true. */ return( ((SYNCHCOUNT == 1) && (FIRSTSYNCH)) || (timesp.tv_sec <= MAXTPERROR) );} /* *++ * InitIPC() * * Functional Description: * * This routine creates a temporary Mailbox to which the Time Service * Process will write its requests. * * Inputs: * * None. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. * *-- */InitIPC( tstpChan, tptsChan )unsigned short *tstpChan;unsigned short *tptsChan;{#if NOSERVER return(1);#else unsigned long status; /* * Create a request channel to the time service. Mark the mailbox * for delete so that it will go away when this process deassigns * its channel. Note that the service will only attach to the * mailbox while it is communicating with the TP, it is generally * detatched. */ status = SYS$CREMBX (1, /* prmflag */ tstpChan, /* channel */ sizeof(TPreqMsg), /* maxmsg */ sizeof(TPreqMsg)*2, /* bufquo */ 0x0330, /* promsk */ 0, /* access in current mode */ &TSTPLOG); /* DTSS$_TSTP_MBX */ if ( !(status & 1) ) return( status ); if ( !(( status = SYS$DELMBX ( *tstpChan ) ) & 1) ) return( status ); /* * Assign a channel to the TP to TS mailbox which was created by * the DTSS$Service process. */ status = SYS$ASSIGN (&TPTSLOG, /* TPtoTS mailbox */ tptsChan, /* channel */ 0, /* access mode */ 0); /* mailbox */ return ( status );#endif}/* End of routine InitIPC */ /* *++ * SendReply() * * Functional Description: * * This routine writes a response message to the Time Service Process's * response Mailbox. * * Inputs: * * tptsChan - The channel to the TS response mailbox * * timeResponse - the address of the response message which * is to be written to the TS. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * int - the status of the write request. * * Side Effects: * * None. * *-- */SendReply( unsigned short tptsChan, TPrspMsg *timeResponse ){ IOsb iosb; unsigned long status;#if NOSERVER return(1);#else status = SYS$QIOW(0, /* efn */ tptsChan, /* chan */ IO$_WRITEVBLK | /* func */ IO$M_NORSWAIT | IO$M_NOW, &iosb, /* I/O status block */ 0, /* ast addr */ 0, /* ast prm */ timeResponse, /* P1 = buffer to write */ sizeof(TPrspMsg), /* P2 = size in bytes */ 0, /* P3 */ 0, /* P4 */ 0, /* P5 */ 0); /* P6 */ if ( !(status & 1) ) return( status ); if ( !(iosb.status & 1) ) return( iosb.status ); return( status );#endif}/* End of routine sendReply */ /* *++ * ReadRequest() * * Functional Description: * * This routine reads a request message written by the Time Service * process to the TSTP mailbox. * * Inputs: * * None. * * Implicit Inputs: * * The Channel to the request mailbox is attached. * * Outputs: * * timeRequest - the address of the structure which will * receive the Time Service request message. * * Implicit Outputs: * * None. * * Value Returned: * * int - the status of the read of the mailbox. * * Side Effects: * * None. * *-- */ReadRequest( unsigned short tstpChan, TPreqMsg *timeRequest ){#if NOSERVER sleep(10); return(1);#else IOsb iosb; unsigned long status; status = SYS$QIOW(0, /* efn */ tstpChan, /* chan */ IO$_READVBLK, /* func */ &iosb, /* I/O status block */ 0, /* ast addr */ 0, /* ast prm */ timeRequest, /* P1 = buffer to write */ sizeof(TPreqMsg), /* P2 = size in bytes */ 0, /* P3 */ 0, /* P4 */ 0, /* P5 */ 0); /* P6 */ if ( !(status & 1) ) return( status ); if ( !(iosb.status & 1) ) return( status ); /* * Check that we got the size message we expected. */ if (iosb.byteCount != sizeof(TPreqMsg)) { (void) fprintf(stderr, "rqstMsg size %d, expected %d\n", iosb.byteCount, sizeof(TPreqMsg)); return( SS$_NODATA ); } if (timeRequest->version_major != K_TPI_VERSION_MAJOR || timeRequest->version_minor != K_TPI_VERSION_MINOR) { (void) fprintf(stderr,"TPI version mismatch \n"); return( SS$_NODATA ); } return( status );#endif}/* End of routine ReadRequest */ /* ********************************************************** * NTP Specific Routines. ********************************************************** *//* * DESCRIPTION OF THE * NETWORK TIME PROTOCOL (NTP) * * The Network Time Protocol is an Internet recommended standard for * distributing time. This provider assumes the user is familiar with * the NTP protocol and has a NTP server available as a time source. * * -------------------------------------------------------------------------- */ /* * FD macros */#ifndef FD_SETtypedef struct fd_set{char fds_bits[4];} fd_set;#define NFDBITS 32#define FD_SETSIZE 32#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p)))#endif/* * Conversion factors */#define K_NS_PER_SEC (1000000000)#define K_MS_PER_SEC (1000)#define K_NS_PER_MS (K_NS_PER_SEC / K_MS_PER_SEC)#define K_100NS_PER_MS (10000)/* * Literals */#define K_NTP_TIMEOUT (60) /* allow NTP server 60 * * seconds to respond */#define K_NTP_RETRY (3) /* Two tries per request */#define K_NTP_JAN_1970 (2208988800) /* 1970 - 1900 in seconds */#define K_DTS_NTP_STRATUM (8) /* Stratum reported by DTS * * when it gives time to NTP */#define NTP_POLL_RATE 60 /* seconds */#define NTP_TIME_STAMPS 4 /* int, 1-6 */#define NTP_INACCURACY 300 /* seconds */#define NTP_TIMEOUT 60 /* seconds */#define NTP_NOCLOCKSET 0 /* int, t/f - 1/0 */#define NTP_RETRIES 4 /* int > 0 */#define NTP_FIRSTSYNCH 1 /* int > 0 */#define NTP_MAXTPERROR 30 /* seconds */#define NTP_ISVERBOSE 1 /* int > 0 *//* * NTP message parameters */#define K_NTP_VERSION1 (0x0b) /* Status bits that encode * * version */#define K_NTP_UNSPECIFIED (0) /* Stratum unspecified */#define K_NTP_DEF_SERVICE_PORT (123) /* default endpoint of NTP */ /* * Structure definitions for NTP fixed point values * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Integer Part | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Fraction Part | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Integer Part | Fraction Part | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/struct l_fixedpt { u_long int_part; u_long fraction;};struct s_fixedpt { u_short sint_part; u_short sfraction;};/* * NTP packet definitions * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |LI | VN |0 0 0| Stratum | Poll | Precision | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Synchronizing Distance | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Estimated Drift Rate | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Reference Clock Identifier | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * | Reference Timestamp (64 bits) | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * | Originate Timestamp (64 bits) | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * | Receive Timestamp (64 bits) | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * | Transmit Timestamp (64 bits) | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/struct ntpdata { u_char status; /* status of local clock and leap info */ u_char stratum; /* Stratum level */ u_char poll; /* poll value */ int precision:8; struct s_fixedpt distance; u_long drift; u_long refid; struct l_fixedpt reftime; struct l_fixedpt org; struct l_fixedpt rec; struct l_fixedpt xmt;};static struct ntpdata ntp_data; /* NTP message structure */struct ntpdata *pkt = &ntp_data; /* NTP message pointer */struct sockaddr_in dst; /* Socket structure for NTP */struct sockaddr_in socketin = {AF_INET};int dstlen = sizeof(dst); /* Size of dst struct */struct sockaddr tstpSockAddr_un; /* UNIX domain socket for TSTP */struct servent *sp; /* Service structure */struct hostent *hp; /* Host structure */void cvt_ntp_utc(struct utc *utc, struct l_fixedpt *ntp);void cvt_utc_ntp(struct l_fixedpt *ntp, struct utc *utc); /* *++ * InitializeTPdefaults() * * Functional Description: * * Initialize the default input parameters for the external time * provider. * * * * Inputs: * Implicit Inputs: * * * Outputs: * * pollrate - int to be set to the default poll rate * timestamp- int to be set to the default number of * timestamps to read from the external time provider. * inaccuracy-int to be set to the default inaccuracy for the * external time provider (systematic error). * tmorate -int to be set to the default time-out rate (the * number of seconds the dtss server must wait for * the data response). * clockset - int to be set to true if the system clock should not * be affected by the results of the TP synch, false if * the clock can be modified by the results of the TP * synch. * retries - int to be set to the number of times the program is * allowed to resend a request after the * external time source has returned a failure. * firstsync- boolean, assume that the time returned by the external * clock is correct on the first synchronization * maxtperror-if the difference between the local clock and the * time provider differs by more than maxtperror, the * external clock is assumed faulty. * local clock and the time provider * isverbose -boolean, > 0 indicates that informational messages * will be displayed. * * * * Implicit Outputs: * none. * * Value Returned: * none. * * Side Effects: * none. * *-- */void InitializeTPdefaults(pollrate,timestamp, inaccuracy,tmorate, clockSet,retries, firstsynch,maxtperror, isverbose)int *pollrate, *timestamp, *inaccuracy, *tmorate, *clockSet, *retries, *firstsynch, *maxtperror, *isverbose;{ *pollrate = NTP_POLL_RATE; /* seconds */ *timestamp = NTP_TIME_STAMPS; /* int, 1-6 */ *inaccuracy= NTP_INACCURACY; /* seconds */ *tmorate = NTP_TIMEOUT; /* seconds */ *clockSet = NTP_NOCLOCKSET; /* int, t/f - 1/0 */ *retries = NTP_RETRIES; /* int > 0 */ *firstsynch= NTP_FIRSTSYNCH; /* int > 0 */ *maxtperror= NTP_MAXTPERROR; /* seconds */ *isverbose = NTP_ISVERBOSE; /* int > 0 */}/* End of routine InitializeTPdefaults */ CleanupNTP(){int retval; retval = shutdown(ttchan,2); if (retval == -1) perror("shutdown"); retval = close(ttchan); if (retval) perror("close");}InitNTP(){int service_port; /* * Create a socket and bind it to ntp/udp */ if ((ttchan = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr,"dtssprovider: NTP socket - %d",errno); return(0); }#if 0 sp = getservbyname("ntp", "udp"); if (sp <= NULL) { (void) fprintf(stderr, "dtssprovider: UDP/NTP: service unknown\n"); (void) fprintf(stderr, "dtssprovider: Assuming NTP port is %d", K_NTP_DEF_SERVICE_PORT); dst.sin_port = htons(K_NTP_DEF_SERVICE_PORT); } else { dst.sin_port = htons(sp->s_port); }#else dst.sin_port = htons(K_NTP_DEF_SERVICE_PORT);#endif /* * Lookup host name and address */ hp = gethostbyname(hostname); if (hp <= NULL) { (void) fprintf(stderr, "dtssprovider: No such host %s : %d\n", hostname,errno); close(ttchan); return(0); } dst.sin_family = hp->h_addrtype; dst.sin_addr = *((struct in_addr *)hp->h_addr); return(1);} /* *++ * QueryProvider() * * Functional Description: * * Query an NTP server for the time. Generate the timestamp triplet. * * Inputs: * * fd - file descriptor to read. * * Outputs: * * providerTime - return utc time, constructed from the NTP response. * beforeTime - the utc just before the request is sent. * afterTime - the utc just after the reply is received. * * Value Returned: * * -1 Unequivocal failure - Stratum too far from TP. * 0 Success * 1 Timeout failure - retry warranted. * *-- */int QueryProvider(fd, beforeTime, providerTime, afterTime)int fd;struct utc *providerTime;struct utc *beforeTime;struct utc *afterTime;{ struct timeval timeout; /* time out value for select */ fd_set readfds; /* mask of file descriptors */ int n; /* file descriptor selected on */ int nfds = fd+1; /* number of fds to select on */ struct utc ref, t1, t2, t3, t4; /* NTP timestamps */ timespec_t synchdist; /* NTP synchronization distance */ timespec_t timesp, inaccsp; /* Temps for time computation */ memset((char *)pkt, 0, sizeof(ntp_data)); FD_ZERO(&readfds); FD_SET(fd, &readfds); timeout.tv_sec = K_NTP_TIMEOUT; timeout.tv_usec = 0; pkt->status = K_NTP_VERSION1; pkt->stratum = K_NTP_UNSPECIFIED; pkt->poll = 6; /* * Record 'before' timestamp */ (void) utc_gettime(beforeTime); cvt_utc_ntp(&pkt->xmt, beforeTime); if ((sendto(fd, (char *)pkt, sizeof(ntp_data), 0, (struct sockaddr *) &dst, dstlen)) < 0) { perror("dtssprovider: NTP sendto"); exit(1); } /* * Wait for the reply by watching the file descriptor */ if ((n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &timeout)) < 0){ perror("dtssprovider: NTP select"); exit(1); } if (n == 0) { (void) fprintf(stderr, "\n\t* Timeout *\n"); return(0); } if ((recvfrom(fd, (char *)pkt, sizeof (ntp_data), 0, (struct sockaddr *) &socketin, &dstlen)) < 0) { perror("dtssprovider: NTP recvfrom"); exit(1); } /* * Record 'after' timestamp */ (void) utc_gettime(afterTime); (void) printf("Packet from: [%s]\n", inet_ntoa(socketin.sin_addr)); (void) printf("Status: %d\tStratum: %d\n", (int)(pkt->status & 0x03f), pkt->stratum); /* * Check stratum of timestamp */ if (pkt->stratum >= K_DTS_NTP_STRATUM) return(0); /* * Compute ntp time from information in the ntp message */ cvt_ntp_utc(&ref, &pkt->reftime); t1 = *beforeTime; cvt_ntp_utc(&t2, &pkt->rec); cvt_ntp_utc(&t3, &pkt->xmt); t4 = *afterTime; synchdist.tv_sec = ntohs((u_short) pkt->distance.sint_part); synchdist.tv_nsec = (u_long) ( (double)ntohs((u_short) pkt->distance.sfraction) * (double)K_NS_PER_SEC / 65536.0 ); (void) utc_bintime(×p, (timespec_t *)0, (long *)0, &t2); inaccsp.tv_sec = synchdist.tv_sec + INACCURACY/K_MS_PER_SEC; inaccsp.tv_nsec = synchdist.tv_nsec + ((INACCURACY%K_MS_PER_SEC) * K_NS_PER_MS); if (inaccsp.tv_nsec > K_NS_PER_SEC) { inaccsp.tv_sec++; inaccsp.tv_nsec -= K_NS_PER_SEC; }; (void) utc_mkbintime(providerTime, ×p, &inaccsp, 0L); return(1);} /* *++ * cvt_utc_ntp() * * Functional Description: * * Convert a utc timestamp into an NTP timestamp. * * Inputs: * * utc - pointer to utc timestamp. * * Outputs: * * ntp - pointer to ntp timestamp. (See NTP spec for format). * * Value Returned: * * None. * *-- */void cvt_utc_ntp( ntp, utc )struct l_fixedpt *ntp;struct utc *utc;{ timespec_t timesp; (void) utc_bintime(×p, (timespec_t *)0, (long *)0, utc); ntp->int_part = ntohl((u_long) (K_NTP_JAN_1970 + timesp.tv_sec)); ntp->fraction = ntohl((u_long) ((float) timesp.tv_nsec * 4.294967295));} /* *++ * cvt_ntp_utc() * * Functional Description: * * Convert an NTP timestamp into a utc timestamp. * * Inputs: * * ntp - pointer to ntp timestamp. (See NTP spec for format). * * Outputs: * * utc - pointer to utc timestamp. * * Value Returned: * * None. * *-- */void cvt_ntp_utc( utc, ntp )struct utc *utc;struct l_fixedpt *ntp;{ timespec_t timesp; timesp.tv_sec = ntohl(ntp->int_part) - K_NTP_JAN_1970; timesp.tv_nsec = ((u_long)ntohl(ntp->fraction)) / 4.294967295; (void) utc_mkbintime(utc, ×p, (timespec_t *)0, 0L);} /* ********************************************************** * output Routines. ********************************************************** *//* *++ * PrintTimes() * * Functional Description: * * Print the Result of a synchronization. * * * Inputs: * * before,after,tptimes - time values used in the synch. * * Implicit Inputs: * * None. * * Outputs: * * None. * * Implicit Outputs: * * None. * * Value Returned: * * None. * * Side Effects: * * None. *-- */PrintTimes( timeResponse )TPrspMsg *timeResponse;{ int i; char timestr[UTC_MAX_STR_LEN]; if ( timeResponse->status == K_TPI_FAILURE ) { (void) fprintf(stdout, "K_TPI_FAILURE\n"); (void) fprintf(stdout, "********************* %u *********************\n", SYNCHCOUNT); return; } (void) printf("TPsuccessful\n"); (void) printf("Serial Number : %d\n", timeResponse->TPsyncID); (void) printf("Time Stamps : %d\n", timeResponse->TPdata.TimeMsg.timeStampCount); for ( i = 0; i < timeResponse->TPdata.TimeMsg.timeStampCount; i++) { (void) printf("Before Time\t:"); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].beforeTime); (void) printf("%s\nTP Time\t\t:",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].TPtime); (void) printf("%s\nAfter Time\t:",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN, &timeResponse->TPdata.TimeMsg.timeStampList[i].afterTime); (void) printf("%s\n",timestr); } (void)printf("******************************************\n");} /* *++ * PrintValidationError() * * Functional Description: * * The timeprovider is returning invalid times, report * to the user. * * Inputs: * * None. * * Implicit Inputs: * * SYNCHCOUNT,MAXTPERROR. * * Outputs: * * None. * * Implicit Outputs: * * * Value Returned: * * None. * * Side Effects: * * None. * *-- */PrintValidationError(systemTime,externalTime)struct utc *systemTime;struct utc *externalTime;{char timestr[UTC_MAX_STR_LEN]; fprintf(stderr,"\n!!!!!!!!! DTSS: EXTERNAL TIME SOURCE IS FAULTY !!!!!!!!!\n"); fprintf(stderr,"The external time did not validate\n"); fprintf(stderr,"Synchronization Count: %u\n",SYNCHCOUNT); fprintf(stderr,"Error Tolerance: %u\n",MAXTPERROR); utc_ascgmtime(timestr,UTC_MAX_STR_LEN,systemTime); fprintf(stderr,"System Time: %s\n",timestr); utc_ascgmtime(timestr,UTC_MAX_STR_LEN,externalTime); fprintf(stderr,"External Device Time: %s\n",timestr); fprintf(stderr,"\n!!!!!!!!!!!!!!!!!!\n"); }#pragma standard/* DEC/CMS REPLACEMENT HISTORY, Element DTSS$NTP_PROVIDER.C */