diff options
author | Martin Burnicki <martin.burnicki@meinberg.de> | 2014-04-01 12:00:00 +0200 |
---|---|---|
committer | Martin Burnicki <martin.burnicki@meinberg.de> | 2014-04-01 12:00:00 +0200 |
commit | 753f5617f666edb989500b2d9aab3656328f18c3 (patch) | |
tree | 20f48b86be11be50d71435080e58210fdeadcd52 | |
download | ntptest-753f5617f666edb989500b2d9aab3656328f18c3.tar.gz ntptest-753f5617f666edb989500b2d9aab3656328f18c3.zip |
Initial version1.0
-rwxr-xr-x | Makefile | 48 | ||||
-rwxr-xr-x | README | 103 | ||||
-rwxr-xr-x | mbglib/common/mbg_ntp_test_util.c | 286 | ||||
-rwxr-xr-x | mbglib/common/mbg_ntp_test_util.h | 292 | ||||
-rwxr-xr-x | mbglib/common/mbg_tgt.h | 590 | ||||
-rwxr-xr-x | mbglib/common/mbgntp.h | 208 | ||||
-rwxr-xr-x | mbglib/common/words.h | 363 | ||||
-rwxr-xr-x | ntptest.c | 310 |
8 files changed, 2200 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d2d947f --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ + +######################################################################### +# +# $Id: Makefile 1.1 2014/04/01 13:02:21 martin REL_M $ +# +# Description: +# Makefile for ntptest. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.1 2014/04/01 13:02:21 martin +# Initial revision. +# +######################################################################### + +TARGET = ntptest + +MBGLIB = mbglib +MBGLIB_DIRS = common + +OBJS = $(TARGET).o +OBJS += mbg_ntp_test_util.o + +ifdef DEBUG + CPPFLAGS += -g2 + CPPFLAGS += -DDEBUG=$(DEBUG) +else + CPPFLAGS += -O2 +endif + +CPPFLAGS += -Wall +CPPFLAGS += $(foreach dir,$(MBGLIB_DIRS),-I$(MBGLIB)/$(dir)) + +LDFLAGS += -lrt + +VPATH += $(foreach dir,$(MBGLIB_DIRS),$(MBGLIB)/$(dir)) + + +.PHONY: all +all: $(TARGET) + +$(TARGET): $(OBJS) + +.PHONY: clean +clean: + rm -f *.o *~ core + rm -f $(TARGET) + @@ -0,0 +1,103 @@ +$Id: README 1.1 2014/04/01 15:13:58 martin REL_M $ + +This is the README file for the ntptest tool which is similar to ntpdate +which comes with the NTP software package. It sends an NTP request packet +to an NTP server, receives the response packet, and evaluates the returned +information. + +Just unpack the tar.gz source code archive, cd into the extracted directory +and run "make" to build the executable. + +Then type "./ntptest -?" to get some usage information. + +At least the hostname or IP address of a remote NTP server has to be +specified on the command line, e.g.: + +------------------------------------------------------------------------------ +#ntptest> ./ntptest 172.16.100.43 + +ntptest v1.0, (c) Meinberg 2014, contact: <martin.burnicki@meinberg.de> + +Host 172.16.100.43 +Request packet: + mode 3, version 4, leap_ind 3, stratum 0, poll 6, prec 238 + root delay: 00000000 (0.0000 s) + root dispersion: 00000000 (0.0000 s/s) + reference id: 00000000 () + Ref time: 00000000.00000000 1900-01-01 00:00:00.000000000 + Org time (T1): 00000000.00000000 1900-01-01 00:00:00.000000000 + Rcv time (T2): 00000000.00000000 1900-01-01 00:00:00.000000000 + Xmt time (T3): D6E541C5.A4A2B11A 2014-04-01 13:46:45.643107479 + Curr time (T4): D6E541C5.A4A2B11A 2014-04-01 13:46:45.643107479 + +Response packet: + mode 4, version 4, leap_ind 0, stratum 1, poll 6, prec 237 + root delay: 00000000 (0.0000 s) + root dispersion: 00000008 (0.0001 s/s) + reference id: 0053524D (MRS) + Ref time: D6E541C4.09622D44 2014-04-01 13:46:44.036654309 + Org time (T1): D6E541C5.A4A2B11A 2014-04-01 13:46:45.643107479 + Rcv time (T2): D6E541C5.A4AEDE9B 2014-04-01 13:46:45.643293297 + Xmt time (T3): D6E541C5.A4B2FEF1 2014-04-01 13:46:45.643356260 + Curr time (T4): D6E541C5.A4BF6278 2014-04-01 13:46:45.643545297 + +turnaround: 437.818 (437.818..437.818) us (T4 - T1) +server latency: 62.963 (0.000..62.963) us (T3 - T2) +computed delay: 374.855 (374.855..374.855) us ((T4 – T1) – (T3 – T2)) +computed offset: -1.610 (-1.610..-1.610) us (((T2 – T1) + (T3 – T4)) / 2) +------------------------------------------------------------------------------ + +The output shows the contents of the request packet sent to the NTP server, +and the response packet received from the server. + +The values T1..T4 from the response packet are evaluated as suggested by the +NTP algorithms. + +The "turnaround" time (T4 - T1) tells how long it takes on the client until +a response is received after the request has been sent. + +The "server latency" value (T3 - T2) indicates the time interval on the server +until it sends the reply after it has received the request. + +The computed "delay" and "offset" numbers are the estimated packet delay +and time offset between the client and the server. + +If called with parameter -c the program runs continuously and sends one +request per second. The minimum and maximum numbers for the computed values +from several pollings are recorded and displayed. + + +Please note: + +- The only relevant number in the request packet is the transmit time (T3). + +- Upon receipt of the request packet the NTP server copies T3 into the + "originate time" field, which becomes T1 in the response packet seen + by the client. So T3 of the request packet should always match T1 of + the response packet. + +- The server latency may vary with the load on the NTP server. However, + this doesn't really matter since it is elimiated in the calculation + of the delay and offset on the client. + +- The computed delay and time offset can only be accurate if the packet + propagation delay is constant all the time, and the same for packets + in both directions. + +- In reality the packet propagation delay to or from the NTP server + *does* vary mor or less for each packet exchange (polling), and + there can be "spikes" where single packet in either direction are + delayed significantly longer than usual, in which case the computec + delay and offset are significantly off their mean values. + +- The NTP daemon has been designed to cope with such spikes, and the + "delay" and "offset" values displayed by "ntpq -p" are filtered values + based on weighted avarages from subsequent poll, so the results displayed + by this program will vary more than those displayed by "ntpq -p". + +- Don't run this program only with parameter -c against public NTP server. + Polling at 1 request per second can be considered as abusive. + Use the -s parameter to increase the sleep interval betweent to pollings + to at least 64 seconds (-s 64), which is the minimum polling interval + used by the NTP reference implementation. + diff --git a/mbglib/common/mbg_ntp_test_util.c b/mbglib/common/mbg_ntp_test_util.c new file mode 100755 index 0000000..59e6bcc --- /dev/null +++ b/mbglib/common/mbg_ntp_test_util.c @@ -0,0 +1,286 @@ + +/************************************************************************** + * + * $Id: mbg_ntp_test_util.c 1.1 2014/04/01 13:02:21 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions useful to test NTP implementations. + * + * ----------------------------------------------------------------------- + * $Log: mbg_ntp_test_util.c $ + * Revision 1.1 2014/04/01 13:02:21 martin + * Initial revision. + * + **************************************************************************/ + +#define _MBG_NTP_TEST_UTIL + #include <mbg_ntp_test_util.h> +#undef _MBG_NTP_TEST_UTIL + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <values.h> + + + +/*HDR*/ +void reset_query_stats( QUERY_STATS *p ) +{ + memset( p, 0, sizeof( *p ) ); + p->turnaround.min = MAXLONG; + p->turnaround.max = MINLONG; + p->ntp_delay.min = MAXDOUBLE; + p->ntp_delay.max = -MAXDOUBLE; + p->ntp_offs.min = MAXDOUBLE; + p->ntp_offs.max = -MAXDOUBLE; + +} // reset_query_stats + + + +/*HDR*/ +void print_stats_double( const char *info, int info_width, + double curr, int curr_width, double scale, + const MIN_MAX_DOUBLE *p, const char *hint ) +{ + if ( info ) + printf( "%-*s", info_width, info ); + + printf( "%*.3f", curr_width, curr * scale ); + + if ( p ) + printf( " (%.3f..%.3f)", p->min * scale, p->max * scale ); + + if ( hint ) + printf( "%s", hint ); + + printf( "\n" ); + +} // print_stats_double + + + +/*HDR*/ +void print_timespec_date_time( const struct timespec *p_ts ) +{ + time_t t = p_ts->tv_sec; + struct tm *tmp = gmtime( &t ); + + printf( "%04i-%02i-%02i %02i:%02i:%02i.%09li", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec, + (long) p_ts->tv_nsec + ); + +} // print_timespec_date_time + + + +/*HDR*/ +/** + * @brief Print date and time of an NTP time stamp + */ +void print_ntp_date_time( const NTP_TSTAMP *t_ntp ) +{ + struct timespec ts; + + ntp_tstamp_to_timespec( &ts, t_ntp ); + print_timespec_date_time( &ts ); + +} // print_ntp_date_time + + + +/*HDR*/ +/** + * @brief Print an NTP timestamp and optionally converted date and time + */ +void print_ntp_time( const char *msg, const NTP_TSTAMP *t, const char *tail ) +{ + printf( "%s%08lX.%08lX", msg, (long) (uint32_t) t->integer, (long) (uint32_t) t->fraction ); + + printf( " " ); + print_ntp_date_time( t ); + + if ( tail ) + printf( tail ); + +} // print_ntp_time + + + +// +// print contents of an NTP packet +// +/*HDR*/ +/** + * @brief Print contents of an NTP packet + */ +void print_ntp_packet( const char *msg, const NTP_PACKET *p, const NTP_TSTAMP *t_rcv ) +{ + int i; + char ref_id_str[80]; + char *cp = ref_id_str; + + printf( "%s\n", msg ); + + printf( INDENT + "mode %u, version %u, leap_ind %u, " + "stratum %u, poll %u, prec %u\n" + , + p->packet.flags.mode, + p->packet.flags.version, + p->packet.flags.leap_ind, + p->packet.flags.stratum, + p->packet.flags.poll, + p->packet.flags.precision + ); + + + for ( i = 0; ; ) + { + unsigned char uc; + uc = BYTE_OF( p->packet.reference_id, i ); + + if ( !isdigit( uc ) ) + { + sprintf( ref_id_str, "%.*s", + (int) sizeof( p->packet.reference_id ), + (char *) &p->packet.reference_id + ); + break; + } + + cp += sprintf( cp, "%u", uc ); + + if ( ++i >= sizeof( p->packet.reference_id ) ) + { + *cp = 0; + break; + } + + *cp++ = '.'; + } + + printf( + INDENT "root delay: %08lX (%.4f s)\n" + INDENT "root dispersion: %08lX (%.4f s/s)\n" + INDENT "reference id: %08lX (%s)\n" + , + (long) p->packet.root_delay, _u_fp_to_d( p->packet.root_delay ), + (long) p->packet.root_dispersion, _u_fp_to_d( p->packet.root_dispersion ), + (long) p->packet.reference_id, + ref_id_str + ); + + print_ntp_time( INDENT "Ref time: ", &p->packet.reference_time, newline ); + print_ntp_time( INDENT "Org time (T1): ", &p->packet.originate_time, newline ); + print_ntp_time( INDENT "Rcv time (T2): ", &p->packet.receive_time, newline ); + print_ntp_time( INDENT "Xmt time (T3): ", &p->packet.transmit_time, newline ); + + + if ( t_rcv ) + print_ntp_time( INDENT "Curr time (T4): ", t_rcv, newline ); + + printf( "\n" ); + +} // print_ntp_packet + + + +/*HDR*/ +void init_ntp_req_packet( NTP_PACKET *p, int req_mode, int prot_version ) +{ + memset( p, 0, sizeof( *p ) ); + + p->packet.flags.mode = req_mode; + p->packet.flags.version = prot_version; + p->packet.flags.leap_ind = 3; + p->packet.flags.stratum = 0; + p->packet.flags.poll = 6; + p->packet.flags.precision = 238; + +} // init_ntp_req_packet + + + +/*HDR*/ +int eval_ntp_packet( NTP_PACKET *p_rcv_packet, NTP_PACKET *p_req_packet, + const struct timespec *p_tsr_rcv, const struct timespec *p_tsr_req, + const NTP_TSTAMP *p_t_req_ntp, QUERY_STATS *p_stats ) +{ + double turnaround; + double latency; + double ntp_delay; + double ntp_offs; + double t34; + double t21; + NTP_TSTAMP t_rcv; // *p_tv_rcv converted to NTP format + + timespec_to_ntp_tstamp( &t_rcv, p_tsr_rcv ); + + ntoh_ntp_packet( p_req_packet ); + ntoh_ntp_packet( p_rcv_packet ); + + + // delay = (T4 – T1) – (T3 – T2) + // offset = ((T2 – T1) + (T3 – T4)) / 2 + + turnaround = delta_tstamps( &t_rcv, &p_rcv_packet->packet.originate_time ); // (T4 - T1) + latency = delta_tstamps( &p_rcv_packet->packet.transmit_time, &p_rcv_packet->packet.receive_time ); // (T3 - T2) + ntp_delay = turnaround - latency; + + t21 = delta_tstamps( &p_rcv_packet->packet.receive_time, &p_rcv_packet->packet.originate_time ); // (T2 - T1) + t34 = delta_tstamps( &p_rcv_packet->packet.transmit_time, &t_rcv ); // (T3 - T4) + ntp_offs = ( t21 + t34 ) / 2.0; + + + // update statistics begins + + p_stats->replies++; + + update_min_max_double( turnaround, &p_stats->turnaround ); + update_min_max_double( latency, &p_stats->latency ); + update_min_max_double( ntp_offs, &p_stats->ntp_offs ); + update_min_max_double( ntp_delay, &p_stats->ntp_delay ); + + // update statistics ended + + + // print results, if appropriate + + + print_ntp_packet( "Request packet:", p_req_packet, p_t_req_ntp ); + print_ntp_packet( "Response packet:", p_rcv_packet, &t_rcv ); + + { + int info_width = 17; + int val_width = 10; + double scale = 1e6; + + print_stats_double( "turnaround: ", info_width, turnaround, val_width, scale, + &p_stats->turnaround, " us (T4 - T1)" ); + + print_stats_double( "server latency: ", info_width, latency, val_width, scale, + &p_stats->latency, " us (T3 - T2)" ); + + print_stats_double( "computed delay: ", info_width, ntp_delay, val_width, scale, + &p_stats->ntp_delay, " us ((T4 – T1) – (T3 – T2))" ); + + print_stats_double( "computed offset: ", info_width, ntp_offs, val_width, scale, + &p_stats->ntp_offs, " us (((T2 – T1) + (T3 – T4)) / 2)" ); + } + + printf( "\n" ); + + return 1; + +} // eval_ntp_packet + + + diff --git a/mbglib/common/mbg_ntp_test_util.h b/mbglib/common/mbg_ntp_test_util.h new file mode 100755 index 0000000..2ef6241 --- /dev/null +++ b/mbglib/common/mbg_ntp_test_util.h @@ -0,0 +1,292 @@ + +/************************************************************************** + * + * $Id: mbg_ntp_test_util.h 1.1 2014/04/01 13:02:21 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes used with mbg_ntp_test_util.h + * + * ----------------------------------------------------------------------- + * $Log: mbg_ntp_test_util.h $ + * Revision 1.1 2014/04/01 13:02:21 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _MBG_NTP_TEST_UTIL_H +#define _MBG_NTP_TEST_UTIL_H + + +/* Other headers to be included */ + +#include <mbg_tgt.h> +#include <mbgntp.h> + +#if defined( MBG_TGT_POSIX ) + #include <syslog.h> + #include <arpa/inet.h> +#endif + + +#ifdef _MBG_NTP_TEST_UTIL + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + + +#if defined( _USE_PACK ) +// not used here +// #pragma pack( 1 ) // set byte alignment +// #define _USING_BYTE_ALIGNMENT +#endif + +/* Start of header body */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define INDENT " " + +void mbglog( int priority, const char *fmt, ... ); + +_ext const char *newline +#ifdef _DO_INIT + = "\n" +#endif +; + + +typedef struct +{ + double min; + double max; + +} MIN_MAX_DOUBLE; + + + +// query mode statistics + +typedef struct +{ + unsigned long long requests; + unsigned long long replies; + unsigned long long timeouts; + + MIN_MAX_DOUBLE turnaround; + MIN_MAX_DOUBLE latency; + MIN_MAX_DOUBLE ntp_delay; + MIN_MAX_DOUBLE ntp_offs; + +} QUERY_STATS; + + + +static __mbg_inline /*HDR*/ +void update_min_max_double( double curr, MIN_MAX_DOUBLE *p ) +{ + if ( curr > p->max ) + p->max = curr; + + if ( curr < p->min ) + p->min = curr; + +} // update_min_max_double + + + +static __mbg_inline /*HDR*/ +double ntp_tstamp_to_double( const NTP_TSTAMP *t ) +{ + return (double) t->integer + ( ( (double) t->fraction ) / NTP_FRAC_PER_SEC ); + +} // ntp_tstamp_to_double + + + +static __mbg_inline /*HDR*/ +ulong ntp_frac_to_nsec( uint32_t frac ) +{ + unsigned long long tmp = ( (unsigned long long) frac * NSECS_PER_SEC ) / NTP_FRAC_PER_SEC; + + if ( tmp >= NSECS_PER_SEC ) + mbglog( LOG_WARNING, "Range overflow in ntp_frac_to_nsec: 0x%X -> %Lu", + frac, tmp ); + + return (ulong) tmp; + +} // ntp_frac_to_nsec + + + +static __mbg_inline /*HDR*/ +uint32_t nsec_to_ntp_frac( ulong nsec ) +{ + unsigned long long tmp; + + tmp = ( (unsigned long long) nsec * NTP_FRAC_PER_SEC ) / NSECS_PER_SEC; + + if ( tmp >= NTP_FRAC_PER_SEC ) + mbglog( LOG_WARNING, "Range overflow in nsec_to_ntp_frac: %lu -> 0x%LX", + (ulong) nsec, tmp ); + + return (uint32_t) tmp; + +} // nsec_to_ntp_frac + + + +static __mbg_inline /*HDR*/ +void timespec_to_ntp_tstamp( NTP_TSTAMP *t_ntp, const struct timespec *t_ts ) +{ + t_ntp->integer = t_ts->tv_sec + NTP_OFFS; + t_ntp->fraction = nsec_to_ntp_frac( t_ts->tv_nsec ); + +} // timespec_to_ntp_tstamp + + + +static __mbg_inline /*HDR*/ +void ntp_tstamp_to_timespec( struct timespec *t_ts, const NTP_TSTAMP *t_ntp ) +{ + t_ts->tv_sec = ( (uint32_t) t_ntp->integer ) - NTP_OFFS; + t_ts->tv_nsec = ntp_frac_to_nsec( t_ntp->fraction ); + +} // ntp_tstamp_to_timespec + + + +// +// convert the byte order of an NTP time stamp +// from net to host +// +static __mbg_inline /*HDR*/ +void ntoh_ntp_time( NTP_TSTAMP *t ) +{ + t->integer = ntohl( t->integer ); + t->fraction = ntohl( t->fraction ); + +} // ntoh_ntp_time + + +// +// convert the byte order of an NTP packet +// from net to host +// +static __mbg_inline /*HDR*/ +void ntoh_ntp_packet( NTP_PACKET *p ) +{ + ntoh_ntp_time( &p->packet.reference_time ); + ntoh_ntp_time( &p->packet.originate_time ); + ntoh_ntp_time( &p->packet.receive_time ); + ntoh_ntp_time( &p->packet.transmit_time ); + + p->packet.root_delay = ntohl( p->packet.root_delay ); + p->packet.root_dispersion = ntohl( p->packet.root_dispersion ); + +} // ntoh_ntp_packet + + + +static __mbg_inline /*HDR*/ +double delta_tstamps( const NTP_TSTAMP *t, + const NTP_TSTAMP *t_ref ) +{ + return ( (double) t->integer - (double) t_ref->integer ) + + ( (double) t->fraction - (double) t_ref->fraction ) / NTP_FRAC_PER_SEC; + +} // delta_tstamps + + + +// +// compute the difference of two timespec variables +// +static __mbg_inline /*HDR*/ +double delta_timespec_d_s( const struct timespec *ts, + const struct timespec *ts_ref ) +{ + return ( (double) ts->tv_sec - (double) ts_ref->tv_sec ) + + ( (double) ts->tv_nsec - (double) ts_ref->tv_nsec ) / NSECS_PER_SEC; + +} // delta_timespec_d_s + + + +static __mbg_inline /*HDR*/ +long long delta_timespec_ll_ns( const struct timespec *ts, + const struct timespec *ts_ref ) +{ + return ( ts->tv_sec - ts_ref->tv_sec ) * NSECS_PER_SEC + + ( ts->tv_nsec - ts_ref->tv_nsec ); + +} // delta_timespec_ll_ns + + + +static __mbg_inline /*HDR*/ +int check_bounds( int opt_val, int min_val, int max_val, int default_val ) +{ + return ( ( opt_val < min_val ) || ( opt_val > max_val ) ) ? default_val : opt_val; + +} // check_bounds + + + + +/* function prototypes: */ + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void reset_query_stats( QUERY_STATS *p ) ; + void print_stats_double( const char *info, int info_width, double curr, int curr_width, double scale, const MIN_MAX_DOUBLE *p, const char *hint ) ; + void print_timespec_date_time( const struct timespec *p_ts ) ; + /** + * @brief Print date and time of an NTP time stamp + */ + void print_ntp_date_time( const NTP_TSTAMP *t_ntp ) ; + + /** + * @brief Print an NTP timestamp and optionally converted date and time + */ + void print_ntp_time( const char *msg, const NTP_TSTAMP *t, const char *tail ) ; + + /** + * @brief Print contents of an NTP packet + */ + void print_ntp_packet( const char *msg, const NTP_PACKET *p, const NTP_TSTAMP *t_rcv ) ; + + void init_ntp_req_packet( NTP_PACKET *p, int req_mode, int prot_version ) ; + int eval_ntp_packet( NTP_PACKET *p_rcv_packet, NTP_PACKET *p_req_packet, const struct timespec *p_tsr_rcv, const struct timespec *p_tsr_req, const NTP_TSTAMP *p_t_req_ntp, QUERY_STATS *p_stats ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + + + +#if defined( _USING_BYTE_ALIGNMENT ) + #pragma pack() // set default alignment + #undef _USING_BYTE_ALIGNMENT +#endif + +/* End of header body */ + + +#undef _ext +#undef _DO_INIT + +#endif /* _MBG_NTP_TEST_UTIL_H */ + diff --git a/mbglib/common/mbg_tgt.h b/mbglib/common/mbg_tgt.h new file mode 100755 index 0000000..91b4d09 --- /dev/null +++ b/mbglib/common/mbg_tgt.h @@ -0,0 +1,590 @@ + +/************************************************************************** + * + * $Id: mbg_tgt.h 1.30 2014/04/01 12:55:58 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Check the build environment and setup control definitions + * for the Meinberg library modules. + * + * ----------------------------------------------------------------------- + * $Log: mbg_tgt.h $ + * Revision 1.30 2014/04/01 12:55:58 martin + * Define MBG_TGT_WIN32 also for MS resource compiler. + * New target MBG_TGT_POSIX. + * Always include winsock2.h and windows.h for MBG_TGT_WIN32. + * Always include unistd.h for MBG_TGT_POSIX. + * Define empty __attribute__ macro for non-gcc environments. + * Revision 1.29 2013/02/01 14:50:46 martin + * Fixed a typo which caused an error under Borland CBuilder 5. + * Revision 1.28 2012/12/12 10:03:16Z martin + * Fix for Borland C 3.1. + * Revision 1.27 2012/11/29 12:03:14Z martin + * Moved definition of _no_macro_fnc() to words.h. + * Revision 1.26 2012/11/02 09:01:47Z martin + * Merged some stuff depending on the build environment here + * and cleaned up. + * Revision 1.25 2012/04/04 07:17:18 martin + * Treat QNX Neutrino as Unix target. + * Revision 1.24 2011/08/23 10:21:23 martin + * New symbol _NO_MBG_API_ATTR which can be used with functions + * which are going to be exported by a DLL, but actually aren't, yet. + * Revision 1.23 2011/08/19 10:47:00 martin + * Don't include stddef.h. + * Distinguish between different gcc target platforms. + * Initial support for IA64 platform. + * Support wchar_t for BSD. + * Defined _NO_USE_PACK_INTF for Sparc and IA64. + * Fixed typo in comment. + * Revision 1.22 2009/10/01 08:20:50 martin + * Fixed inline code support with different BC versions. + * Revision 1.21 2009/09/01 10:34:23Z martin + * Don't define __mbg_inline for CVI and undefined targets. + * Revision 1.20 2009/08/18 15:14:26 martin + * Defined default MBG_INVALID_PORT_HANDLE for non-Windows targets. + * Revision 1.19 2009/06/09 10:03:58 daniel + * Preliminary support for ARM architecture. + * Revision 1.18 2009/04/01 14:10:55 martin + * Cleanup for CVI. + * Revision 1.17 2009/03/19 15:21:07Z martin + * Conditionally define DWORD_PTR type for old MS C compilers. + * Revision 1.16 2008/12/08 16:42:30 martin + * Defined _GNU_SOURCE for Linux. + * Revision 1.15 2008/11/19 15:31:49 martin + * Added symbol MBG_ARCH_I386. + * Revision 1.14 2008/09/03 15:06:04 martin + * Support DOS protected mode target. + * Support SUN SPARC architecture. + * Specified handle types for common host environments. + * Added macro MBG_USE_MM_IO_FOR_PCI. + * Added macro _nop_macro_fnc(). + * Revision 1.13 2008/01/30 15:52:22 martin + * Modified checking for availability of wchar_t. + * Revision 1.13 2008/01/29 15:18:07Z martin + * Recognize DOS target under Watcom compilers. + * Flag Watcom C always supports wchar_t. + * Revision 1.12 2008/01/17 09:38:50Z daniel + * Added macros to determine whether C language extensions + * (e.g. C94, C99) are supported by the target environment. + * Added macro to check whether wchar_t and friends are + * supported, and some compatibility stuff. + * Revision 1.11 2007/10/31 16:58:03 martin + * Fixed __mbg_inline for Borland C (DOS). + * Revision 1.10 2007/09/25 08:10:27Z martin + * Support CVI target environment. + * Added MBG_PORT_HANDLE type for serial ports. + * Added macros for unified inline code syntax. + * Revision 1.9 2006/12/08 12:45:54Z martin + * Under Windows include ntddk.h rather than windows.h + * if building kernel driver . + * Revision 1.8 2006/10/25 12:20:45Z martin + * Initial support for FreeBSD, NetBSD, and OpenBSD. + * Added definitions for generic handle types. + * Revision 1.7 2006/08/23 13:43:55 martin + * Added definition for MBG_TGT_UNIX. + * Minor syntax fixes. + * Revision 1.6 2006/01/25 14:37:06 martin + * Added definitions for 64 bit Windows environments. + * Revision 1.5 2003/12/17 16:11:41Z martin + * Split API modifiers into _MBG_API and _MBG_API_ATTR. + * Revision 1.4 2003/06/19 08:20:22Z martin + * Added WINAPI attribute for DLL exported functions. + * Revision 1.3 2003/04/09 13:37:20Z martin + * Added definition for _MBG_API. + * Revision 1.2 2003/02/24 16:08:45Z martin + * Don't setup for Win32 PNP if explicitely configured non-PNP. + * Revision 1.1 2002/02/19 13:46:20Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _MBG_TGT_H +#define _MBG_TGT_H + + +/* Other headers to be included */ + +#ifdef _MBG_TGT + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _CVI_ ) + + #define MBG_TGT_CVI + + #if defined( _NI_mswin_ ) + #define MBG_TGT_WIN32 + #else + #error Unsupported CVI target platform. + #endif + +#elif defined( _WIN32_WINNT ) + + // MS platform SDK + // WinNT 4.0 and above + #define MBG_TGT_WIN32 + + #if ( _WIN32_WINNT >= 0x0500 ) + // Win2k and above + #if !defined( MBG_TGT_WIN32_NON_PNP ) + // only if not explicitely disabled + #define MBG_TGT_WIN32_PNP + #endif + #endif + +#elif defined( WINVER ) + + // MS platform SDK + // Win95, WinNT 4.0 and above + #define MBG_TGT_WIN32 + + #if ( WINVER >= 0x0500 ) + // Win98, Win2k and above + // #define ... + #endif + +#elif defined( __WIN32__ ) + + // Borland C++ Builder + #define MBG_TGT_WIN32 + +#elif defined( _WIN32 ) + + // MS Visual C++ + #define MBG_TGT_WIN32 + +#elif defined( RC_INVOKED ) + + //MS resource compiler + #define MBG_TGT_WIN32 + +#elif defined( __WINDOWS_386__ ) + + // Watcom C/C++ for target Win32 + #define MBG_TGT_WIN32 + +#elif defined( __NETWARE_386__ ) + + // Watcom C/C++ for target NetWare + #define MBG_TGT_NETWARE + +#elif defined( __OS2__ ) + + // Watcom C/C++ for target OS/2 + #define MBG_TGT_OS2 + +#elif defined( __linux ) + + // GCC for target Linux + #define MBG_TGT_LINUX + #define _GNU_SOURCE 1 + + #if defined( __KERNEL__ ) + #define MBG_TGT_KERNEL + #endif + +#elif defined( __FreeBSD__ ) + + // GCC for target FreeBSD + #define MBG_TGT_FREEBSD + +#elif defined( __NetBSD__ ) + + // GCC for target NetBSD + #define MBG_TGT_NETBSD + +#elif defined( __OpenBSD__ ) + + // GCC for target OpenBSD + #define MBG_TGT_OPENBSD + +#elif defined( __QNX__ ) + + // any compiler for target QNX + #define MBG_TGT_QNX + + #if defined( __QNXNTO__ ) + // target QNX Neutrino + #define MBG_TGT_QNX_NTO + #endif + +#elif defined( __MSDOS__ ) || defined( __DOS__ ) + + // any compiler for target DOS + #define MBG_TGT_DOS + + #if defined( __WATCOMC__ ) && defined( __386__ ) + + #define MBG_TGT_DOS_PM // protected mode DOS + + #endif + +#endif + + + +#if defined( MBG_TGT_FREEBSD ) \ + || defined( MBG_TGT_NETBSD ) \ + || defined( MBG_TGT_OPENBSD ) + #define MBG_TGT_BSD + + #if defined( _KERNEL ) + #define MBG_TGT_KERNEL + #endif + +#endif + +#if defined( MBG_TGT_LINUX ) \ + || defined( MBG_TGT_BSD ) + #define MBG_TGT_POSIX + #define MBG_TGT_UNIX +#endif + + + +// Some definitions depending on the build environment ... + +#if defined( __GNUC__ ) + + #if defined( __i386__ ) + + #define MBG_ARCH_I386 + #define MBG_ARCH_X86 + + #elif defined( __x86_64__ ) + + #define MBG_ARCH_X86_64 + #define MBG_ARCH_X86 + + #elif defined( __ia64__ ) + + #define MBG_ARCH_IA64 + + #define _NO_USE_PACK_INTF + + #elif defined( __sparc__ ) + + #define MBG_ARCH_SPARC + #define MBG_USE_MM_IO_FOR_PCI 1 + + #define _NO_USE_PACK_INTF + + #elif defined( __arm__ ) + + #define MBG_ARCH_ARM + + #endif + + #if defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + #include <linux/types.h> + #else + #include <sys/types.h> + #include <stdint.h> + #include <stdbool.h> + #endif + + #elif defined( MBG_TGT_BSD ) + + #include <sys/types.h> + + #elif defined( MBG_TGT_QNX_NTO ) // QNX 6.x (Neutrino) + + #include <stdint.h> + #include <stdbool.h> + + #else + + #include <stdint.h> + #include <stdbool.h> + + #endif + + #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1 + + #define MBG_TGT_HAS_WCHAR_T 1 + + #define __mbg_inline __inline__ + +#elif defined( _MSC_VER ) + + // Known predifined MS compiler version codes: + // 1700: MSVC++ 11.0 (Visual Studio 2012) + // 1600: MSVC++ 10.0 (Visual Studio 2010) + // 1500: MSVC++ 9.0 (Visual Studio 2008) + // 1400: MSVC++ 8.0 (Visual Studio 2005) + // 1310: MSVC++ 7.1 (Visual Studio 2003) + // 1300: MSVC++ 7.0 + // 1200: MSVC++ 6.0 + // 1100: MSVC++ 5.0 + + #if ( _MSC_VER >= 1600 ) + #include <stdint.h> + #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1 + #else + #define MBG_TGT_HAS_INT_8_16_32 1 + #endif + + // no bool support anyway + #define MBG_TGT_MISSING_BOOL_TYPE 1 + + #define MBG_TGT_HAS_WCHAR_T 1 + + #define __mbg_inline __forceinline + +#elif defined( _CVI_ ) + + // 1000 for CVI v10.0 (CVI 2010) + // 911 for CVI v9.1.1 (CVI 2009 SP1) + // 910 for CVI v9.1 (CVI 2009) + // 310 for CVI v3.1 + // 301 for CVI v3.0.1 + // 1 for CVI v3.0 + + #if ( _CVI_ >= 910 ) + // LabWindows/CVI 2009 is the first version providing stdint.h. + #include <stdint.h> + #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1 + #else + #define USE_LONG_FOR_INT32 1 + #endif + + // As of LabWindows/CVI 2010, stdbool.h is still missing. + #define MBG_TGT_MISSING_BOOL_TYPE 1 + + #define MBG_TGT_HAS_WCHAR_T 0 + + // Inline code is not supported, though the inline keyword + // is silently accepted since CVI v9.0 + +#elif defined( __BORLANDC__ ) + + // 0x0570 Borland Developer Studio 2006 + // 0x0550 Borland C/C++ 5.5 (C++ Builder 5.0) + // 0x0410 Borland C/C++ 3.1 + // 0x0400 Borland C/C++ 3.0 + // 0x0200 Borland C/C++ 2.0 + + #if ( __BORLANDC__ >= 0x570 ) + // at least Borland Developer Studio 2006 supports C99 + #include <stdint.h> + #include <stdbool.h> + #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1 + #elif ( __BORLANDC__ >= 0x0550 ) + #define MBG_TGT_HAS_INT_8_16_32 1 + #define MBG_TGT_MISSING_BOOL_TYPE 1 + #else // e.g. BC 3.1 or earlier + #if ( __BORLANDC__ <= 0x410 ) + #define MBG_TGT_MISSING_64_BIT_TYPES 1 + #define MBG_TGT_MISSING_BOOL_TYPE 1 + #define USE_LONG_FOR_INT32 1 + #endif + #endif + + #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 ) + + #if defined( __cplusplus ) + #define __mbg_inline inline // standard C++ syntax + #elif ( __BORLANDC__ > 0x410 ) // BC3.1 defines 0x410 ! + #define __mbg_inline __inline // newer BC versions support this for C + #else + #define __mbg_inline // up to BC3.1 not supported for C + #endif + +#elif defined( __WATCOMC__ ) + + // 1050 v10.5 + // 1100 v11.0 + // 1200 Open Watcom C++ v1.0 + // 1230 Open Watcom C++ v1.3 + // 1270 Open Watcom C++ v1.7 + + #if defined( MBG_TGT_QNX ) // QNX 4.x + + #include <sys/types.h> + + #define MBG_TGT_MISSING_64_BIT_TYPES 1 + + #elif ( __WATCOMC__ > 1230 ) // Open Watcom C 1.3 and above + + #include <stdint.h> + + #elif !defined( __WATCOM_INT64__ ) // Watcom C 11 + + #define MBG_TGT_MISSING_64_BIT_TYPES 1 + + #endif + + #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 ) + + #define __mbg_inline _inline + +#endif + + +#if !defined( __GNUC__ ) && !defined( __attribute__ ) + #define __attribute__( _x ) +#endif + + +#if defined( MBG_TGT_WIN32 ) + + #if defined( _AMD64_ ) + // This is used for AMD64 architecture and for + // Intel XEON CPUs with 64 bit extension. + #define MBG_TGT_WIN32_PNP_X64 + #define WIN32_FLAVOR "x64" + #elif defined( _IA64_ ) + #define MBG_TGT_WIN32_PNP_IA64 + #define WIN32_FLAVOR "ia64" + #endif + + #if defined( _KDD_ ) + #define MBG_TGT_KERNEL + #include <ntddk.h> + #else + // This must not be used for kernel drivers. + #define WIN32_LEAN_AND_MEAN 1 + #define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ + #include <winsock2.h> + #include <windows.h> + + typedef HANDLE MBG_HANDLE; + + #define MBG_INVALID_HANDLE INVALID_HANDLE_VALUE + + #if defined( MBG_TGT_CVI ) + // CVI uses an own set of functions to support serial ports + typedef int MBG_PORT_HANDLE; + #define MBG_INVALID_PORT_HANDLE -1 + #else + typedef HANDLE MBG_PORT_HANDLE; + #endif + + // The DWORD_PTR type is not defined in the headers shipping + // with VC6. However, if the SDK is installed then the SDK's + // headers may declare this type. This is at least the case + // in the Oct 2001 SDK which also defines the symbol _W64. + #if !defined( _W64 ) + typedef DWORD DWORD_PTR; + #endif + + #endif + + #define _MBG_API WINAPI + + #if defined( MBG_LIB_EXPORT ) + #define _MBG_API_ATTR __declspec( dllexport ) + #else + #define _MBG_API_ATTR __declspec( dllimport ) + #endif + +#elif defined( MBG_TGT_POSIX ) + + #if !defined( MBG_TGT_KERNEL ) + #include <unistd.h> + #endif + + typedef int MBG_HANDLE; + typedef int MBG_PORT_HANDLE; + + #define MBG_INVALID_HANDLE -1 + +#else + + typedef int MBG_HANDLE; + typedef int MBG_PORT_HANDLE; + + #define MBG_INVALID_HANDLE -1 + +#endif + + +#if !defined( _MBG_API ) + #define _MBG_API +#endif + +#if !defined( _MBG_API_ATTR ) + #define _MBG_API_ATTR +#endif + +#if !defined( _NO_MBG_API_ATTR ) + #define _NO_MBG_API_ATTR +#endif + +#if !defined( MBG_INVALID_PORT_HANDLE ) + #define MBG_INVALID_PORT_HANDLE MBG_INVALID_HANDLE +#endif + +#if !defined( MBG_USE_MM_IO_FOR_PCI ) + #define MBG_USE_MM_IO_FOR_PCI 0 +#endif + + +// The macros below are defined in order to be able to check if +// certain C language extensions are available on the target system: +#if defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199409L ) + #define MBG_TGT_C94 1 +#else + #define MBG_TGT_C94 0 +#endif + + +#if defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) + #define MBG_TGT_C99 1 +#else + #define MBG_TGT_C99 0 +#endif + +// Check if wchar_t is supported +#if !defined( MBG_TGT_HAS_WCHAR_T ) + #define MBG_TGT_HAS_WCHAR_T ( MBG_TGT_C94 || defined( WCHAR_MAX ) ) +#endif + +#if !MBG_TGT_HAS_WCHAR_T + // Even if wchar_t is not natively supported by the target platform + // there may already be a compatibility define (e.g. BC3.1) + // However, some functions may be missing (e.g. snwprintf()). + #if !defined( _WCHAR_T ) /* BC3.1 */ \ + && !defined( _WCHAR_T_DEFINED_ ) /* WC11 */ + #define _WCHAR_T + #define wchar_t char + #endif +#endif + + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _MBG_TGT_H */ diff --git a/mbglib/common/mbgntp.h b/mbglib/common/mbgntp.h new file mode 100755 index 0000000..a464b59 --- /dev/null +++ b/mbglib/common/mbgntp.h @@ -0,0 +1,208 @@ + +/************************************************************************** + * + * $Id: mbgntp.h 1.4 2014/04/01 12:30:30 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for mbgntp.h. + * + * ----------------------------------------------------------------------- + * $Log: mbgntp.h $ + * Revision 1.4 2014/04/01 12:30:30 martin + * Include mbg_tgt.h. + * MD5 auth support disabled by default. + * Moved some definitions here. + * Revision 1.3 2005/11/15 13:51:15 martin + * Changed NTP_TSTAMP::fraction to unsigned. + * Conditional preliminary union for NTP_TSTAMP using 64 bit type. + * Revision 1.2 2005/05/19 14:42:07 martin + * Use C99 fixed with data types. + * Support MD5 symmetric key authentication. + * Revision 1.1 2000/05/23 12:04:21 martin + * Initial revision + * + **************************************************************************/ + +#ifndef _MBGNTP_H +#define _MBGNTP_H + + +/* Other headers to be included */ + +#include <mbg_tgt.h> +#include <words.h> + +#ifdef _MBGNTP + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#ifndef MBG_MD5_AUTH + #define MBG_MD5_AUTH 0 +#endif + + +#define NTP_PORT 123 + +#define NTP_OFFS 2208988800UL + + +#define NTP_FRAC_PER_SEC (uint64_t) 4294967296.0 +#define NSECS_PER_SEC 1000000000L + +#define MIN_REQ_NTP_VERSION 3 +#define MAX_REQ_NTP_VERSION 4 +#define DEFAULT_REQ_NTP_VERSION MAX_REQ_NTP_VERSION + +// From NTP's ntp.h: +#define MODE_UNSPEC 0 /* unspecified (old version) */ +#define MODE_ACTIVE 1 /* symmetric active mode */ +#define MODE_PASSIVE 2 /* symmetric passive mode */ +#define MODE_CLIENT 3 /* client mode */ +#define MODE_SERVER 4 /* server mode */ +#define MODE_BROADCAST 5 /* broadcast mode */ + +#define DEFAULT_REQ_NTP_MODE MODE_CLIENT + + + +typedef struct +{ + int32_t integer; + uint32_t fraction; +} NTP_TSTAMP; + + + +typedef int32_t NTP_S_FP; // signed floating point in integer representation +typedef uint32_t NTP_U_FP; // unsigned floating point in integer representation + + +/* + * s_fp/double and u_fp/double conversions + */ +#define FRIC 65536 /* 2^16 as a double */ + +#if 1 + +static __mbg_inline /*HDR*/ +NTP_S_FP d_to_s_fp( double d ) +{ + return (NTP_S_FP) ( d * FRIC ); +} + +static __mbg_inline /*HDR*/ +NTP_S_FP d_to_u_fp( double d ) +{ + return (NTP_U_FP) ( d * FRIC ); +} + +static __mbg_inline /*HDR*/ +double s_fp_to_d( NTP_S_FP s_fp ) +{ + return (double) s_fp / FRIC; +} + +static __mbg_inline /*HDR*/ +double u_fp_to_d( NTP_U_FP u_fp ) +{ + return (double) u_fp / FRIC; +} + + +#define _d_to_s_fp( _r ) d_to_s_fp( _r ) +#define _d_to_u_fp( _r ) d_to_u_fp( _r ) +#define _s_fp_to_d( _r ) s_fp_to_d( _r ) +#define _u_fp_to_d( _r ) u_fp_to_d( _r ) + +#else + +#define _d_to_s_fp( _r ) ( (NTP_S_FP) ( (_r) * FRIC ) ) +#define _d_to_u_fp( _r ) ( (NTP_U_FP) ( (_r) * FRIC ) ) +#define _s_fp_to_d( _r ) _u_fp_to_d( _r ) +#define _u_fp_to_d( _r ) ( (double) ( _r ) / FRIC ) + +#endif + +typedef struct +{ + unsigned int mode : 3; + unsigned int version : 3; + unsigned int leap_ind : 2; + unsigned int stratum : 8; + unsigned int poll : 8; + unsigned int precision : 8; +} NTP_FLAGS; + + + +typedef struct +{ + NTP_FLAGS flags; + NTP_U_FP root_delay; + NTP_U_FP root_dispersion; + uint32_t reference_id; + NTP_TSTAMP reference_time; + NTP_TSTAMP originate_time; + NTP_TSTAMP receive_time; + NTP_TSTAMP transmit_time; +} NTP_BASE_PACKET; + + +#if MBG_MD5_AUTH + +#define N_NTP_MAC_BYTES 16 + +typedef struct +{ + uint32_t key_id; + uint8_t mac[N_NTP_MAC_BYTES]; // message authenticator +} NTP_AUTH_INFO; + +#endif + + +typedef struct +{ + NTP_BASE_PACKET packet; + #if MBG_MD5_AUTH + NTP_AUTH_INFO auth_info; + #endif +} NTP_PACKET; + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _MBGNTP_H */ + diff --git a/mbglib/common/words.h b/mbglib/common/words.h new file mode 100755 index 0000000..5047f16 --- /dev/null +++ b/mbglib/common/words.h @@ -0,0 +1,363 @@ + +/************************************************************************** + * + * $Id: words.h 1.32 2014/01/07 15:43:52 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions of commonly used data types. + * + * ----------------------------------------------------------------------- + * $Log: words.h $ + * Revision 1.32 2014/01/07 15:43:52 martin + * Define __mbg_inline for ARM firmware targets. + * Revision 1.31 2012/11/29 11:54:39Z martin + * Removed #if sizeof() definitions which may cause build errors + * with some older compilers. + * Include stdbool.h for __ARMCC_VERSION targets. + * Moved _nop_macro_fnc() definition here. + * Revision 1.30 2012/11/02 09:12:29Z martin + * Moved most feature detection code to mbg_tgt.h. + * Tried to define missing features most flexibly and portably. + * Revision 1.29 2012/07/11 16:45:45Z martin + * New macros to access individual bytes of long constants. + * Revision 1.28 2012/04/05 14:36:18Z martin + * Support CVI 2010 compiler which provides C99 types. + * Revision 1.27 2011/07/18 10:21:38Z martin + * Added definition for MBG_CODE_NAME_TABLE_ENTRY which can + * be used to define tables assigning strings to numeric codes. + * Revision 1.26 2011/04/06 10:23:03 martin + * Added FBYTE_OF() and FWORD_OF() macros. + * Modifications required for *BSD. + * Revision 1.25 2010/11/17 10:23:09 martin + * Define _BIT_REDEFINED if bit type is redefined. + * Revision 1.24 2010/11/17 08:44:56Z martin + * If supported, use type "bool" to implement "bit". + * Revision 1.23 2010/05/27 08:54:30Z martin + * Support fixed size data types with Keil RealView compiler for ARM. + * Keil RealView ARM targets are always considered as firmware. + * Revision 1.22 2009/10/21 07:53:55 martin + * Undid changes introduced in 1.21 since they were not consistent + * across glibc and/or Linux kernel header versions. + * Revision 1.21 2009/10/01 14:00:17 martin + * Conditionally define ulong and friends also for Linux/glibc. + * Revision 1.20 2009/07/02 15:38:12 martin + * Added new macro _wswap32(). + * Revision 1.19 2009/04/14 14:45:45Z martin + * Added BYTE_OF_P() and WORD_OF_P() macros. + * Revision 1.18 2009/03/27 14:05:18 martin + * Cleanup for CVI. + * Revision 1.17 2009/03/13 09:06:03Z martin + * Declared bit type for non-firmware environments. + * Revision 1.16 2008/12/05 12:05:41Z martin + * Define dummy int64_t/uint64_t types for targets + * which don't support 64 bit data types. + * Revision 1.15 2008/07/14 14:44:00Z martin + * Use fixed size C99 types which come with GCC and newer Borland compilers. + * Revision 1.14 2008/01/30 10:27:50Z martin + * Moved some macro definitions here. + * Revision 1.13 2007/03/08 15:00:30Z martin + * Fixed incompatibility of macro _IS_MBG_FIRMWARE. + * Added a workaround for _IS_MBG_FIRMWARE under CVI. + * Support for BSD. + * Revision 1.12 2006/12/15 10:45:46 martin + * Added macro _IS_MBG_FIRMWARE. + * Cleanup for Linux, QNX, and Watcom C. + * Include mbg_tgt.h for non-firmware targets. + * Revision 1.11 2004/11/10 10:45:34 martin + * Added C99 fixed-type handling for QNX. + * Revision 1.10 2004/11/09 13:12:56 martin + * Redefined C99 integer types with fixed sizes as standard types + * if required, depending on the environment. + * Revision 1.9 2003/02/07 11:36:54 MARTIN + * New macros _hilo_16() and _hilo_32() for endian conversion. + * Revision 1.8 2002/05/28 10:09:54 MARTIN + * Added new macros _var_bswap16() and _var_bswap32(). + * Revision 1.7 2001/03/14 11:30:48 MARTIN + * Removed definitions for UINT8, UINT16, UINT32. + * Redefined preprocessor control for Win32. + * Revision 1.6 2001/02/28 15:43:20 MARTIN + * Modified preprocessor syntax. + * Revision 1.5 2001/02/05 10:20:53 MARTIN + * Include different Linux types for user space and kernel space programs. + * Source code cleanup. + * Revision 1.4 2000/09/15 08:34:11 MARTIN + * Exclude some definitions if compiling under Win NT. + * Revision 1.3 2000/08/22 15:04:28 MARTIN + * Added new file header. + * Added macros to revert endianess of 16 and 32 bit values. + * + **************************************************************************/ + +#ifndef _WORDS_H +#define _WORDS_H + + +/* Other headers to be included */ + + +#if !defined( _IS_MBG_FIRMWARE ) + + #if defined( _C166 ) || \ + defined( _CC51 ) || \ + defined( __ARM ) || \ + defined( __ARMCC_VERSION ) + #define _IS_MBG_FIRMWARE 1 + #else + #define _IS_MBG_FIRMWARE 0 + #endif + +#endif + + +#if !_IS_MBG_FIRMWARE + #include <mbg_tgt.h> +#else + #if defined( __ARMCC_VERSION ) // Keil RealView Compiler for ARM + #define __mbg_inline __inline + #include <stdint.h> + #include <stdbool.h> + #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1 + #else + #define MBG_TGT_MISSING_64_BIT_TYPES 1 + #endif +#endif + + + +#ifdef _WORDS + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _C166 ) \ + || defined( _CC51 ) + #define _BIT_DEFINED 1 // these compilers natively support the "bit" type + #define USE_LONG_FOR_INT32 1 +#endif + + + +#if !defined( MBG_TGT_HAS_EXACT_SIZE_TYPES ) + + #if defined( MBG_TGT_HAS_INT_8_16_32 ) + + // Define C99 exact size types using non-standard exact-size types + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + + #else + + // Assume a 16 or 32 bit compiler which doesn't + // support exact-size types. + + typedef char int8_t; + typedef unsigned char uint8_t; + + typedef short int16_t; + typedef unsigned short uint16_t; + + // Using #if sizeof() to determine the size of a type may not + // be supported by all preprocessors, and may even result in + // build errors if used in a conditional preprocessor section, + // so we can't use this here without compatibility problems. + + #if defined( USE_LONG_FOR_INT32 ) + typedef long int32_t; + typedef unsigned long uint32_t; + #elif defined( USE_INT_FOR_INT32 ) + typedef int int32_t; + typedef unsigned int uint32_t; + #else + #error Need to define int32_t and uint32_t + #endif + + #endif + + #if defined( MBG_TGT_MISSING_64_BIT_TYPES ) + + // The build environment does not support 64 bit types. However, + // 64 bit types need to be defined to avoid build errors + // if these types are formally used in function prototypes. + // We explicitely use abnormal data types to hopefully + // cause compiler errors in case these types are + // unexpectedly used to generate real code for a target + // platform which does not support 64 bit types. + typedef void *int64_t; + typedef void *uint64_t; + + #else + + // Define C99 types using non-standard exact-size types + // which are usually supported by build envonronments + // supporting 64 bit types but no C99 types. + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + + #endif + +#endif + + + +#if defined( MBG_TGT_MISSING_64_BIT_TYPES ) + + #define MBG_TGT_HAS_64BIT_TYPES 0 + +#else + + #define MBG_TGT_HAS_64BIT_TYPES 1 + +#endif + + + +// Some commonly used types + +typedef unsigned char uchar; + +#if !defined( MBG_TGT_LINUX ) \ + && !( defined ( MBG_TGT_NETBSD ) \ + && defined ( MBG_TGT_KERNEL ) ) + typedef unsigned short ushort; + typedef unsigned int uint; + typedef unsigned long ulong; +#endif + +typedef double udouble; + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long longword; +typedef unsigned long dword; + + +#if !defined( _BIT_DEFINED ) + + // We need to implement a "bit" type. Preferably we use "bool" + // to do this, but this is only supported by C++ compilers, and + // by C compilers supporting the C99 standard. + + #if !defined( MBG_TGT_MISSING_BOOL_TYPE ) && \ + ( defined( __cplusplus ) || defined( __bool_true_false_are_defined ) ) + + typedef bool bit; + + #else // C99 types not supported + + // Falling back to use "int" for "bit". This prevents error + // messages if "bit" is used in function prototypes, but may + // yield unexpected results for code like: + // return (bit) ( val & 0x10 ); + typedef int bit; + + #endif + + #define _BIT_REDEFINED 1 + +#endif + + +#define BYTE_0( _x ) ( ( (ulong) (_x) ) & 0xFF ) +#define BYTE_1( _x ) ( ( ( (ulong) (_x) ) >> 8 ) & 0xFF ) +#define BYTE_2( _x ) ( ( ( (ulong) (_x) ) >> 16 ) & 0xFF ) +#define BYTE_3( _x ) ( ( ( (ulong) (_x) ) >> 24 ) & 0xFF ) + + +#define HI_BYTE( _x ) ( (_x) >> 8 ) +#define LO_BYTE( _x ) ( (_x) & 0xFF ) + +#define HI_WORD( _x ) ( (_x) >> 16 ) +#define LO_WORD( _x ) ( (_x) & 0xFFFF ) + +// the macros below assume little endianess +// these macros expect the name of a variable +#define BYTE_OF( _v, _n ) *( ( (uint8_t *) &(_v) ) + (_n) ) +#define WORD_OF( _v, _n ) *( ( (uint16_t *) &(_v) ) + (_n) ) + +#define FBYTE_OF( _v, _n ) *( ( (uint8_t far *) &(_v) ) + (_n) ) +#define FWORD_OF( _v, _n ) *( ( (uint16_t far *) &(_v) ) + (_n) ) + +// same as above, but taking pointers +#define BYTE_OF_P( _p, _n ) *( ( (uint8_t *) (_p) ) + (_n) ) +#define WORD_OF_P( _p, _n ) *( ( (uint16_t *) (_p) ) + (_n) ) + + +// a macro to swap the byte order of a 16 bit value +#define _bswap16( _x ) \ +( \ + ( ( ( (uint16_t) (_x) ) & 0x00FF ) << 8 ) | \ + ( ( ( (uint16_t) (_x) ) & 0xFF00 ) >> 8 ) \ +) + +// a macro to swap the byte order of a 32 bit value +#define _bswap32( _x ) \ +( \ + ( ( ( (uint32_t) (_x) ) & 0x000000FFUL ) << 24 ) | \ + ( ( ( (uint32_t) (_x) ) & 0x0000FF00UL ) << 8 ) | \ + ( ( ( (uint32_t) (_x) ) & 0x00FF0000UL ) >> 8 ) | \ + ( ( ( (uint32_t) (_x) ) & 0xFF000000UL ) >> 24 ) \ +) + +// a macro to swap the word order of a 32 bit value +#define _wswap32( _x ) \ +( \ + ( ( ( (uint32_t) (_x) ) & 0x0000FFFFUL ) << 16 ) | \ + ( ( ( (uint32_t) (_x) ) >> 16 ) & 0x0000FFFFUL ) \ +) + +#define _var_bswap16( _v ) (_v) = _bswap16( _v ) +#define _var_bswap32( _v ) (_v) = _bswap32( _v ) + + +// The C51 compiler is big-endian, that means the most +// significant byte of a 16 or 32 bit value is stored in +// the lowest memory location. Most other systems are +// little-endian, so we must use macros to adjust the +// byte order if the C51 is used. + +#if defined( _CC51 ) + #define _hilo_16( _x ) _bswap16( _x ) + #define _hilo_32( _x ) _bswap32( _x ) +#else + #define _hilo_16( _x ) (_x) + #define _hilo_32( _x ) (_x) +#endif + + +// A macro function which can safely be used without +// side effects as a macro doing nothing. +// This is useful to define debug macros away in +// release builds, etc. +#if !defined( _nop_macro_fnc ) + #define _nop_macro_fnc() do {} while (0) +#endif + + +/** + * @brief A table entry which can be used to map codes to names. + */ +typedef struct +{ + ulong code; + const char *name; +} MBG_CODE_NAME_TABLE_ENTRY; + + + +/* End of header body */ + +#undef _ext + +#endif /* _WORDS_H */ diff --git a/ntptest.c b/ntptest.c new file mode 100755 index 0000000..1066b08 --- /dev/null +++ b/ntptest.c @@ -0,0 +1,310 @@ + +/************************************************************************** + * + * $Id: ntptest.c 1.1 2014/04/01 13:02:21 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Main module for ntptest program. Sends one or several client + * request packets to an NTP server, receives the replies and + * prints NTP statistics. + * + * ----------------------------------------------------------------------- + * $Log: ntptest.c $ + * Revision 1.1 2014/04/01 13:02:21 martin + * Initial revision. + * + **************************************************************************/ + +#include <mbg_ntp_test_util.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> +#include <errno.h> +#include <netdb.h> + + +static const char program_name[] = "ntptest"; + +static const char program_version[] = "v1.0"; +static const char program_copyright[] = "(c) Meinberg 2014"; +static const char program_contact[] = "contact: <martin.burnicki@meinberg.de>"; + + +#define RCV_TIMEOUT 400 // [msec] + + + +// parameters which can to some extent be modified via command +// line options to control the program's behaviour + +static int run_continuously; // -c +static int sleep_intv = 1; // -s, [sec], sleep interval between requests, default 1 +static int prot_version; // -V, protocol version to be used +static unsigned long rcv_timeout; // -T, [msec] receive timeout after request sent + +static const char *tgt_host; // target hostname or IP address +static struct sockaddr_in tgt_addr; // target address + +static int must_print_usage; +static NTP_PACKET default_ntp_req_packet; // template of request packet + +static QUERY_STATS glb_query_stats; + + + +/*HDR*/ +void mbglog( int priority, const char *fmt, ... ) +{ + char s[300]; + + va_list ap; + + va_start( ap, fmt); + vsnprintf( s, sizeof( s ), fmt, ap ); + va_end(ap); + + fprintf( stderr, "%s\n", s ); + +} // mbglog + + + +// +// send query packet(s) to a host, wait for a response +// and evaluate the response packet +// +static /*HDR*/ +void do_ntp_queries( void ) +{ + fd_set read_set; + struct timeval tv_timeout; + struct timespec tsr_req; // time stamp when request was sent + struct timespec tsr_rcv; // time stamp when response arrived + NTP_TSTAMP t_req_ntp; // tv_req converted to NTP format + NTP_PACKET ntp_req_packet; // set up from template + NTP_PACKET rcv_buffer; + void *req_packet; + int req_packet_size; + ssize_t rcv_packet_size; + int sockfd; + int rc; + struct sockaddr_in si_src; + socklen_t slen_src; + + + sockfd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); // create socket on which to send + + if ( sockfd < 0 ) + { + mbglog( LOG_ERR, "Failed to open UDP socket in %s: %s", __func__, strerror( errno ) ); + exit( 1 ); + } + + + ntp_req_packet = default_ntp_req_packet; + + for (;;) + { + // get time stamp when request packet was sent + clock_gettime( CLOCK_REALTIME, &tsr_req ); + + timespec_to_ntp_tstamp( &t_req_ntp, &tsr_req ); + + ntp_req_packet.packet.transmit_time = t_req_ntp; + ntoh_ntp_time( &ntp_req_packet.packet.transmit_time ); + + req_packet = &ntp_req_packet; + req_packet_size = sizeof( ntp_req_packet ); + + // send request packet + if ( sendto( sockfd, req_packet, req_packet_size, 0, + (__const__ struct sockaddr *) &tgt_addr, + sizeof( tgt_addr ) ) < 0 ) + { + mbglog( LOG_ERR, "Failed to send UDP packet in %s: %s", __func__, strerror( errno ) ); + exit( 1 ); + } + + glb_query_stats.requests++; + + + FD_ZERO( &read_set ); + FD_SET( sockfd, &read_set ); + + tv_timeout.tv_sec = 0; + tv_timeout.tv_usec = rcv_timeout * 1000; + + rc = select( sockfd + 1, &read_set, NULL, NULL, &tv_timeout ); + + if ( rc < 0 ) // select() failed + { + mbglog( LOG_ERR, "Select failed in %s: %s", __func__, strerror( errno ) ); + break; + } + + if ( rc == 0 ) // select() timed out + { + mbglog( LOG_ERR, "Timeout waiting for reply packet, exiting." ); + exit( 1 ); + } + + // read response packet + slen_src = sizeof( si_src ) ; + rcv_packet_size = recvfrom( sockfd, &rcv_buffer, sizeof( rcv_buffer ), 0, + (struct sockaddr *) &si_src, &slen_src ); + + if ( rcv_packet_size < 0 ) + { + mbglog( LOG_ERR, "Failed to receive from UDP socket in %s: %s", __func__, strerror( errno ) ); + continue; + } + + // get time stamp when response was received + clock_gettime( CLOCK_REALTIME, &tsr_rcv ); + + rc = eval_ntp_packet( &rcv_buffer, &ntp_req_packet, &tsr_rcv, + &tsr_req, &t_req_ntp, &glb_query_stats ); + + if ( !run_continuously ) + break; + + sleep( sleep_intv ); + } + + close( sockfd ); + +} // do_ntp_queries + + + +static /*HDR*/ +void usage( void ) +{ + printf( "\n" ); + printf( "Usage: %s [[OPTION]...] <host>\n", program_name ); + printf( "\n" ); + printf( "Send NTP client requests to an NTP server with IP address or\n" + "hostname <host>, show the sent and received packets,\n" + "and evaluate the results.\n" ); + printf( "\n" ); + printf( "[OPTION] can be one of the following:\n" ); + printf( " -c run continuously\n" ); + printf( " -s n n seconds delay between queries, default: %i s\n", sleep_intv ); + printf( " -V n NTP protocol version, %i..%i, default: %i\n", + MIN_REQ_NTP_VERSION, MAX_REQ_NTP_VERSION, DEFAULT_REQ_NTP_VERSION ); + printf( " -T n packet receive timeout [ms], default: %u\n", RCV_TIMEOUT ); + printf( " -?, -h print this usage information\n" + "\n" ); + +} // usage + + + +static /*HDR*/ +void check_options( int argc, char *argv[] ) +{ + char c; + + while ( ( c = getopt( argc, argv, "cs:V:T:h?" ) ) != -1 ) + { + switch ( c ) + { + case 'c': + run_continuously = 1; + break; + + + case 's': + sleep_intv = strtol( optarg, NULL, 10 ); + + if ( sleep_intv < 1 ) + sleep_intv = 1; + + break; + + + case 'V': + prot_version = strtol( optarg, NULL, 10 ); + break; + + + case 'T': + rcv_timeout = strtoul( optarg, NULL, 10 ); + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + +} // check_options + + + +int main( int argc, char *argv[] ) +{ + struct hostent *p_hostent; + + fprintf( stderr, "\n%s %s, %s, %s\n\n", program_name, program_version, + program_copyright, program_contact ); + + check_options( argc, argv ); + + if ( rcv_timeout == 0 ) + rcv_timeout = RCV_TIMEOUT; + + prot_version = check_bounds( prot_version, MIN_REQ_NTP_VERSION, + MAX_REQ_NTP_VERSION, DEFAULT_REQ_NTP_VERSION ); + + if ( ( argc - optind ) > 0 ) // a host name has been specified + tgt_host = argv[optind]; + else + must_print_usage = 1; // required in client mode + + if ( must_print_usage ) + { + usage(); + return 1; + } + + + if ( tgt_host ) + { + // Construct name, with no wildcards, of the socket to send to. + // getnostbyname() returns a structure including the network address + // of the specified host. + p_hostent = gethostbyname( tgt_host ); + + if ( p_hostent == 0 ) + { + mbglog( LOG_ERR, "Unknown host %s: (error code %i)", tgt_host, h_errno ); + exit( 2 ); + } + + // set up host info for sending + memset( &tgt_addr, 0, sizeof( tgt_addr ) ); + memcpy( &tgt_addr.sin_addr, p_hostent->h_addr, p_hostent->h_length ); + tgt_addr.sin_family = AF_INET; + tgt_addr.sin_port = htons( NTP_PORT ); + } + + + reset_query_stats( &glb_query_stats ); + + // setup packet templates + init_ntp_req_packet( &default_ntp_req_packet, MODE_CLIENT, prot_version ); + + printf( "Host %s%s\n", tgt_host, run_continuously ? ", running continuously" : "" ); + + do_ntp_queries(); + + return 0; +} |