home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: InfoMgt
/
InfoMgt.zip
/
nistimex.zip
/
nistime.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-12
|
16KB
|
396 lines
/* nistime.c - query and set time from NIST server */
/* ------------------------------ */
/* Feature test macros */
/* ------------------------------ */
/* #define _POSIX_SOURCE /* Always require POSIX standard */
/* ------------------------------ */
/* Standard include files */
/* ------------------------------ */
#define INCL_DOSDATETIME
#include <os2.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <types.h> /* Will be OS/2 TCP/IP types.h file */
#include <sys/socket.h> /* More TCP/IP include files */
#include <netinet/in.h>
#include <arpa/inet.h>
/* ------------------------------ */
/* Local include files */
/* ------------------------------ */
/* ------------------------------- */
/* My local typedef's and defines */
/* ------------------------------- */
#define panic SysPanic(__FILE__, __LINE__)
#define NIST_TIME_INET_ADDRESS "132.163.135.130" /* time.nist.gov */
#define NIST_TIME_PORT 13 /* specific port */
#define UNIX_EPOCH_MJD 40587 /* UNIX epoch date */
/* ------------------------------- */
/* My external function prototypes */
/* ------------------------------- */
/* ------------------------------- */
/* My internal function prototypes */
/* ------------------------------- */
static int sw(int argc, char *arg, char *let, long *val);
static int ShiftTime(time_t diff);
static void PrintUsage(void);
/* ------------------------------- */
/* My usage of other external fncs */
/* ------------------------------- */
/* ------------------------------- */
/* Locally defined global vars */
/* ------------------------------- */
/* ---------------------------------------------------------------------------
- client process to connect to the daytime service via port 13 from nist
- time server.
-
- This OS/2 implementation is a port of the unix utility by the same name
- obtained by anonymous FTP from time_a.timefreq.bldrdoc.gov. My apologies
- to Judah Levine for the hack of his code. For questions about this OS/2
- implementation, contact:
-
- Michael Thompson
- Cornell University
- Dept. of Materials Science
- 129 Bard Hall
- tommy@msc.cornell.edu
-
-
- The client process uses the time message received to check (and optionally
- to set) the time of the local clock. the comparison assumes that the local
- clock keeps time in seconds from 1/1/70 which is the UNIX standard, and it
- computes the time difference by converting the received MJD to seconds
- since 1/1/70 and adding the received hr, min and sec, also converted to
- seconds. If the local machine keeps time in some other way, then the
- comparison method will have to change, but the rest should be okay.
-
- This software was developed with US Government support and it may not be
- sold, restricted or licensed. You may duplicate this program provided
- that this notice remains in all of the copies, and you may give it to
- others provided they understand and agree to this condition.
-
- This program and the time protocol it uses are under development and the
- implementation may change without notice.
-
- For questions or additional information, contact:
-
- Judah Levine
- Time and Frequency Division
- NIST/847
- 325 Broadway
- Boulder, Colorado 80303
- (303) 492 7785
- jlevine@time_a.timefreq.bldrdoc.gov
--------------------------------------------------------------------------- */
int main(int argc, char *argv[]) {
/* Internet socket access parameters */
char *cp = NIST_TIME_INET_ADDRESS; /* server address in . notation */
int pserv = NIST_TIME_PORT; /* port for time service */
long address; /* ip address */
struct sockaddr_in *sin; /* socket address structure */
int s; /* socket number */
int length; /* size of message */
char buf[132]; /* holds message */
time_t my_time, nist_time; /* Time since epoch */
time_t diff; /* time difference, local - NIST */
/* Values obtained from the internet message */
long mjd0 = UNIX_EPOCH_MJD; /* MJD of the UNIX EPOCH */
long mjd; /* holds parsed received mjd */
int yr,mo,dy,hr,min,sec; /* holds parsed received time */
int day_light, /* Daylight savings flag */
leap_sec, /* Leap second status */
health; /* Health of server status */
/* Local variables */
char achr; /* Random character */
char let; /* command-line letter */
long val; /* command line value */
/* ---------------------------------------------------------------------------
- the following variables define what this program should do and what
- output should be produced. The values below are the defaults which
- may be changed by characters on the command line as described below.
- The effect of each variable is as follows:
-
- Command-Line Switch effect
- -m0 msg = 0 Do not produce any messages; only time difference is
- written to standard output.
- -m1 or -M = 1 Produce short messages.
- -m2 = 2 Produce longer messages.
-
- -s0 set = 0 Do not adjust local time.
- -s1 or -S = 1 Adjust local time if server is healthy.
- -s2 = 2 Adjust local time even if server is unhealthy.
- -s3 = 3 Ask operator first.
--------------------------------------------------------------------------- */
int msg = 1; /* default is short messages */
int set = 3; /* default is ask before setting clock */
/* parse command line switches */
++argv; --argc; /* Skip command name */
while (sw(argc, argv[0], &let, &val) != 0) { /* Switch present */
switch (let) {
case '?':
case 'h':
case 'H':
PrintUsage();
return(EXIT_SUCCESS);
case 'm':
msg=val;
break;
case 's':
set=val;
break;
case 'S':
set=1;
break;
case 'M':
msg=1;
break;
default:
fprintf(stderr, "\nSwitch %c not recognized.\n", let);
break;
}
argc--; /* decrement argument counter */
argv++; /* and increment pointer */
}
/* -----------------------------------------------------------------
-- (1) Make sure we are using the TZ variable
-- (2) Convert xxx.xxx internet address to internal format
-- (3) allocate space for socket info, and fill int
-- (4) Create socket
-- (5) Connect to server. Note this is a stream server and
-- record boundaries are not preserved.
-- (6) Query local time via time() call
-- (7) Close socket and free allocated memory
----------------------------------------------------------------- */
_tzset(); /* Get timezone from TZ */
sock_init(); /* Initialize sockets */
if ( (address=inet_addr(cp)) == -1) { /* Internal format */
fprintf(stderr,"Internet address error.\n");
return(EXIT_FAILURE);
}
if ( (sin = calloc(sizeof(*sin), 1)) == NULL) { /* Allocate space */
fprintf(stderr, "Unable to allocate memory for socket info.\n");
return(EXIT_FAILURE);
}
sin->sin_family = AF_INET; /* Fill in request */
sin->sin_addr.s_addr = address;
sin->sin_port = htons(pserv);
/* Now, create socket, open and read */
if ( (s = socket(AF_INET, SOCK_STREAM, 0) ) < 0) { /* Get a socket */
fprintf(stderr,"Socket creation error.\n");
return(EXIT_FAILURE);
} else if (connect(s, (struct sockaddr *) sin, sizeof(*sin) ) < 0) {
fprintf(stderr, "Failed to connect to time server: %d\n", tcperrno());
return(EXIT_FAILURE);
}
if ( (length = recv(s, buf, sizeof(buf)-1, 0)) <= 0) {
fprintf(stderr, "No response from NIST server.\n");
soclose(s);
return(EXIT_FAILURE);
}
buf[length] = '\0'; /* terminate msg */
/* Immediately, get local time as well for comparison */
if ( (my_time = time(NULL)) == (time_t) -1) {
fprintf(stderr, "Unable to determine local clock time\n");
return(EXIT_FAILURE);
}
/* And close socket, free allocated space */
soclose(s); /* Close port and free memory now */
free(sin);
/* --------------------------------------------------------------------------
-- convert received time to seconds since EPOCH and subtract this from the
-- local time in the same units. Since POSIX makes no specification about
-- times less than 1 second, and the internet message only goes to seconds,
-- look only this far and ignore smaller differences. Fortunately, the delay
-- in the net should be no more than about 0.05 seconds (according to NIST).
--------------------------------------------------------------------------- */
sscanf(buf," %ld %2d-%2d-%2d %2d:%2d:%2d %d %d %d",
&mjd, &yr, &mo, &dy, &hr, &min, &sec, &day_light, &leap_sec, &health);
nist_time = 86400*(mjd-mjd0) + 3600*hr + 60*min + sec;
diff = my_time - nist_time;
/* --------------------------------------------------------------------------
-- Output various reports to stdout depending on the setting of msg
-- parameter.
--------------------------------------------------------------------------- */
/* Output desired messages */
if (msg != 0) {
printf(" Time message received:\n");
printf(" D L\n");
printf(" MJD YY MM DD HH MM SS ST S H Adv.%s", buf);
}
if (msg == 2) { /* longer messages selected */
if( (day_light == 0) || (day_light > 51) ) {
printf("Standard Time now in effect\n");
if (day_light > 51)
printf("Change to Daylight Saving Time in %d days\n",day_light-51);
}
if( (day_light <= 50) && (day_light > 1) ) {
printf("Daylight Saving Time now in effect\n");
if (day_light > 1 && day_light != 50)
printf("Change to Standard Time in %d days\n", day_light-1);
}
if (day_light == 1) printf("Standard time begins at 2am today\n");
if (day_light == 51) printf("Daylight Saving Time begins at 2am today\n");
if (leap_sec == 1) printf("Leap Second to be added at end of month\n");
if (leap_sec == 2) printf("Second to be dropped at end of month\n");
}
if (msg == 0) { /* no messages except time diff */
printf("%ld", diff);
} else {
printf("Local Clock - NIST = %ld second(s)\n", diff);
}
/* --------------------------------------------------------------------------
-- Deal with possibly resetting the clock based on setting of set parameter
--------------------------------------------------------------------------- */
if (set == 0 || diff == 0) {
if (diff == 0 && msg != 0) printf("\n No adjustment is needed.\n");
return(EXIT_SUCCESS);
}
if( (health != 0) && (msg != 0) )
printf("\n Server is not healthy, adjustment not recommended.");
achr = 'n'; /* default is not to set */
if (set == 3) { /* action depends on answer to query */
printf("Do you want to adjust the local clock ? [y/n] ");
fflush(stdout);
achr = getchar();
}
if ( (set==2) || (set==1 && health==0) || (tolower(achr) == 'y') ) {
if (ShiftTime(diff) != 0) {
fprintf(stderr, "Unable to modify system clock\n");
return(EXIT_FAILURE);
} else {
if (msg != 0) printf("Local clock time reset to NIST standard\n");
}
}
return(EXIT_SUCCESS);
}
/* ---------------------------------------------------------------------------
--
-- Inputs: diff - Time difference from current setting
--------------------------------------------------------------------------- */
static int ShiftTime(time_t diff) {
DATETIME os2_time;
struct tm *tm;
time_t newtime;
int rc;
DosGetDateTime(&os2_time); /* Fill in unknown components */
newtime = time(NULL) - diff; /* Get corrected time */
tm = localtime(&newtime); /* Fill in the structure */
os2_time.hours = tm->tm_hour;
os2_time.minutes = tm->tm_min;
os2_time.seconds = tm->tm_sec;
os2_time.hundredths = 0;
os2_time.day = tm->tm_mday;
os2_time.month = tm->tm_mon + 1;
os2_time.year = tm->tm_year + 1900;
os2_time.weekday = tm->tm_wday;
rc = DosSetDateTime(&os2_time);
return(rc);
}
/* ---------------------------------------------------------------------------
- this subroutine parses switches on the command line.
- switches are of the form -<letter><value>. If one is found, a pointer to
- the letter is returned in let and a pointer to the value in val as a
- long integer.
-
- parameters argc and argv are passed in from the main calling program.
- Note that if argc = 0, no arguments are left.
- if a switch is decoded, the value of the function is 1, otherwise zero.
-
- a number following the letter is decoded as a decimal value unless it
- has a leading x in which case it is decoded as hexadecimal.
--------------------------------------------------------------------------- */
static int sw(int argc, char *arg, char *let, long *val) {
/* either nothing is left or what is left is not a switch */
if( (argc == 0) || (*arg != '-') ) {
*let = '\0';
*val = 0;
return(0);
}
++arg; /* Jump over the - sign */
*let = *arg++; /* Letter option */
if (*arg != 'x') { /* if next char is not x, decode number */
*val = atol(arg);
} else { /* Use sscanf to interpret complex value */
sscanf(arg+1, "%lx", val);
}
return(1);
}
/* ---------------------------------------------------------------------------
- Routine to print the usage in response to a -? option.
--------------------------------------------------------------------------- */
static void PrintUsage(void) {
fputs(
" Syntax: nistime [ options ]\n"
"\n"
" Description:\n"
" This program connects to the daytime service on the NIST time server\n"
" time_a.timefreq.bldrdoc.gov using tcp/ip port 13. The time server\n"
" returns the current time which is then compared with the time of the\n"
" local clock. The difference may be used to adjust the time of the\n"
" local clock using DosSetDateTime().\n"
"\n"
" Options:\n"
" -m0 Terse mode. Only the time difference in seconds is written\n"
" to standard output. A positive value means local clock is fast.\n"
" -m1 Display short time messages. (also -M and default)\n"
" -m2 Display verbose time messages.\n"
"\n"
" -s0 Do not set the local clock.\n"
" -s1 Set the local clock if the server is healthy. (also -S)\n"
" -s2 Set the local clock even if the server is not healthy.\n"
" -s3 Query operator before setting the clock. (default)\n"
"\n"
"Bugs: (1) This version does not estimate transmission delays in the network.\n"
" Not a big deal since time is set to the nearest second only.\n"
" (2) Time is instantaneously reset and thus may be non-monotonic.\n"
, stdout);
return;
}