summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Burnicki <martin.burnicki@meinberg.de>2014-04-01 12:00:00 +0200
committerMartin Burnicki <martin.burnicki@meinberg.de>2014-04-01 12:00:00 +0200
commit753f5617f666edb989500b2d9aab3656328f18c3 (patch)
tree20f48b86be11be50d71435080e58210fdeadcd52
downloadntptest-753f5617f666edb989500b2d9aab3656328f18c3.tar.gz
ntptest-753f5617f666edb989500b2d9aab3656328f18c3.zip
Initial version1.0
-rwxr-xr-xMakefile48
-rwxr-xr-xREADME103
-rwxr-xr-xmbglib/common/mbg_ntp_test_util.c286
-rwxr-xr-xmbglib/common/mbg_ntp_test_util.h292
-rwxr-xr-xmbglib/common/mbg_tgt.h590
-rwxr-xr-xmbglib/common/mbgntp.h208
-rwxr-xr-xmbglib/common/words.h363
-rwxr-xr-xntptest.c310
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)
+
diff --git a/README b/README
new file mode 100755
index 0000000..063f3f1
--- /dev/null
+++ b/README
@@ -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;
+}