Re: [uCsimm] Setting date/time on uCsimm

From: Phil Wilshire (philwil@on-ramp.ior.com)
Date: Thu Mar 16 2000 - 09:36:23 EST


Patrick
Great work...
Can I include it in the realtimelinux.org CRAN archive please
Thanks
  Phil Wilshire

>
> Joe Lang and I have written a program that allows uCsimm to go out via the
> Internet and get the time from the US National Institute of Standards and
> Technology (NIST) and set the system time.
>
> It does adjust for network traffic, Daylight Savings Time, leap seconds and
> so forth. We even called NIST in Boulder for clarification about some of
> the algorithm because the RFC on the subject (RFC-857) is not in complete
> agreement with the data they provide via their time servers. We included
> the best parts of that RFC in doc.txt to further describe the program.
>
> We hope that this is a useful program to other uCsimm users both for the
> time and as an example of client/server programming on the uCsimm.
>
> The program, pasted below for those users for whom attachments are
> problematic, and attached for others, should compile directly. It requires
> no special libraries and has no hooks in it. The attachments to this
> e-mail are in plain, unformatted ASCII to avoid viruses.
>
> All the best,
>
> Pat Stingley (stingley@cpcug.org) and Joe Lang (lang@thunder.nws.noaa.gov).
>
> ----------------------------------------------------------------------------
> --------------
> /* stp - Simple Time Protocol - This program makes the uCsimm contact the
> US National Institute of Technology(NIST) and get the current time via the
> Internet. This program uses no non-standard libraries.
> Developed by Joe Lang Lang@thunder.nws.noaa.gov and Pat Stingley
> stingley@cpcug.org
>
> Copyright 2000 in accordance with the GPL.
>
> Daytime Protocol Usage: stp [minutes west of Zulu][DST - yes/no]
> */
>
> #include <ctype.h>
> #include <errno.h>
> #include <netdb.h>
> #include <netinet/in.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <sys/time.h>
> #include <sys/socket.h>
> #include <time.h>
> #include <unistd.h>
>
> #define PROGRAM_NAME "stp"
>
> #define TRUE 1
> #define FALSE 0
>
> #define CHAR_NULL ((char *) NULL)
> #define NULL_CHAR '\0'
>
> #define ADDR_CAST (struct sockaddr *)
>
> #define NO_HOST_INFO -1
> #define NO_SERVICE_INFO -2
> #define NO_CONNECT -3
> #define BAD_DATA_SIZE -4
> #define NO_SOCKET -5
> #define NOT_HEALTHY -6
> #define INCOMPLETE_DATA -7
>
> #define SPM 60 /* Seconds Per Minute */
> #define SPH 3600 /* Seconds Per Hour */
>
> /* Function prototypes. */
> int DayTimeProtocol( char *nist_time_host, struct timeval *tv_ptr,
> struct timezone *tz_ptr, int minutes_west, int use_dst );
>
> int lc_client( char *the_host, char *the_service,
> char *the_protocol, int *sd_ptr );
>
> int lc_connect( int sd, struct hostent *hp, struct servent *sp );
>
> int lc_get_host_info( char *host_name, struct hostent **hpp );
>
> int lc_get_service_info( char *service, char *protocol, struct servent
> **spp );
>
> int lc_socket( int *sd_ptr, int socket_type );
>
> int lc_read_data( int sd, void *data, int max_bytes );
>
> /* Static/global variables for recording errors. */
> static int g_error; /* global error number variable for the stp program */
> static char g_error_msg[BUFSIZ]; /* global error message buffer for the stp
> program */
>
> /* NIST Time Hosts. */
> static char *nist_time_hosts[] =
> {
> "time-a.nist.gov",
> "time-b.nist.gov",
> "time-a.timefreq.bldrdoc.gov",
> "time-b.timefreq.bldrdoc.gov",
> "time-c.timefreq.bldrdoc.gov",
> "utcnist.colorado.edu",
> "time.nist.gov",
> "time-nw.nist.gov",
> "nist1.dc.certifiedtime.com",
> "nist1.datum.com",
> "nist1.nyc.certifiedtime.com",
> "nist1.sjc.certifiedtime.com",
> CHAR_NULL
> };
>
> int main( int argc, char *argv[] )
> {
> char host_name[BUFSIZ];
> struct timeval tv;
> struct timezone tz;
> int minutes_west;
> int use_dst; /* Indicates if we should use DST if applicable. */
> int i; /* loop variable */
> int rv; /* return value (rv) variable */
> char *minutes_west_argument;
> int valid_minutes_west_argument;
> int got_nist_time;
> int the_time_was_set;
> time_t current_time_in_seconds;
>
> /* Determine the name of our host. */
> gethostname( host_name, sizeof( host_name ) );
>
> /* Process the command line. */
> switch ( argc )
> {
>
> case 1: /* command line: stp --- defaulting to GMT/UTC. */
>
> minutes_west = 0; /* Default to GMT */
>
> use_dst = FALSE; /* The default is not to use DST. */
>
> break;
>
> case 2: /* command line: stp minuteswest */
> case 3: /* command line: stp minuteswest yes_or_no */
>
> /* Point to the argument that specifies the minutes west. */
> minutes_west_argument = argv[1];
>
> /* Scan the minutes west argument for the specified minutes west value. */
> rv = sscanf( minutes_west_argument, "%d", &minutes_west );
>
> valid_minutes_west_argument = (rv == 1);
>
> if ( ! valid_minutes_west_argument )
> {
>
> fprintf( stderr, "Invalid value [%s] forMinutesWest.\n",
> minutes_west_argument );
>
> exit( 1 );
>
> }
>
> /* Was the yes/no DST value specified? */
> if ( argc == 3 )
> {
> rv = strcasecmp( argv[2], "no" );
> use_dst = (rv != 0); /* argv[2] did not equal "no" */
> }
> else use_dst = TRUE; /* The default is to use DST if minutes west
> is provided. */
>
> break;
>
> default:
>
> fprintf( stderr, "Error In Usage!\n" );
>
> fprintf( stderr, "Proper Usage: %s MinutesWest [yes] or [no]\n",
> PROGRAM_NAME );
>
> exit( 0 );
>
> break;
>
> } /* switch ( argc ) */
>
> /* Find a NIST host to supply us with the current UTC time. */
> for (i = 0; nist_time_hosts[i] != CHAR_NULL; i++)
> {
>
> rv = DayTimeProtocol( nist_time_hosts[i], &tv,&tz,
> minutes_west, use_dst );
>
> got_nist_time = (rv == 0);
>
> if ( got_nist_time ) break;
>
> } /* for ( i ) */
>
> if ( ! got_nist_time )
> {
> fprintf( stderr, "No NIST Time!\n" );
> fprintf( stderr, "%s\n", g_error_msg );
> exit( 1 );
> }
>
> printf( "%s received the time from: %s Server #%d\n",
> host_name, nist_time_hosts[i], i + 1 );
>
> /* Must be the super user (root) to successfully execute settimeofday(). */
> rv = settimeofday( &tv, &tz );
>
> the_time_was_set = (rv == 0);
>
> if ( ! the_time_was_set )
> {
> perror( "settimeofday()" );
> exit( 1 );
> }
>
> /* Display the current system time. */
> time( &current_time_in_seconds );
>
> printf( "The System Time: %s", ctime( &current_time_in_seconds ) );
>
> return 0;
> } /* main() */
>
> int DayTimeProtocol( char *nist_time_host, struct timeval *tv_ptr,
> struct timezone *tz_ptr, int minutes_west, int use_dst )
> {
> int sd; /* socket descriptor */
> int rv; /* return value (rv) variable */
> int offset;
> char c;
> char buf[BUFSIZ];
> long modified_julian_day; /* read from the NIST time string */
> int month;
> int day;
> int year;
> int hour;
> int minute;
> int second;
> int US_time; /* the reference to Daylight Savings Time (DST) in the NIST
> time string */
> int US_standard_time; /* Indicates if the United States are observing DST */
> int leap_second;
> int server_health_digit;
> char ms_advanced_str[BUFSIZ];
> char nist_str[BUFSIZ];
> char otm_str[BUFSIZ]; /* the On-Time Marker (OTM) */
> struct tm time_structure;
> time_t time_in_seconds;
>
> /**
> Initialize the input "time" structures.
> Fill them with zeroes.
> **/
> memset( tv_ptr, 0, sizeof( *tv_ptr ) );
>
> memset( tz_ptr, 0, sizeof( *tz_ptr ) );
>
> /* Initialize the client socket logic. */
> rv = lc_client( nist_time_host, "daytime", "tcp", &sd );
>
> /* An error? */
> if ( rv ) return 1;
>
> /**
> Read the time string from the NIST server.
> rv = The number of bytes read.
> **/
> rv = lc_read_data( sd, buf, sizeof( buf ) );
>
> /* Disconnect the socket connection with the NIST time server. */
> close( sd );
>
> /* Null terminate the received NIST time string. */
> buf[rv] = NULL_CHAR;
>
> /* Scan the NIST time string for the necessary values. */
> rv = sscanf( buf,
> "%ld " /* Modified Julian date */
> "%d-%d-%d " /* the date yy-mm-dd */
> "%d:%d:%d " /* the time hh:mm:ss */
> "%d "
> "%d "
> "%d "
> "%s "
> "%s "
> "%s ",
> &modified_julian_day,
> &year, &month, &day,
> &hour, &minute, &second,
> &US_time,
> &leap_second,
> &server_health_digit,
> ms_advanced_str,
> nist_str,
> otm_str );
>
> /* Were all 13 time relative fields in the string from the NIST time
> server? */
> if ( rv != 13 )
> {
> g_error = INCOMPLETE_DATA;
> sprintf( g_error_msg, "The received data buffer was incomplete." );
> return 1;
> }
>
> /* Was the time server healthy? */
> if ( server_health_digit != 0 )
> {
> g_error = NOT_HEALTHY;
> sprintf( g_error_msg, "Server Health Digit: %d", server_health_digit );
> return 1;
> }
>
> /* Set the United States DST indicator flag variable. */
> US_standard_time = ( ( US_time == 0 ) || ( US_time > 50 ) );
>
> memset( &time_structure, 0, sizeof( time_structure ) );
>
> time_structure.tm_hour = hour;
>
> time_structure.tm_min = minute;
>
> time_structure.tm_sec = second;
>
> time_structure.tm_mon = month - 1; /* Jan = 0 ... and Dec = 11 */
>
> time_structure.tm_mday = day;
>
> time_structure.tm_year = year + 100; /* years since 1900 */
>
> /* Convert the time structure into "time in seconds". */
> time_in_seconds = mktime( &time_structure );
>
> tv_ptr->tv_sec = time_in_seconds;
>
> tv_ptr->tv_usec = 0; /* no microseconds */
>
> /* Adjustment relative to GMT. */
> tv_ptr->tv_sec += (-SPM * minutes_west);
>
> /* Handle Daylight Savings Time here. */
> if ( ( use_dst ) && ( ! US_standard_time ) )
> {
>
> /**
> Add one hour for DST.
> "Spring Forward"
> **/
> tv_ptr->tv_sec += SPH;
>
> }
>
> return 0;
> } /* DayTimeProtocol() */
>
> int lc_client( char *the_host, char *the_service,
> char *the_protocol, int *sd_ptr )
> {
> struct hostent *hp;
> struct servent *sp;
> int socket_type;
> int rv;
>
> /* Some initializations. */
> g_error = 0;
>
> *g_error_msg = NULL_CHAR;
>
> /* Get the host information. */
> rv = lc_get_host_info( the_host, &hp );
>
> if ( rv )
> {
> sprintf( g_error_msg, "gethostbyname() returned NULL for host: %s",
> the_host );
> g_error = NO_HOST_INFO;
> return 1;
> }
>
> /* Get the service information. */
> rv = lc_get_service_info( the_service, the_protocol, &sp );
>
> if ( rv )
> {
> sprintf( g_error_msg,
> "getservbyname() returned NULL for %s/%s",
> the_service, the_protocol );
> g_error = NO_SERVICE_INFO;
> return 1;
> }
>
> /* Determine the socket type. */
> if ( strcmp( the_protocol, "tcp" ) == 0 )
> socket_type = SOCK_STREAM;
> else socket_type = SOCK_DGRAM;
>
> /* Get a socket. */
> rv = lc_socket( sd_ptr, socket_type );
>
> if ( rv ) return 1;
>
> /* Attempt the connection. */
> if ( socket_type == SOCK_STREAM )
> {
>
> rv = lc_connect( *sd_ptr, hp, sp );
>
> if ( rv != 0 )
> {
> close( *sd_ptr );
> return 1;
> }
>
> }
>
> return 0;
> } /* lc_client() */
>
> int lc_connect( int sd, struct hostent *hp, struct servent *sp )
> {
> int rv;
> struct sockaddr_in sin;
>
> memset( &sin, 0, sizeof( sin ) );
>
> sin.sin_family = AF_INET;
>
> sin.sin_port = htons( sp->s_port );
>
> memcpy( &sin.sin_addr.s_addr, hp->h_addr, hp->h_length );
>
> rv = connect( sd, ADDR_CAST &sin, sizeof( sin ) );
>
> if ( rv )
> {
> sprintf( g_error_msg, "connect() failed: %s\n", strerror( errno ) );
> sprintf(g_error_msg + strlen(g_error_msg)," sd: %d\n",sd );
> g_error = NO_CONNECT;
> }
>
> return rv;
> } /* lc_connect() */
>
> int lc_get_host_info( char *host_name, struct hostent **hpp )
> {
> struct hostent *hp;
> int rv = 0;
>
> hp = gethostbyname( host_name );
>
> if ( hp == (struct hostent *) NULL )
> rv = 1;
> else *hpp = hp;
>
> return rv;
> } /* lc_get_host_info() */
>
> int lc_get_service_info( char *service, char *protocol, struct servent **spp )
> {
> static struct servent ses; /* service entry structure (ses) */
> struct servent *sp;
> int rv = 0;
>
> #ifdef use_getservbyname
> sp = getservbyname( service, protocol );
>
> if ( sp == (struct servent *) NULL )
> rv = 1;
> else *spp = sp;
>
> #else
>
> ses.s_proto = strdup( "tcp" );
>
> ses.s_port = 13;
>
> *spp = &ses;
>
> #endif
>
> return rv;
> } /* lc_get_service_info() */
>
> int lc_socket( int *sd_ptr, int socket_type )
> {
> int sd;
> int rv;
>
> sd = socket( AF_INET, socket_type, 0 );
>
> if ( sd == -1 )
> {
> sprintf( g_error_msg, "socket() returned -1" );
> g_error = NO_SOCKET;
> rv = 1;
> }
> else
> {
> *sd_ptr = sd;
> rv = 0;
> }
>
> return rv;
> } /* lc_socket() */
>
> int lc_read_data( int sd, void *data, int max_bytes )
> {
> int bytes = 0;
> int rv;
> char c;
> char *buf = data;
>
> while ( ( rv = read( sd, &c, sizeof( c ) ) ) == sizeof( c ) )
> {
> buf[bytes] = c;
> ++bytes;
> if ( bytes == max_bytes ) break;
> }
>
> return bytes;
> } /* lc_read_data() */
>
> ------------------------------------------------------------------------
>
> stp.cName: stp.c
> Type: Plain Text (text/plain)
>
> doc.txtName: doc.txt
> Type: Plain Text (text/plain)
This message resent by the ucsimm@uclinux.com list server http://www.uClinux.com/



This archive was generated by hypermail 2b30 : Sun Apr 07 2002 - 00:01:35 EST