summaryrefslogtreecommitdiffstats
path: root/ntpdate
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>2008-08-17 17:37:33 +0000
committerroberto <roberto@FreeBSD.org>2008-08-17 17:37:33 +0000
commit4ded1c1fa0bc21c61f91a2dbe864835986745121 (patch)
tree16d100fbc9dae63888d48b464e471ba0e5065193 /ntpdate
parent8b5a86d4fda08a9c68231415812edcb26be52f79 (diff)
downloadFreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.zip
FreeBSD-src-4ded1c1fa0bc21c61f91a2dbe864835986745121.tar.gz
Flatten the dist and various 4.n.n trees in preparation of future ntp imports.
Diffstat (limited to 'ntpdate')
-rw-r--r--ntpdate/Makefile.am22
-rw-r--r--ntpdate/Makefile.in481
-rw-r--r--ntpdate/README7
-rw-r--r--ntpdate/ntpdate.c2225
-rw-r--r--ntpdate/ntpdate.h104
-rw-r--r--ntpdate/ntptime_config.c552
-rw-r--r--ntpdate/ntptimeset.c2171
7 files changed, 5562 insertions, 0 deletions
diff --git a/ntpdate/Makefile.am b/ntpdate/Makefile.am
new file mode 100644
index 0000000..bfe3fea
--- /dev/null
+++ b/ntpdate/Makefile.am
@@ -0,0 +1,22 @@
+#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+#bin_PROGRAMS = ntpdate ntptimeset
+bin_PROGRAMS = ntpdate
+EXTRA_PROGRAMS = ntptimeset
+ntptimeset_SOURCES = ntptimeset.c ntptime_config.c
+INCLUDES = -I$(top_srcdir)/include
+# LDADD might need RESLIB and ADJLIB
+LDADD = version.o ../libntp/libntp.a
+DISTCLEANFILES = .version version.c stamp-v
+noinst_HEADERS = ntpdate.h
+#EXTRA_DIST = ntpdate.mak
+ETAGS_ARGS = Makefile.am
+
+$(PROGRAMS): $(LDADD)
+
+../libntp/libntp.a:
+ cd ../libntp && $(MAKE)
+
+version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/version
+ env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpdate
+ $(COMPILE) -c version.c
diff --git a/ntpdate/Makefile.in b/ntpdate/Makefile.in
new file mode 100644
index 0000000..391f494
--- /dev/null
+++ b/ntpdate/Makefile.in
@@ -0,0 +1,481 @@
+# Makefile.in generated by automake 1.7.7 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+ARLIB_DIR = @ARLIB_DIR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHUTEST = @CHUTEST@
+CLKTEST = @CLKTEST@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DCFD = @DCFD@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EF_LIBS = @EF_LIBS@
+EF_PROGS = @EF_PROGS@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LCRYPTO = @LCRYPTO@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBPARSE = @LIBPARSE@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MAKE_ADJTIMED = @MAKE_ADJTIMED@
+MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@
+MAKE_LIBNTPSIM = @MAKE_LIBNTPSIM@
+MAKE_LIBPARSE = @MAKE_LIBPARSE@
+MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@
+MAKE_NTPDSIM = @MAKE_NTPDSIM@
+MAKE_NTPTIME = @MAKE_NTPTIME@
+MAKE_NTP_KEYGEN = @MAKE_NTP_KEYGEN@
+MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@
+MAKE_SNTP = @MAKE_SNTP@
+MAKE_TICKADJ = @MAKE_TICKADJ@
+MAKE_TIMETRIM = @MAKE_TIMETRIM@
+OBJEXT = @OBJEXT@
+OPENSSL = @OPENSSL@
+OPENSSL_INC = @OPENSSL_INC@
+OPENSSL_LIB = @OPENSSL_LIB@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_PERL = @PATH_PERL@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PATH_SH = @PATH_SH@
+PROPDELAY = @PROPDELAY@
+RANLIB = @RANLIB@
+READLINE_LIBS = @READLINE_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TESTDCF = @TESTDCF@
+U = @U@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+
+#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies
+AUTOMAKE_OPTIONS = ../util/ansi2knr
+#bin_PROGRAMS = ntpdate ntptimeset
+bin_PROGRAMS = ntpdate
+EXTRA_PROGRAMS = ntptimeset
+ntptimeset_SOURCES = ntptimeset.c ntptime_config.c
+INCLUDES = -I$(top_srcdir)/include
+# LDADD might need RESLIB and ADJLIB
+LDADD = version.o ../libntp/libntp.a
+DISTCLEANFILES = .version version.c stamp-v
+noinst_HEADERS = ntpdate.h
+#EXTRA_DIST = ntpdate.mak
+ETAGS_ARGS = Makefile.am
+subdir = ntpdate
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+EXTRA_PROGRAMS = ntptimeset$(EXEEXT)
+bin_PROGRAMS = ntpdate$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+
+ntpdate_SOURCES = ntpdate.c
+ntpdate_OBJECTS = ntpdate$U.$(OBJEXT)
+ntpdate_LDADD = $(LDADD)
+ntpdate_DEPENDENCIES = version.o ../libntp/libntp.a
+ntpdate_LDFLAGS =
+am_ntptimeset_OBJECTS = ntptimeset$U.$(OBJEXT) \
+ ntptime_config$U.$(OBJEXT)
+ntptimeset_OBJECTS = $(am_ntptimeset_OBJECTS)
+ntptimeset_LDADD = $(LDADD)
+ntptimeset_DEPENDENCIES = version.o ../libntp/libntp.a
+ntptimeset_LDFLAGS =
+
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ntpdate$U.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ntptime_config$U.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/ntptimeset$U.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = ntpdate.c $(ntptimeset_SOURCES)
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.in \
+ Makefile.am
+SOURCES = ntpdate.c $(ntptimeset_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu ntpdate/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
+ rm -f $(DESTDIR)$(bindir)/$$f; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+ntpdate$(EXEEXT): $(ntpdate_OBJECTS) $(ntpdate_DEPENDENCIES)
+ @rm -f ntpdate$(EXEEXT)
+ $(LINK) $(ntpdate_LDFLAGS) $(ntpdate_OBJECTS) $(ntpdate_LDADD) $(LIBS)
+ntptimeset$(EXEEXT): $(ntptimeset_OBJECTS) $(ntptimeset_DEPENDENCIES)
+ @rm -f ntptimeset$(EXEEXT)
+ $(LINK) $(ntptimeset_LDFLAGS) $(ntptimeset_OBJECTS) $(ntptimeset_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+ANSI2KNR = ../util/ansi2knr
+../util/ansi2knr:
+ cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr
+
+mostlyclean-kr:
+ -test "$U" = "" || rm -f *_.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdate$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntptime_config$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntptimeset$U.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+ntpdate_.c: ntpdate.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdate.c; then echo $(srcdir)/ntpdate.c; else echo ntpdate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+ntptime_config_.c: ntptime_config.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptime_config.c; then echo $(srcdir)/ntptime_config.c; else echo ntptime_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+ntptimeset_.c: ntptimeset.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptimeset.c; then echo $(srcdir)/ntptimeset.c; else echo ntptimeset.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+ntpdate_.$(OBJEXT) ntptime_config_.$(OBJEXT) ntptimeset_.$(OBJEXT) : \
+$(ANSI2KNR)
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-binPROGRAMS install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-kr pdf pdf-am ps ps-am tags \
+ uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am
+
+
+$(PROGRAMS): $(LDADD)
+
+../libntp/libntp.a:
+ cd ../libntp && $(MAKE)
+
+version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/version
+ env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpdate
+ $(COMPILE) -c version.c
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ntpdate/README b/ntpdate/README
new file mode 100644
index 0000000..27b51ed
--- /dev/null
+++ b/ntpdate/README
@@ -0,0 +1,7 @@
+README file for directory ./ntpdate of the NTP Version 4 distribution
+
+This directory contains the sources for the ntpdate utility program. See
+the README and RELNOTES files in the parent directory for directions on
+how to make and install this program. The current version number of this
+program is in the version.c file.
+
diff --git a/ntpdate/ntpdate.c b/ntpdate/ntpdate.c
new file mode 100644
index 0000000..b2cbe7e
--- /dev/null
+++ b/ntpdate/ntpdate.c
@@ -0,0 +1,2225 @@
+/*
+ * ntpdate - set the time of day by polling one or more NTP servers
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_NETINFO
+#include <netinfo/ni.h>
+#endif
+
+#include "ntp_machine.h"
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntpdate.h"
+#include "ntp_string.h"
+#include "ntp_syslog.h"
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+#ifndef SYS_WINNT
+# include <netdb.h>
+# ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+# else
+# include <signal.h>
+# endif
+# ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif
+#endif /* SYS_WINNT */
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#include <arpa/inet.h>
+
+#ifdef __QNXNTO__
+# include "adjtime.h"
+#endif
+
+#ifdef SYS_VXWORKS
+# include "ioLib.h"
+# include "sockLib.h"
+# include "timers.h"
+
+/* select wants a zero structure ... */
+struct timeval timeout = {0,0};
+#else
+struct timeval timeout = {60,0};
+#endif
+
+#ifdef HAVE_NETINFO
+#include <netinfo/ni.h>
+#endif
+
+#include "recvbuff.h"
+
+#ifdef SYS_WINNT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy
+ on Windows NT timers. */
+#pragma comment(lib, "winmm")
+#endif /* SYS_WINNT */
+
+/*
+ * Scheduling priority we run at
+ */
+#ifndef SYS_VXWORKS
+# define NTPDATE_PRIO (-12)
+#else
+# define NTPDATE_PRIO (100)
+#endif
+
+#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
+/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
+static timer_t ntpdate_timerid;
+#endif
+
+/*
+ * Compatibility stuff for Version 2
+ */
+#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */
+#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */
+#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */
+#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */
+#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */
+#define NTP_MAXLIST 5 /* maximum select list size */
+#define PEER_SHIFT 8 /* 8 suitable for crystal time base */
+
+/*
+ * Debugging flag
+ */
+volatile int debug = 0;
+
+/*
+ * File descriptor masks etc. for call to select
+ */
+
+int ai_fam_templ;
+int nbsock;
+SOCKET fd[MAX_AF]; /* support up to 2 sockets */
+int fd_family[MAX_AF]; /* to remember the socket family */
+#ifdef HAVE_POLL_H
+struct pollfd fdmask[MAX_AF];
+#else
+fd_set fdmask;
+int maxfd;
+#endif
+int polltest = 0;
+
+/*
+ * Initializing flag. All async routines watch this and only do their
+ * thing when it is clear.
+ */
+int initializing = 1;
+
+/*
+ * Alarm flag. Set when an alarm occurs
+ */
+volatile int alarm_flag = 0;
+
+/*
+ * Simple query flag.
+ */
+int simple_query = 0;
+
+/*
+ * Unpriviledged port flag.
+ */
+int unpriv_port = 0;
+
+/*
+ * Time to spend measuring drift rate
+ */
+int rate = 0;
+
+/*
+ * Program name.
+ */
+char *progname;
+
+/*
+ * Systemwide parameters and flags
+ */
+int sys_samples = DEFSAMPLES; /* number of samples/server */
+u_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */
+struct server *sys_servers; /* the server list */
+int sys_numservers = 0; /* number of servers to poll */
+int sys_authenticate = 0; /* true when authenticating */
+u_int32 sys_authkey = 0; /* set to authentication key in use */
+u_long sys_authdelay = 0; /* authentication delay */
+int sys_version = NTP_VERSION; /* version to poll with */
+
+/*
+ * The current internal time
+ */
+u_long current_time = 0;
+
+/*
+ * Counter for keeping track of completed servers
+ */
+int complete_servers = 0;
+
+/*
+ * File of encryption keys
+ */
+
+#ifndef KEYFILE
+# ifndef SYS_WINNT
+#define KEYFILE "/etc/ntp.keys"
+# else
+#define KEYFILE "%windir%\\ntp.keys"
+# endif /* SYS_WINNT */
+#endif /* KEYFILE */
+
+#ifndef SYS_WINNT
+const char *key_file = KEYFILE;
+#else
+char key_file_storage[MAX_PATH+1], *key_file ;
+#endif /* SYS_WINNT */
+
+/*
+ * Miscellaneous flags
+ */
+int verbose = 0;
+int always_step = 0;
+int never_step = 0;
+
+int ntpdatemain P((int, char **));
+
+static void transmit P((struct server *));
+static void receive P((struct recvbuf *));
+static void server_data P((struct server *, s_fp, l_fp *, u_fp));
+static void clock_filter P((struct server *));
+static struct server *clock_select P((void));
+static int clock_adjust P((void));
+static void addserver P((char *));
+static struct server *findserver P((struct sockaddr_storage *));
+ void timer P((void));
+static void init_alarm P((void));
+#ifndef SYS_WINNT
+static RETSIGTYPE alarming P((int));
+#endif /* SYS_WINNT */
+static void init_io P((void));
+static void sendpkt P((struct sockaddr_storage *, struct pkt *, int));
+void input_handler P((void));
+
+static int l_adj_systime P((l_fp *));
+static int l_step_systime P((l_fp *));
+
+static void printserver P((struct server *, FILE *));
+
+#ifdef SYS_WINNT
+int on = 1;
+WORD wVersionRequested;
+WSADATA wsaData;
+HANDLE TimerThreadHandle = NULL;
+#endif /* SYS_WINNT */
+
+#ifdef NO_MAIN_ALLOWED
+CALL(ntpdate,"ntpdate",ntpdatemain);
+
+void clear_globals()
+{
+ /*
+ * Debugging flag
+ */
+ debug = 0;
+
+ ntp_optind = 0;
+ /*
+ * Initializing flag. All async routines watch this and only do their
+ * thing when it is clear.
+ */
+ initializing = 1;
+
+ /*
+ * Alarm flag. Set when an alarm occurs
+ */
+ alarm_flag = 0;
+
+ /*
+ * Simple query flag.
+ */
+ simple_query = 0;
+
+ /*
+ * Unpriviledged port flag.
+ */
+ unpriv_port = 0;
+
+ /*
+ * Time to spend measuring drift rate
+ */
+ rate = 0;
+ /*
+ * Systemwide parameters and flags
+ */
+ sys_numservers = 0; /* number of servers to poll */
+ sys_authenticate = 0; /* true when authenticating */
+ sys_authkey = 0; /* set to authentication key in use */
+ sys_authdelay = 0; /* authentication delay */
+ sys_version = NTP_VERSION; /* version to poll with */
+
+ /*
+ * The current internal time
+ */
+ current_time = 0;
+
+ /*
+ * Counter for keeping track of completed servers
+ */
+ complete_servers = 0;
+ verbose = 0;
+ always_step = 0;
+ never_step = 0;
+}
+#endif
+
+#ifdef HAVE_NETINFO
+static ni_namelist *getnetinfoservers P((void));
+#endif
+
+/*
+ * Main program. Initialize us and loop waiting for I/O and/or
+ * timer expiries.
+ */
+#ifndef NO_MAIN_ALLOWED
+int
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ return ntpdatemain (argc, argv);
+}
+#endif /* NO_MAIN_ALLOWED */
+
+int
+ntpdatemain (
+ int argc,
+ char *argv[]
+ )
+{
+ int was_alarmed;
+ struct recvbuf *rbuflist;
+ struct recvbuf *rbuf;
+ l_fp tmp;
+ int errflg;
+ int c;
+ int nfound;
+
+#ifdef HAVE_NETINFO
+ ni_namelist *netinfoservers;
+#endif
+#ifdef SYS_WINNT
+ HANDLE process_handle;
+
+ wVersionRequested = MAKEWORD(1,1);
+ if (WSAStartup(wVersionRequested, &wsaData)) {
+ netsyslog(LOG_ERR, "No useable winsock.dll: %m");
+ exit(1);
+ }
+
+ key_file = key_file_storage;
+
+ if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH))
+ {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n");
+ }
+#endif /* SYS_WINNT */
+
+#ifdef NO_MAIN_ALLOWED
+ clear_globals();
+#endif
+
+ errflg = 0;
+ progname = argv[0];
+ syslogit = 0;
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, "46a:bBde:k:o:p:qr:st:uv")) != EOF)
+ switch (c)
+ {
+ case '4':
+ ai_fam_templ = AF_INET;
+ break;
+ case '6':
+ ai_fam_templ = AF_INET6;
+ break;
+ case 'a':
+ c = atoi(ntp_optarg);
+ sys_authenticate = 1;
+ sys_authkey = c;
+ break;
+ case 'b':
+ always_step++;
+ never_step = 0;
+ break;
+ case 'B':
+ never_step++;
+ always_step = 0;
+ break;
+ case 'd':
+ ++debug;
+ break;
+ case 'e':
+ if (!atolfp(ntp_optarg, &tmp)
+ || tmp.l_ui != 0) {
+ (void) fprintf(stderr,
+ "%s: encryption delay %s is unlikely\n",
+ progname, ntp_optarg);
+ errflg++;
+ } else {
+ sys_authdelay = tmp.l_uf;
+ }
+ break;
+ case 'k':
+ key_file = ntp_optarg;
+ break;
+ case 'o':
+ sys_version = atoi(ntp_optarg);
+ break;
+ case 'p':
+ c = atoi(ntp_optarg);
+ if (c <= 0 || c > NTP_SHIFT) {
+ (void) fprintf(stderr,
+ "%s: number of samples (%d) is invalid\n",
+ progname, c);
+ errflg++;
+ } else {
+ sys_samples = c;
+ }
+ break;
+ case 'q':
+ simple_query = 1;
+ break;
+ case 'r':
+ c = atoi(ntp_optarg);
+ if (c <= 0 || c > (60 * 60)) {
+ (void) fprintf(stderr,
+ "%s: rate (%d) is invalid: 0 - %d\n",
+ progname, c, (60 * 60));
+ errflg++;
+ } else {
+ rate = c;
+ }
+ break;
+ case 's':
+ syslogit = 1;
+ break;
+ case 't':
+ if (!atolfp(ntp_optarg, &tmp)) {
+ (void) fprintf(stderr,
+ "%s: timeout %s is undecodeable\n",
+ progname, ntp_optarg);
+ errflg++;
+ } else {
+ sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ)
+ + 0x8000) >> 16;
+ if (sys_timeout == 0)
+ sys_timeout = 1;
+ }
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'u':
+ unpriv_port = 1;
+ break;
+ case '?':
+ ++errflg;
+ break;
+ default:
+ break;
+ }
+
+ if (errflg) {
+ (void) fprintf(stderr,
+ "usage: %s [-46bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-t timeo] server ...\n",
+ progname);
+ exit(2);
+ }
+
+ if (debug || simple_query) {
+#ifdef HAVE_SETVBUF
+ static char buf[BUFSIZ];
+ setvbuf(stdout, buf, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(stdout);
+#endif
+ }
+
+ /*
+ * Logging. Open the syslog if we have to
+ */
+ if (syslogit) {
+#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
+# ifndef LOG_DAEMON
+ openlog("ntpdate", LOG_PID);
+# else
+
+# ifndef LOG_NTP
+# define LOG_NTP LOG_DAEMON
+# endif
+ openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP);
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ else
+ setlogmask(LOG_UPTO(LOG_INFO));
+# endif /* LOG_DAEMON */
+#endif /* SYS_WINNT */
+ }
+
+ if (debug || verbose)
+ msyslog(LOG_NOTICE, "%s", Version);
+
+ /*
+ * Add servers we are going to be polling
+ */
+#ifdef HAVE_NETINFO
+ netinfoservers = getnetinfoservers();
+#endif
+
+ for ( ; ntp_optind < argc; ntp_optind++)
+ addserver(argv[ntp_optind]);
+
+#ifdef HAVE_NETINFO
+ if (netinfoservers) {
+ if ( netinfoservers->ni_namelist_len &&
+ *netinfoservers->ni_namelist_val ) {
+ u_int servercount = 0;
+ while (servercount < netinfoservers->ni_namelist_len) {
+ if (debug) msyslog(LOG_DEBUG,
+ "Adding time server %s from NetInfo configuration.",
+ netinfoservers->ni_namelist_val[servercount]);
+ addserver(netinfoservers->ni_namelist_val[servercount++]);
+ }
+ }
+ ni_namelist_free(netinfoservers);
+ free(netinfoservers);
+ }
+#endif
+
+ if (sys_numservers == 0) {
+ msyslog(LOG_ERR, "no servers can be used, exiting");
+ exit(1);
+ }
+
+ /*
+ * Initialize the time of day routines and the I/O subsystem
+ */
+ if (sys_authenticate) {
+ init_auth();
+ if (!authreadkeys(key_file)) {
+ msyslog(LOG_ERR, "no key file <%s>, exiting", key_file);
+ exit(1);
+ }
+ authtrust(sys_authkey, 1);
+ if (!authistrusted(sys_authkey)) {
+ char buf[10];
+
+ (void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
+ msyslog(LOG_ERR, "authentication key %s unknown", buf);
+ exit(1);
+ }
+ }
+ init_io();
+ init_alarm();
+
+ /*
+ * Set the priority.
+ */
+#ifdef SYS_VXWORKS
+ taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
+#endif
+#if defined(HAVE_ATT_NICE)
+ nice (NTPDATE_PRIO);
+#endif
+#if defined(HAVE_BSD_NICE)
+ (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
+#endif
+#ifdef SYS_WINNT
+ process_handle = GetCurrentProcess();
+ if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
+ msyslog(LOG_ERR, "SetPriorityClass failed: %m");
+ }
+#endif /* SYS_WINNT */
+
+
+
+ initializing = 0;
+ was_alarmed = 0;
+ rbuflist = (struct recvbuf *)0;
+
+ while (complete_servers < sys_numservers) {
+#ifdef HAVE_POLL_H
+ struct pollfd* rdfdes;
+ rdfdes = fdmask;
+#else
+ fd_set rdfdes;
+ rdfdes = fdmask;
+#endif
+
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+ rbuflist = getrecvbufs(); /* get received buffers */
+
+ if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
+ /*
+ * Nothing to do. Wait for something.
+ */
+#ifdef HAVE_POLL_H
+ nfound = poll(rdfdes, (unsigned int)nbsock, timeout.tv_sec * 1000);
+
+#else
+ nfound = select(maxfd, &rdfdes, (fd_set *)0,
+ (fd_set *)0, &timeout);
+#endif
+ if (nfound > 0)
+ input_handler();
+ else if (
+#ifndef SYS_WINNT
+ nfound == -1
+#else
+ nfound == SOCKET_ERROR
+#endif /* SYS_WINNT */
+ ) {
+#ifndef SYS_WINNT
+ if (errno != EINTR)
+#endif
+ netsyslog(LOG_ERR,
+#ifdef HAVE_POLL_H
+ "poll() error: %m"
+#else
+ "select() error: %m"
+#endif
+ );
+ } else {
+#ifndef SYS_VXWORKS
+ netsyslog(LOG_DEBUG,
+#ifdef HAVE_POLL_H
+ "poll(): nfound = %d, error: %m",
+#else
+ "select(): nfound = %d, error: %m",
+#endif
+ nfound);
+#endif
+ }
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+ rbuflist = getrecvbufs(); /* get received buffers */
+ }
+
+ /*
+ * Out here, signals are unblocked. Call receive
+ * procedure for each incoming packet.
+ */
+ while (rbuflist != (struct recvbuf *)0) {
+ rbuf = rbuflist;
+ rbuflist = rbuf->next;
+ receive(rbuf);
+ freerecvbuf(rbuf);
+ }
+
+ /*
+ * Call timer to process any timeouts
+ */
+ if (was_alarmed) {
+ timer();
+ was_alarmed = 0;
+ }
+
+ /*
+ * Go around again
+ */
+ }
+
+ /*
+ * When we get here we've completed the polling of all servers.
+ * Adjust the clock, then exit.
+ */
+#ifdef SYS_WINNT
+ WSACleanup();
+#endif
+#ifdef SYS_VXWORKS
+ close (fd);
+ timer_delete(ntpdate_timerid);
+#endif
+
+ return clock_adjust();
+}
+
+
+/*
+ * transmit - transmit a packet to the given server, or mark it completed.
+ * This is called by the timeout routine and by the receive
+ * procedure.
+ */
+static void
+transmit(
+ register struct server *server
+ )
+{
+ struct pkt xpkt;
+
+ if (debug)
+ printf("transmit(%s)\n", stoa(&(server->srcadr)));
+
+ if (server->filter_nextpt < server->xmtcnt) {
+ l_fp ts;
+ /*
+ * Last message to this server timed out. Shift
+ * zeros into the filter.
+ */
+ L_CLR(&ts);
+ server_data(server, 0, &ts, 0);
+ }
+
+ if ((int)server->filter_nextpt >= sys_samples) {
+ /*
+ * Got all the data we need. Mark this guy
+ * completed and return.
+ */
+ server->event_time = 0;
+ complete_servers++;
+ return;
+ }
+
+ /*
+ * If we're here, send another message to the server. Fill in
+ * the packet and let 'er rip.
+ */
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
+ sys_version, MODE_CLIENT);
+ xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
+ xpkt.ppoll = NTP_MINPOLL;
+ xpkt.precision = NTPDATE_PRECISION;
+ xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
+ xpkt.rootdispersion = htonl(NTPDATE_DISP);
+ xpkt.refid = htonl(NTPDATE_REFID);
+ L_CLR(&xpkt.reftime);
+ L_CLR(&xpkt.org);
+ L_CLR(&xpkt.rec);
+
+ /*
+ * Determine whether to authenticate or not. If so,
+ * fill in the extended part of the packet and do it.
+ * If not, just timestamp it and send it away.
+ */
+ if (sys_authenticate) {
+ int len;
+
+ xpkt.exten[0] = htonl(sys_authkey);
+ get_systime(&server->xmt);
+ L_ADDUF(&server->xmt, sys_authdelay);
+ HTONL_FP(&server->xmt, &xpkt.xmt);
+ len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
+ sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len));
+
+ if (debug > 1)
+ printf("transmit auth to %s\n",
+ stoa(&(server->srcadr)));
+ } else {
+ get_systime(&(server->xmt));
+ HTONL_FP(&server->xmt, &xpkt.xmt);
+ sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC);
+
+ if (debug > 1)
+ printf("transmit to %s\n", stoa(&(server->srcadr)));
+ }
+
+ /*
+ * Update the server timeout and transmit count
+ */
+ server->event_time = current_time + sys_timeout;
+ server->xmtcnt++;
+}
+
+
+/*
+ * receive - receive and process an incoming frame
+ */
+static void
+receive(
+ struct recvbuf *rbufp
+ )
+{
+ register struct pkt *rpkt;
+ register struct server *server;
+ register s_fp di;
+ l_fp t10, t23, tmp;
+ l_fp org;
+ l_fp rec;
+ l_fp ci;
+ int has_mac;
+ int is_authentic;
+
+ if (debug)
+ printf("receive(%s)\n", stoa(&rbufp->recv_srcadr));
+ /*
+ * Check to see if the packet basically looks like something
+ * intended for us.
+ */
+ if (rbufp->recv_length == LEN_PKT_NOMAC)
+ has_mac = 0;
+ else if (rbufp->recv_length >= LEN_PKT_NOMAC)
+ has_mac = 1;
+ else {
+ if (debug)
+ printf("receive: packet length %d\n",
+ rbufp->recv_length);
+ return; /* funny length packet */
+ }
+
+ rpkt = &(rbufp->recv_pkt);
+ if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
+ PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
+ return;
+ }
+
+ if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
+ && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
+ || rpkt->stratum >= STRATUM_UNSPEC) {
+ if (debug)
+ printf("receive: mode %d stratum %d\n",
+ PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
+ return;
+ }
+
+ /*
+ * So far, so good. See if this is from a server we know.
+ */
+ server = findserver(&(rbufp->recv_srcadr));
+ if (server == NULL) {
+ if (debug)
+ printf("receive: server not found\n");
+ return;
+ }
+
+ /*
+ * Decode the org timestamp and make sure we're getting a response
+ * to our last request.
+ */
+ NTOHL_FP(&rpkt->org, &org);
+ if (!L_ISEQU(&org, &server->xmt)) {
+ if (debug)
+ printf("receive: pkt.org and peer.xmt differ\n");
+ return;
+ }
+
+ /*
+ * Check out the authenticity if we're doing that.
+ */
+ if (!sys_authenticate)
+ is_authentic = 1;
+ else {
+ is_authentic = 0;
+
+ if (debug > 3)
+ printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
+ (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
+ (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
+ LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
+
+ if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
+ authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
+ (int)(rbufp->recv_length - LEN_PKT_NOMAC)))
+ is_authentic = 1;
+ if (debug)
+ printf("receive: authentication %s\n",
+ is_authentic ? "passed" : "failed");
+ }
+ server->trust <<= 1;
+ if (!is_authentic)
+ server->trust |= 1;
+
+ /*
+ * Looks good. Record info from the packet.
+ */
+ server->leap = PKT_LEAP(rpkt->li_vn_mode);
+ server->stratum = PKT_TO_STRATUM(rpkt->stratum);
+ server->precision = rpkt->precision;
+ server->rootdelay = ntohl(rpkt->rootdelay);
+ server->rootdispersion = ntohl(rpkt->rootdispersion);
+ server->refid = rpkt->refid;
+ NTOHL_FP(&rpkt->reftime, &server->reftime);
+ NTOHL_FP(&rpkt->rec, &rec);
+ NTOHL_FP(&rpkt->xmt, &server->org);
+
+ /*
+ * Make sure the server is at least somewhat sane. If not, try
+ * again.
+ */
+ if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
+ transmit(server);
+ return;
+ }
+
+ /*
+ * Calculate the round trip delay (di) and the clock offset (ci).
+ * We use the equations (reordered from those in the spec):
+ *
+ * d = (t2 - t3) - (t1 - t0)
+ * c = ((t2 - t3) + (t1 - t0)) / 2
+ */
+ t10 = server->org; /* pkt.xmt == t1 */
+ L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
+
+ t23 = rec; /* pkt.rec == t2 */
+ L_SUB(&t23, &org); /* pkt->org == t3 */
+
+ /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
+ /*
+ * Calculate (ci) = ((t1 - t0) / 2) + ((t2 - t3) / 2)
+ * For large offsets this may prevent an overflow on '+'
+ */
+ ci = t10;
+ L_RSHIFT(&ci);
+ tmp = t23;
+ L_RSHIFT(&tmp);
+ L_ADD(&ci, &tmp);
+
+ /*
+ * Calculate di in t23 in full precision, then truncate
+ * to an s_fp.
+ */
+ L_SUB(&t23, &t10);
+ di = LFPTOFP(&t23);
+
+ if (debug > 3)
+ printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
+
+ di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
+ + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
+
+ if (di <= 0) { /* value still too raunchy to use? */
+ L_CLR(&ci);
+ di = 0;
+ } else {
+ di = max(di, NTP_MINDIST);
+ }
+
+ /*
+ * Shift this data in, then transmit again.
+ */
+ server_data(server, (s_fp) di, &ci, 0);
+ transmit(server);
+}
+
+
+/*
+ * server_data - add a sample to the server's filter registers
+ */
+static void
+server_data(
+ register struct server *server,
+ s_fp d,
+ l_fp *c,
+ u_fp e
+ )
+{
+ u_short i;
+
+ i = server->filter_nextpt;
+ if (i < NTP_SHIFT) {
+ server->filter_delay[i] = d;
+ server->filter_offset[i] = *c;
+ server->filter_soffset[i] = LFPTOFP(c);
+ server->filter_error[i] = e;
+ server->filter_nextpt = (u_short)(i + 1);
+ }
+}
+
+
+/*
+ * clock_filter - determine a server's delay, dispersion and offset
+ */
+static void
+clock_filter(
+ register struct server *server
+ )
+{
+ register int i, j;
+ int ord[NTP_SHIFT];
+
+ /*
+ * Sort indices into increasing delay order
+ */
+ for (i = 0; i < sys_samples; i++)
+ ord[i] = i;
+
+ for (i = 0; i < (sys_samples-1); i++) {
+ for (j = i+1; j < sys_samples; j++) {
+ if (server->filter_delay[ord[j]] == 0)
+ continue;
+ if (server->filter_delay[ord[i]] == 0
+ || (server->filter_delay[ord[i]]
+ > server->filter_delay[ord[j]])) {
+ register int tmp;
+
+ tmp = ord[i];
+ ord[i] = ord[j];
+ ord[j] = tmp;
+ }
+ }
+ }
+
+ /*
+ * Now compute the dispersion, and assign values to delay and
+ * offset. If there are no samples in the register, delay and
+ * offset go to zero and dispersion is set to the maximum.
+ */
+ if (server->filter_delay[ord[0]] == 0) {
+ server->delay = 0;
+ L_CLR(&server->offset);
+ server->soffset = 0;
+ server->dispersion = PEER_MAXDISP;
+ } else {
+ register s_fp d;
+
+ server->delay = server->filter_delay[ord[0]];
+ server->offset = server->filter_offset[ord[0]];
+ server->soffset = LFPTOFP(&server->offset);
+ server->dispersion = 0;
+ for (i = 1; i < sys_samples; i++) {
+ if (server->filter_delay[ord[i]] == 0)
+ d = PEER_MAXDISP;
+ else {
+ d = server->filter_soffset[ord[i]]
+ - server->filter_soffset[ord[0]];
+ if (d < 0)
+ d = -d;
+ if (d > PEER_MAXDISP)
+ d = PEER_MAXDISP;
+ }
+ /*
+ * XXX This *knows* PEER_FILTER is 1/2
+ */
+ server->dispersion += (u_fp)(d) >> i;
+ }
+ }
+ /*
+ * We're done
+ */
+}
+
+
+/*
+ * clock_select - select the pick-of-the-litter clock from the samples
+ * we've got.
+ */
+static struct server *
+clock_select(void)
+{
+ register struct server *server;
+ register int i;
+ register int nlist;
+ register s_fp d;
+ register int j;
+ register int n;
+ s_fp local_threshold;
+ struct server *server_list[NTP_MAXCLOCK];
+ u_fp server_badness[NTP_MAXCLOCK];
+ struct server *sys_server;
+
+ /*
+ * This first chunk of code is supposed to go through all
+ * servers we know about to find the NTP_MAXLIST servers which
+ * are most likely to succeed. We run through the list
+ * doing the sanity checks and trying to insert anyone who
+ * looks okay. We are at all times aware that we should
+ * only keep samples from the top two strata and we only need
+ * NTP_MAXLIST of them.
+ */
+ nlist = 0; /* none yet */
+ for (server = sys_servers; server != NULL; server = server->next_server) {
+ if (server->delay == 0) {
+ if (debug)
+ printf("%s: Server dropped: no data\n", ntoa(&server->srcadr));
+ continue; /* no data */
+ }
+ if (server->stratum > NTP_INFIN) {
+ if (debug)
+ printf("%s: Server dropped: strata too high\n", ntoa(&server->srcadr));
+ continue; /* stratum no good */
+ }
+ if (server->delay > NTP_MAXWGT) {
+ if (debug)
+ printf("%s: Server dropped: server too far away\n",
+ ntoa(&server->srcadr));
+ continue; /* too far away */
+ }
+ if (server->leap == LEAP_NOTINSYNC) {
+ if (debug)
+ printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr));
+ continue; /* he's in trouble */
+ }
+ if (!L_ISHIS(&server->org, &server->reftime)) {
+ if (debug)
+ printf("%s: Server dropped: server is very broken\n",
+ ntoa(&server->srcadr));
+ continue; /* very broken host */
+ }
+ if ((server->org.l_ui - server->reftime.l_ui)
+ >= NTP_MAXAGE) {
+ if (debug)
+ printf("%s: Server dropped: Server has gone too long without sync\n",
+ ntoa(&server->srcadr));
+ continue; /* too long without sync */
+ }
+ if (server->trust != 0) {
+ if (debug)
+ printf("%s: Server dropped: Server is untrusted\n",
+ ntoa(&server->srcadr));
+ continue;
+ }
+
+ /*
+ * This one seems sane. Find where he belongs
+ * on the list.
+ */
+ d = server->dispersion + server->dispersion;
+ for (i = 0; i < nlist; i++)
+ if (server->stratum <= server_list[i]->stratum)
+ break;
+ for ( ; i < nlist; i++) {
+ if (server->stratum < server_list[i]->stratum)
+ break;
+ if (d < (s_fp) server_badness[i])
+ break;
+ }
+
+ /*
+ * If i points past the end of the list, this
+ * guy is a loser, else stick him in.
+ */
+ if (i >= NTP_MAXLIST)
+ continue;
+ for (j = nlist; j > i; j--)
+ if (j < NTP_MAXLIST) {
+ server_list[j] = server_list[j-1];
+ server_badness[j]
+ = server_badness[j-1];
+ }
+
+ server_list[i] = server;
+ server_badness[i] = d;
+ if (nlist < NTP_MAXLIST)
+ nlist++;
+ }
+
+ /*
+ * Got the five-or-less best. Cut the list where the number of
+ * strata exceeds two.
+ */
+ j = 0;
+ for (i = 1; i < nlist; i++)
+ if (server_list[i]->stratum > server_list[i-1]->stratum)
+ if (++j == 2) {
+ nlist = i;
+ break;
+ }
+
+ /*
+ * Whew! What we should have by now is 0 to 5 candidates for
+ * the job of syncing us. If we have none, we're out of luck.
+ * If we have one, he's a winner. If we have more, do falseticker
+ * detection.
+ */
+
+ if (nlist == 0)
+ sys_server = 0;
+ else if (nlist == 1) {
+ sys_server = server_list[0];
+ } else {
+ /*
+ * Re-sort by stratum, bdelay estimate quality and
+ * server.delay.
+ */
+ for (i = 0; i < nlist-1; i++)
+ for (j = i+1; j < nlist; j++) {
+ if (server_list[i]->stratum
+ < server_list[j]->stratum)
+ break; /* already sorted by stratum */
+ if (server_list[i]->delay
+ < server_list[j]->delay)
+ continue;
+ server = server_list[i];
+ server_list[i] = server_list[j];
+ server_list[j] = server;
+ }
+
+ /*
+ * Calculate the fixed part of the dispersion limit
+ */
+ local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
+ + NTP_MAXSKW;
+
+ /*
+ * Now drop samples until we're down to one.
+ */
+ while (nlist > 1) {
+ for (n = 0; n < nlist; n++) {
+ server_badness[n] = 0;
+ for (j = 0; j < nlist; j++) {
+ if (j == n) /* with self? */
+ continue;
+ d = server_list[j]->soffset
+ - server_list[n]->soffset;
+ if (d < 0) /* absolute value */
+ d = -d;
+ /*
+ * XXX This code *knows* that
+ * NTP_SELECT is 3/4
+ */
+ for (i = 0; i < j; i++)
+ d = (d>>1) + (d>>2);
+ server_badness[n] += d;
+ }
+ }
+
+ /*
+ * We now have an array of nlist badness
+ * coefficients. Find the badest. Find
+ * the minimum precision while we're at
+ * it.
+ */
+ i = 0;
+ n = server_list[0]->precision;;
+ for (j = 1; j < nlist; j++) {
+ if (server_badness[j] >= server_badness[i])
+ i = j;
+ if (n > server_list[j]->precision)
+ n = server_list[j]->precision;
+ }
+
+ /*
+ * i is the index of the server with the worst
+ * dispersion. If his dispersion is less than
+ * the threshold, stop now, else delete him and
+ * continue around again.
+ */
+ if ( (s_fp) server_badness[i] < (local_threshold
+ + (FP_SECOND >> (-n))))
+ break;
+ for (j = i + 1; j < nlist; j++)
+ server_list[j-1] = server_list[j];
+ nlist--;
+ }
+
+ /*
+ * What remains is a list of less than 5 servers. Take
+ * the best.
+ */
+ sys_server = server_list[0];
+ }
+
+ /*
+ * That's it. Return our server.
+ */
+ return sys_server;
+}
+
+
+/*
+ * clock_adjust - process what we've received, and adjust the time
+ * if we got anything decent.
+ */
+static int
+clock_adjust(void)
+{
+ register struct server *sp, *server;
+ s_fp absoffset;
+ int dostep;
+
+ for (sp = sys_servers; sp != NULL; sp = sp->next_server)
+ clock_filter(sp);
+ server = clock_select();
+
+ if (debug || simple_query) {
+ for (sp = sys_servers; sp != NULL; sp = sp->next_server)
+ printserver(sp, stdout);
+ }
+
+ if (server == 0) {
+ msyslog(LOG_ERR,
+ "no server suitable for synchronization found");
+ return(1);
+ }
+
+ if (always_step) {
+ dostep = 1;
+ } else if (never_step) {
+ dostep = 0;
+ } else {
+ absoffset = server->soffset;
+ if (absoffset < 0)
+ absoffset = -absoffset;
+ dostep = (absoffset >= NTPDATE_THRESHOLD || absoffset < 0);
+ }
+
+ if (dostep) {
+ if (simple_query || l_step_systime(&server->offset)) {
+ msyslog(LOG_NOTICE, "step time server %s offset %s sec",
+ stoa(&server->srcadr),
+ lfptoa(&server->offset, 6));
+ }
+ } else {
+#if !defined SYS_WINNT && !defined SYS_CYGWIN32
+ if (simple_query || l_adj_systime(&server->offset)) {
+ msyslog(LOG_NOTICE, "adjust time server %s offset %s sec",
+ stoa(&server->srcadr),
+ lfptoa(&server->offset, 6));
+ }
+#else
+ /* The NT SetSystemTimeAdjustment() call achieves slewing by
+ * changing the clock frequency. This means that we cannot specify
+ * it to slew the clock by a definite amount and then stop like
+ * the Unix adjtime() routine. We can technically adjust the clock
+ * frequency, have ntpdate sleep for a while, and then wake
+ * up and reset the clock frequency, but this might cause some
+ * grief if the user attempts to run ntpd immediately after
+ * ntpdate and the socket is in use.
+ */
+ printf("\nThe -b option is required by ntpdate on Windows NT platforms\n");
+ exit(1);
+#endif /* SYS_WINNT */
+ }
+ return(0);
+}
+
+
+/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */
+/*
+ * addserver - determine a server's address and allocate a new structure
+ * for it.
+ */
+static void
+addserver(
+ char *serv
+ )
+{
+ register struct server *server;
+ /* Address infos structure to store result of getaddrinfo */
+ struct addrinfo *addrResult;
+ /* Address infos structure to store hints for getaddrinfo */
+ struct addrinfo hints;
+ /* Error variable for getaddrinfo */
+ int error;
+ /* Service name */
+ char service[5];
+ strcpy(service, "ntp");
+
+ /* Get host address. Looking for UDP datagram connection. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai_fam_templ;
+ hints.ai_socktype = SOCK_DGRAM;
+
+#ifdef DEBUG
+ if (debug)
+ printf("Looking for host %s and service %s\n", serv, service);
+#endif
+
+ error = getaddrinfo(serv, service, &hints, &addrResult);
+ if (error != 0) {
+ fprintf(stderr, "Error : %s\n", gai_strerror(error));
+ msyslog(LOG_ERR, "can't find host %s\n", serv);
+ return;
+ }
+#ifdef DEBUG
+ else if (debug) {
+ fprintf(stderr, "host found : %s\n", stohost((struct sockaddr_storage*)addrResult->ai_addr));
+ }
+#endif
+
+ server = (struct server *)emalloc(sizeof(struct server));
+ memset((char *)server, 0, sizeof(struct server));
+
+ /* For now we only get the first returned server of the addrinfo list */
+ memset(&(server->srcadr), 0, sizeof(struct sockaddr_storage));
+ memcpy(&(server->srcadr), addrResult->ai_addr, addrResult->ai_addrlen);
+ server->event_time = ++sys_numservers;
+ if (sys_servers == NULL)
+ sys_servers = server;
+ else {
+ struct server *sp;
+
+ for (sp = sys_servers; sp->next_server != NULL;
+ sp = sp->next_server) ;
+ sp->next_server = server;
+ }
+}
+
+
+/*
+ * findserver - find a server in the list given its address
+ * ***(For now it isn't totally AF-Independant, to check later..)
+ */
+static struct server *
+findserver(
+ struct sockaddr_storage *addr
+ )
+{
+ struct server *server;
+ struct server *mc_server;
+
+ mc_server = NULL;
+ if (htons(((struct sockaddr_in*)addr)->sin_port) != NTP_PORT)
+ return 0;
+
+ for (server = sys_servers; server != NULL;
+ server = server->next_server) {
+
+ if (memcmp(addr, &server->srcadr, SOCKLEN(addr))==0)
+ return server;
+ /* Multicast compatibility to verify here... I'm not sure it's working */
+ if(addr->ss_family == AF_INET) {
+ if (IN_MULTICAST(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr)))
+ mc_server = server;
+ }
+ else {
+#ifdef AF_INET6
+ if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)(&server->srcadr))->sin6_addr))
+ mc_server = server;
+#else
+ return 0;
+#endif
+ }
+ }
+
+ if (mc_server != NULL) {
+
+ struct server *sp;
+
+ if (mc_server->event_time != 0) {
+ mc_server->event_time = 0;
+ complete_servers++;
+ }
+
+ server = (struct server *)emalloc(sizeof(struct server));
+ memset((char *)server, 0, sizeof(struct server));
+
+ memcpy(&server->srcadr, &addr, sizeof(struct sockaddr_storage));
+
+ server->event_time = ++sys_numservers;
+
+ for (sp = sys_servers; sp->next_server != NULL;
+ sp = sp->next_server) ;
+ sp->next_server = server;
+ transmit(server);
+ }
+ return NULL;
+}
+
+
+/*
+ * timer - process a timer interrupt
+ */
+void
+timer(void)
+{
+ struct server *server;
+
+ /*
+ * Bump the current idea of the time
+ */
+ current_time++;
+
+ /*
+ * Search through the server list looking for guys
+ * who's event timers have expired. Give these to
+ * the transmit routine.
+ */
+ for (server = sys_servers; server != NULL;
+ server = server->next_server) {
+ if (server->event_time != 0
+ && server->event_time <= current_time)
+ transmit(server);
+ }
+}
+
+
+/*
+ * The code duplication in the following subroutine sucks, but
+ * we need to appease ansi2knr.
+ */
+
+#ifndef SYS_WINNT
+/*
+ * alarming - record the occurance of an alarm interrupt
+ */
+static RETSIGTYPE
+alarming(
+ int sig
+ )
+{
+ alarm_flag++;
+}
+#else
+void CALLBACK
+alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ alarm_flag++;
+}
+#endif /* SYS_WINNT */
+
+
+/*
+ * init_alarm - set up the timer interrupt
+ */
+static void
+init_alarm(void)
+{
+#ifndef SYS_WINNT
+# ifndef HAVE_TIMER_SETTIME
+ struct itimerval itimer;
+# else
+ struct itimerspec ntpdate_itimer;
+# endif
+#else
+ TIMECAPS tc;
+ UINT wTimerRes, wTimerID;
+# endif /* SYS_WINNT */
+#if defined SYS_CYGWIN32 || defined SYS_WINNT
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tkp;
+ DWORD dwUser = 0;
+#endif /* SYS_WINNT */
+
+ alarm_flag = 0;
+
+#ifndef SYS_WINNT
+# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
+ alarm_flag = 0;
+ /* this code was put in as setitimer() is non existant this us the
+ * POSIX "equivalents" setup - casey
+ */
+ /* ntpdate_timerid is global - so we can kill timer later */
+ if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
+# ifdef SYS_VXWORKS
+ ERROR
+# else
+ -1
+# endif
+ )
+ {
+ fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
+ return;
+ }
+
+ /* TIMER_HZ = (5)
+ * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
+ * seconds from now and they continue on every 1/TIMER_HZ seconds.
+ */
+ (void) signal_no_reset(SIGALRM, alarming);
+ ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
+ ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
+ ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
+ timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
+# else
+ /*
+ * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
+ * seconds from now and they continue on every 1/TIMER_HZ seconds.
+ */
+ (void) signal_no_reset(SIGALRM, alarming);
+ itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
+ itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
+ itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
+
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+# endif
+#if defined SYS_CYGWIN32
+ /*
+ * Get previleges needed for fiddling with the clock
+ */
+
+ /* get the current process token handle */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ msyslog(LOG_ERR, "OpenProcessToken failed: %m");
+ exit(1);
+ }
+ /* get the LUID for system-time privilege. */
+ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; /* one privilege to set */
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ /* get set-time privilege for this process. */
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
+ /* cannot test return value of AdjustTokenPrivileges. */
+ if (GetLastError() != ERROR_SUCCESS)
+ msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
+#endif
+#else /* SYS_WINNT */
+ _tzset();
+
+ /*
+ * Get previleges needed for fiddling with the clock
+ */
+
+ /* get the current process token handle */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ msyslog(LOG_ERR, "OpenProcessToken failed: %m");
+ exit(1);
+ }
+ /* get the LUID for system-time privilege. */
+ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; /* one privilege to set */
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ /* get set-time privilege for this process. */
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
+ /* cannot test return value of AdjustTokenPrivileges. */
+ if (GetLastError() != ERROR_SUCCESS)
+ msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
+
+ /*
+ * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
+ * Under Win/NT, expiry of timer interval leads to invocation
+ * of a callback function (on a different thread) rather than
+ * generating an alarm signal
+ */
+
+ /* determine max and min resolution supported */
+ if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
+ msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
+ exit(1);
+ }
+ wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
+ /* establish the minimum timer resolution that we'll use */
+ timeBeginPeriod(wTimerRes);
+
+ /* start the timer event */
+ wTimerID = timeSetEvent(
+ (UINT) (1000/TIMER_HZ), /* Delay */
+ wTimerRes, /* Resolution */
+ (LPTIMECALLBACK) alarming, /* Callback function */
+ (DWORD) dwUser, /* User data */
+ TIME_PERIODIC); /* Event type (periodic) */
+ if (wTimerID == 0) {
+ msyslog(LOG_ERR, "timeSetEvent failed: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+}
+
+
+
+
+/*
+ * We do asynchronous input using the SIGIO facility. A number of
+ * recvbuf buffers are preallocated for input. In the signal
+ * handler we poll to see if the socket is ready and read the
+ * packets from it into the recvbuf's along with a time stamp and
+ * an indication of the source host and the interface it was received
+ * through. This allows us to get as accurate receive time stamps
+ * as possible independent of other processing going on.
+ *
+ * We allocate a number of recvbufs equal to the number of servers
+ * plus 2. This should be plenty.
+ */
+
+
+/*
+ * init_io - initialize I/O data and open socket
+ */
+static void
+init_io(void)
+{
+ struct addrinfo *res, *ressave;
+ struct addrinfo hints;
+ char service[5];
+ int optval = 1;
+
+ /*
+ * Init buffer free list and stat counters
+ */
+ init_recvbuff(sys_numservers + 2);
+
+ /*
+ * Open the socket
+ */
+
+ strcpy(service, "ntp");
+
+ /*
+ * Init hints addrinfo structure
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ if(getaddrinfo(NULL, service, &hints, &res) != 0) {
+ msyslog(LOG_ERR, "getaddrinfo() failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ /* Remember the address of the addrinfo structure chain */
+ ressave = res;
+
+ /*
+ * For each structure returned, open and bind socket
+ */
+ for(nbsock = 0; (nbsock < MAX_AF) && res ; res = res->ai_next) {
+ /* create a datagram (UDP) socket */
+ if ((fd[nbsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
+ if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT ||
+ errno == EPFNOSUPPORT)
+ continue;
+ netsyslog(LOG_ERR, "socket() failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+ /* set socket to reuse address */
+ if (setsockopt(fd[nbsock], SOL_SOCKET, SO_REUSEADDR, (void*) &optval, sizeof(optval)) < 0) {
+ netsyslog(LOG_ERR, "setsockopt() SO_REUSEADDR failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#ifdef IPV6_V6ONLY
+ /* Restricts AF_INET6 socket to IPv6 communications (see RFC 2553bis-03) */
+ if (res->ai_family == AF_INET6)
+ if (setsockopt(fd[nbsock], IPPROTO_IPV6, IPV6_V6ONLY, (void*) &optval, sizeof(optval)) < 0) {
+ netsyslog(LOG_ERR, "setsockopt() IPV6_V6ONLY failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#endif
+
+ /* Remember the socket family in fd_family structure */
+ fd_family[nbsock] = res->ai_family;
+
+ /*
+ * bind the socket to the NTP port
+ */
+ if (!debug && !simple_query && !unpriv_port) {
+ if (bind(fd[nbsock], res->ai_addr, SOCKLEN(res->ai_addr)) < 0) {
+#ifndef SYS_WINNT
+ if (errno == EADDRINUSE)
+#else
+ if (WSAGetLastError() == WSAEADDRINUSE)
+#endif /* SYS_WINNT */
+ netsyslog(LOG_ERR,
+ "the NTP socket is in use, exiting");
+ else
+ netsyslog(LOG_ERR, "bind() fails: %m");
+ exit(1);
+ }
+ }
+
+#ifdef HAVE_POLL_H
+ fdmask[nbsock].fd = fd[nbsock];
+ fdmask[nbsock].events = POLLIN;
+#else
+ FD_SET(fd[nbsock], &fdmask);
+ if ((SOCKET) maxfd < fd[nbsock]+1) {
+ maxfd = fd[nbsock]+1;
+ }
+#endif
+
+ /*
+ * set non-blocking,
+ */
+#ifndef SYS_WINNT
+# ifdef SYS_VXWORKS
+ {
+ int on = TRUE;
+
+ if (ioctl(fd[nbsock],FIONBIO, &on) == ERROR) {
+ netsyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
+ exit(1);
+ }
+ }
+# else /* not SYS_VXWORKS */
+# if defined(O_NONBLOCK)
+ if (fcntl(fd[nbsock], F_SETFL, O_NONBLOCK) < 0) {
+ netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+# else /* not O_NONBLOCK */
+# if defined(FNDELAY)
+ if (fcntl(fd[nbsock], F_SETFL, FNDELAY) < 0) {
+ netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+# else /* FNDELAY */
+# include "Bletch: Need non blocking I/O"
+# endif /* FNDELAY */
+# endif /* not O_NONBLOCK */
+# endif /* SYS_VXWORKS */
+#else /* SYS_WINNT */
+ if (ioctlsocket(fd[nbsock], FIONBIO, (u_long *) &on) == SOCKET_ERROR) {
+ netsyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+ nbsock++;
+ }
+ freeaddrinfo(ressave);
+}
+
+/*
+ * sendpkt - send a packet to the specified destination
+ */
+static void
+sendpkt(
+ struct sockaddr_storage *dest,
+ struct pkt *pkt,
+ int len
+ )
+{
+ int i;
+ int cc;
+ SOCKET sock = 0;
+
+#ifdef SYS_WINNT
+ DWORD err;
+#endif /* SYS_WINNT */
+
+ /* Find a local family compatible socket to send ntp packet to ntp server */
+ for(i = 0; (i < MAX_AF); i++) {
+ if(dest->ss_family == fd_family[i]) {
+ sock = fd[i];
+ break;
+ }
+ }
+
+ if ( sock == 0 ) {
+ netsyslog(LOG_ERR, "cannot find family compatible socket to send ntp packet");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ cc = sendto(sock, (char *)pkt, len, 0, (struct sockaddr *)dest,
+ SOCKLEN(dest));
+
+#ifndef SYS_WINNT
+ if (cc == -1) {
+ if (errno != EWOULDBLOCK && errno != ENOBUFS)
+#else
+ if (cc == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
+#endif /* SYS_WINNT */
+ netsyslog(LOG_ERR, "sendto(%s): %m", stohost(dest));
+ }
+}
+
+
+/*
+ * input_handler - receive packets asynchronously
+ */
+void
+input_handler(void)
+{
+ register int n;
+ register struct recvbuf *rb;
+ struct timeval tvzero;
+ int fromlen;
+ l_fp ts;
+ int i;
+#ifdef HAVE_POLL_H
+ struct pollfd fds[MAX_AF];
+#else
+ fd_set fds;
+#endif
+ int fdc = 0;
+
+ /*
+ * Do a poll to see if we have data
+ */
+ for (;;) {
+ tvzero.tv_sec = tvzero.tv_usec = 0;
+#ifdef HAVE_POLL_H
+ memcpy(fds, fdmask, sizeof(fdmask));
+ n = poll(fds, (unsigned int)nbsock, tvzero.tv_sec * 1000);
+
+ /*
+ * Determine which socket received data
+ */
+
+ for(i=0; i < nbsock; i++) {
+ if(fds[i].revents & POLLIN) {
+ fdc = fd[i];
+ break;
+ }
+ }
+
+#else
+ fds = fdmask;
+ n = select(maxfd, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
+
+ /*
+ * Determine which socket received data
+ */
+
+ for(i=0; i < maxfd; i++) {
+ if(FD_ISSET(fd[i], &fds)) {
+ fdc = fd[i];
+ break;
+ }
+ }
+
+#endif
+
+ /*
+ * If nothing to do, just return. If an error occurred,
+ * complain and return. If we've got some, freeze a
+ * timestamp.
+ */
+ if (n == 0)
+ return;
+ else if (n == -1) {
+ if (errno != EINTR)
+ netsyslog(LOG_ERR,
+#ifdef HAVE_POLL_H
+ "poll() error: %m"
+#else
+ "select() error: %m"
+#endif
+ );
+ return;
+ }
+ get_systime(&ts);
+
+ /*
+ * Get a buffer and read the frame. If we
+ * haven't got a buffer, or this is received
+ * on the wild card socket, just dump the packet.
+ */
+ if (initializing || free_recvbuffs() == 0) {
+ char buf[100];
+
+
+#ifndef SYS_WINNT
+ (void) read(fdc, buf, sizeof buf);
+#else
+ /* NT's _read does not operate on nonblocking sockets
+ * either recvfrom or ReadFile() has to be used here.
+ * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
+ * just to be different use recvfrom() here
+ */
+ recvfrom(fdc, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
+#endif /* SYS_WINNT */
+ continue;
+ }
+
+ rb = get_free_recv_buffer();
+
+ fromlen = sizeof(struct sockaddr_storage);
+ rb->recv_length = recvfrom(fdc, (char *)&rb->recv_pkt,
+ sizeof(rb->recv_pkt), 0,
+ (struct sockaddr *)&rb->recv_srcadr, &fromlen);
+ if (rb->recv_length == -1) {
+ freerecvbuf(rb);
+ continue;
+ }
+
+ /*
+ * Got one. Mark how and when it got here,
+ * put it on the full list.
+ */
+ rb->recv_time = ts;
+ add_full_recv_buffer(rb);
+ }
+}
+
+
+#if !defined SYS_WINNT && !defined SYS_CYGWIN32
+/*
+ * adj_systime - do a big long slew of the system time
+ */
+static int
+l_adj_systime(
+ l_fp *ts
+ )
+{
+ struct timeval adjtv, oadjtv;
+ int isneg = 0;
+ l_fp offset;
+#ifndef STEP_SLEW
+ l_fp overshoot;
+#endif
+
+ /*
+ * Take the absolute value of the offset
+ */
+ offset = *ts;
+ if (L_ISNEG(&offset)) {
+ isneg = 1;
+ L_NEG(&offset);
+ }
+
+#ifndef STEP_SLEW
+ /*
+ * Calculate the overshoot. XXX N.B. This code *knows*
+ * ADJ_OVERSHOOT is 1/2.
+ */
+ overshoot = offset;
+ L_RSHIFTU(&overshoot);
+ if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) {
+ overshoot.l_ui = 0;
+ overshoot.l_uf = ADJ_MAXOVERSHOOT;
+ }
+ L_ADD(&offset, &overshoot);
+#endif
+ TSTOTV(&offset, &adjtv);
+
+ if (isneg) {
+ adjtv.tv_sec = -adjtv.tv_sec;
+ adjtv.tv_usec = -adjtv.tv_usec;
+ }
+
+ if (adjtv.tv_usec != 0 && !debug) {
+ if (adjtime(&adjtv, &oadjtv) < 0) {
+ msyslog(LOG_ERR, "Can't adjust the time of day: %m");
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif /* SYS_WINNT */
+
+
+/*
+ * This fuction is not the same as lib/systime step_systime!!!
+ */
+static int
+l_step_systime(
+ l_fp *ts
+ )
+{
+ double dtemp;
+
+#ifdef SLEWALWAYS
+#ifdef STEP_SLEW
+ l_fp ftmp;
+ int isneg;
+ int n;
+
+ if (debug) return 1;
+ /*
+ * Take the absolute value of the offset
+ */
+ ftmp = *ts;
+ if (L_ISNEG(&ftmp)) {
+ L_NEG(&ftmp);
+ isneg = 1;
+ } else
+ isneg = 0;
+
+ if (ftmp.l_ui >= 3) { /* Step it and slew - we might win */
+ LFPTOD(ts, dtemp);
+ n = step_systime(dtemp);
+ if (!n)
+ return n;
+ if (isneg)
+ ts->l_ui = ~0;
+ else
+ ts->l_ui = ~0;
+ }
+ /*
+ * Just add adjustment into the current offset. The update
+ * routine will take care of bringing the system clock into
+ * line.
+ */
+#endif
+ if (debug)
+ return 1;
+#ifdef FORCE_NTPDATE_STEP
+ LFPTOD(ts, dtemp);
+ return step_systime(dtemp);
+#else
+ l_adj_systime(ts);
+ return 1;
+#endif
+#else /* SLEWALWAYS */
+ if (debug)
+ return 1;
+ LFPTOD(ts, dtemp);
+ return step_systime(dtemp);
+#endif /* SLEWALWAYS */
+}
+
+
+/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
+/*
+ * printserver - print detail information for a server
+ */
+static void
+printserver(
+ register struct server *pp,
+ FILE *fp
+ )
+{
+ register int i;
+ char junk[5];
+ char *str;
+
+ if (!debug) {
+ (void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n",
+ stoa(&pp->srcadr), pp->stratum,
+ lfptoa(&pp->offset, 6), fptoa((s_fp)pp->delay, 5));
+ return;
+ }
+
+ (void) fprintf(fp, "server %s, port %d\n",
+ stoa(&pp->srcadr), ntohs(((struct sockaddr_in*)&(pp->srcadr))->sin_port));
+
+ (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
+ pp->stratum, pp->precision,
+ pp->leap & 0x2 ? '1' : '0',
+ pp->leap & 0x1 ? '1' : '0',
+ pp->trust);
+
+ if (pp->stratum == 1) {
+ junk[4] = 0;
+ memmove(junk, (char *)&pp->refid, 4);
+ str = junk;
+ } else {
+ str = stoa(&pp->srcadr);
+ }
+ (void) fprintf(fp,
+ "refid [%s], delay %s, dispersion %s\n",
+ str, fptoa((s_fp)pp->delay, 5),
+ ufptoa(pp->dispersion, 5));
+
+ (void) fprintf(fp, "transmitted %d, in filter %d\n",
+ pp->xmtcnt, pp->filter_nextpt);
+
+ (void) fprintf(fp, "reference time: %s\n",
+ prettydate(&pp->reftime));
+ (void) fprintf(fp, "originate timestamp: %s\n",
+ prettydate(&pp->org));
+ (void) fprintf(fp, "transmit timestamp: %s\n",
+ prettydate(&pp->xmt));
+
+ (void) fprintf(fp, "filter delay: ");
+ for (i = 0; i < NTP_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
+ if (i == (NTP_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "filter offset:");
+ for (i = 0; i < PEER_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
+ if (i == (PEER_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "delay %s, dispersion %s\n",
+ fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
+
+ (void) fprintf(fp, "offset %s\n\n",
+ lfptoa(&pp->offset, 6));
+}
+
+#if !defined(HAVE_VSPRINTF)
+int
+vsprintf(
+ char *str,
+ const char *fmt,
+ va_list ap
+ )
+{
+ FILE f;
+ int len;
+
+ f._flag = _IOWRT+_IOSTRG;
+ f._ptr = str;
+ f._cnt = 32767;
+ len = _doprnt(fmt, ap, &f);
+ *f._ptr = 0;
+ return (len);
+}
+#endif
+
+#if 0
+/* override function in library since SA_RESTART makes ALL syscalls restart */
+#ifdef SA_RESTART
+void
+signal_no_reset(
+ int sig,
+ void (*func)()
+ )
+{
+ int n;
+ struct sigaction vec;
+
+ vec.sa_handler = func;
+ sigemptyset(&vec.sa_mask);
+ vec.sa_flags = 0;
+
+ while (1)
+ {
+ n = sigaction(sig, &vec, NULL);
+ if (n == -1 && errno == EINTR)
+ continue;
+ break;
+ }
+ if (n == -1)
+ {
+ perror("sigaction");
+ exit(1);
+ }
+}
+#endif
+#endif
+
+#ifdef HAVE_NETINFO
+static ni_namelist *
+getnetinfoservers(void)
+{
+ ni_status status;
+ void *domain;
+ ni_id confdir;
+ ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist));
+
+ /* Find a time server in NetInfo */
+ if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL;
+
+ while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) {
+ void *next_domain;
+ if (ni_open(domain, "..", &next_domain) != NI_OK) break;
+ ni_free(domain);
+ domain = next_domain;
+ }
+ if (status != NI_OK) return NULL;
+
+ NI_INIT(namelist);
+ if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) {
+ ni_namelist_free(namelist);
+ free(namelist);
+ return NULL;
+ }
+
+ return(namelist);
+}
+#endif
diff --git a/ntpdate/ntpdate.h b/ntpdate/ntpdate.h
new file mode 100644
index 0000000..f3531b3
--- /dev/null
+++ b/ntpdate/ntpdate.h
@@ -0,0 +1,104 @@
+/*
+ * ntpdate.h - declarations for the ntpdate and ntptimeset programs
+ */
+
+#include "ntp_malloc.h"
+
+extern void loadservers P((char *cfgpath));
+
+/*
+ * The server structure is a much simplified version of the
+ * peer structure, for ntpdate's use. Since we always send
+ * in client mode and expect to receive in server mode, this
+ * leaves only a very limited number of things we need to
+ * remember about the server.
+ */
+struct server {
+ struct server *next_server; /* next server in build list */
+ struct sockaddr_storage srcadr; /* address of remote host */
+ u_char version; /* version to use */
+ u_char leap; /* leap indicator */
+ u_char stratum; /* stratum of remote server */
+ s_char precision; /* server's clock precision */
+ u_char trust; /* trustability of the filtered data */
+ u_fp rootdelay; /* distance from primary clock */
+ u_fp rootdispersion; /* peer clock dispersion */
+ u_int32 refid; /* peer reference ID */
+ l_fp reftime; /* time of peer's last update */
+ u_long event_time; /* time for next timeout */
+ u_long last_xmit; /* time of last transmit */
+ u_short xmtcnt; /* number of packets transmitted */
+ u_short rcvcnt; /* number of packets received */
+ u_char reach; /* reachability, NTP_WINDOW bits */
+ u_short filter_nextpt; /* index into filter shift register */
+ s_fp filter_delay[NTP_SHIFT]; /* delay part of shift register */
+ l_fp filter_offset[NTP_SHIFT]; /* offset part of shift register */
+ s_fp filter_soffset[NTP_SHIFT]; /* offset in s_fp format, for disp */
+ u_fp filter_error[NTP_SHIFT]; /* error part of shift register */
+ l_fp org; /* peer's originate time stamp */
+ l_fp xmt; /* transmit time stamp */
+ u_fp delay; /* filter estimated delay */
+ u_fp dispersion; /* filter estimated dispersion */
+ l_fp offset; /* filter estimated clock offset */
+ s_fp soffset; /* fp version of above */
+};
+
+
+/*
+ * ntpdate runs everything on a simple, short timeout. It sends a
+ * packet and sets the timeout (by default, to a small value suitable
+ * for a LAN). If it receives a response it sends another request.
+ * If it times out it shifts zeroes into the filter and sends another
+ * request.
+ *
+ * The timer routine is run often (once every 1/5 second currently)
+ * so that time outs are done with reasonable precision.
+ */
+#define TIMER_HZ (5) /* 5 per second */
+
+/*
+ * ntpdate will make a long adjustment using adjtime() if the times
+ * are close, or step the time if the times are farther apart. The
+ * following defines what is "close".
+ */
+#define NTPDATE_THRESHOLD (FP_SECOND >> 1) /* 1/2 second */
+
+#define NTP_MAXAGE 86400 /* one day in seconds */
+
+/*
+ * When doing adjustments, ntpdate actually overadjusts (currently
+ * by 50%, though this may change). While this will make it take longer
+ * to reach a steady state condition, it will typically result in
+ * the clock keeping more accurate time, on average. The amount of
+ * overshoot is limited.
+ */
+#ifdef NOTNOW
+#define ADJ_OVERSHOOT 1/2 /* this is hard coded */
+#endif /* NOTNOW */
+#define ADJ_MAXOVERSHOOT 0x10000000 /* 50 ms as a ts fraction */
+
+/*
+ * Since ntpdate isn't aware of some of the things that normally get
+ * put in an NTP packet, we fix some values.
+ */
+#define NTPDATE_PRECISION (-6) /* use this precision */
+#define NTPDATE_DISTANCE FP_SECOND /* distance is 1 sec */
+#define NTPDATE_DISP FP_SECOND /* so is the dispersion */
+#define NTPDATE_REFID (0) /* reference ID to use */
+#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */
+
+
+/*
+ * Some defaults
+ */
+#define DEFTIMEOUT 5 /* 5 timer increments */
+#define DEFSAMPLES 4 /* get 4 samples per server */
+#define DEFPRECISION (-5) /* the precision we claim */
+#define DEFMAXPERIOD 60 /* maximum time to wait */
+#define DEFMINSERVERS 3 /* minimum responding servers */
+#define DEFMINVALID 1 /* mimimum servers with valid time */
+
+/*
+ * Define the max number of sockets we can open
+ */
+#define MAX_AF 2
diff --git a/ntpdate/ntptime_config.c b/ntpdate/ntptime_config.c
new file mode 100644
index 0000000..e784d28
--- /dev/null
+++ b/ntpdate/ntptime_config.c
@@ -0,0 +1,552 @@
+/*
+ * ntptime_config.c
+ *
+ * What follows is a simplified version of the config parsing code
+ * in ntpd/ntp_config.c. We only parse a subset of the configuration
+ * syntax, and don't bother whining about things we don't understand.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_filegen.h"
+#include "ntpdate.h"
+#include "ntp_syslog.h"
+#include "ntp_stdlib.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+
+/*
+ * These routines are used to read the configuration file at
+ * startup time. An entry in the file must fit on a single line.
+ * Entries are processed as multiple tokens separated by white space
+ * Lines are considered terminated when a '#' is encountered. Blank
+ * lines are ignored.
+ */
+
+/*
+ * Configuration file name
+ */
+#ifndef CONFIG_FILE
+# ifndef SYS_WINNT
+# define CONFIG_FILE "/etc/ntp.conf"
+# else /* SYS_WINNT */
+# define CONFIG_FILE "%windir%\\ntp.conf"
+# define ALT_CONFIG_FILE "%windir%\\ntp.ini"
+# endif /* SYS_WINNT */
+#endif /* not CONFIG_FILE */
+
+/*
+ *
+ * We understand the following configuration entries and defaults.
+ *
+ * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * keys file_name
+ */
+
+#define CONFIG_UNKNOWN 0
+
+#define CONFIG_PEER 1
+#define CONFIG_SERVER 2
+#define CONFIG_KEYS 8
+
+#define CONF_MOD_VERSION 1
+#define CONF_MOD_KEY 2
+#define CONF_MOD_MINPOLL 3
+#define CONF_MOD_MAXPOLL 4
+#define CONF_MOD_PREFER 5
+#define CONF_MOD_BURST 6
+#define CONF_MOD_SKEY 7
+#define CONF_MOD_TTL 8
+#define CONF_MOD_MODE 9
+
+/*
+ * Translation table - keywords to function index
+ */
+struct keyword {
+ const char *text;
+ int keytype;
+};
+
+/*
+ * Command keywords
+ */
+static struct keyword keywords[] = {
+ { "peer", CONFIG_PEER },
+ { "server", CONFIG_SERVER },
+ { "keys", CONFIG_KEYS },
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * "peer", "server", "broadcast" modifier keywords
+ */
+static struct keyword mod_keywords[] = {
+ { "version", CONF_MOD_VERSION },
+ { "key", CONF_MOD_KEY },
+ { "minpoll", CONF_MOD_MINPOLL },
+ { "maxpoll", CONF_MOD_MAXPOLL },
+ { "prefer", CONF_MOD_PREFER },
+ { "burst", CONF_MOD_BURST },
+ { "autokey", CONF_MOD_SKEY },
+ { "mode", CONF_MOD_MODE }, /* reference clocks */
+ { "ttl", CONF_MOD_TTL }, /* NTP peers */
+ { "", CONFIG_UNKNOWN }
+};
+
+/*
+ * Limits on things
+ */
+#define MAXTOKENS 20 /* 20 tokens on line */
+#define MAXLINE 1024 /* maximum length of line */
+#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */
+
+/*
+ * Miscellaneous macros
+ */
+#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
+#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0')
+#define ISSPACE(c) ((c) == ' ' || (c) == '\t')
+#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+/*
+ * Systemwide parameters and flags
+ */
+extern struct server **sys_servers; /* the server list */
+extern int sys_numservers; /* number of servers to poll */
+extern char *key_file;
+
+/*
+ * Function prototypes
+ */
+static int gettokens P((FILE *, char *, char **, int *));
+static int matchkey P((char *, struct keyword *));
+static int getnetnum P((const char *num, struct sockaddr_in *addr,
+ int complain));
+
+
+/*
+ * loadservers - load list of NTP servers from configuration file
+ */
+void
+loadservers(
+ char *cfgpath
+ )
+{
+ register int i;
+ int errflg;
+ int peerversion;
+ int minpoll;
+ int maxpoll;
+ /* int ttl; */
+ int srvcnt;
+ /* u_long peerkey; */
+ int peerflags;
+ struct sockaddr_in peeraddr;
+ FILE *fp;
+ char line[MAXLINE];
+ char *(tokens[MAXTOKENS]);
+ int ntokens;
+ int tok;
+ const char *config_file;
+#ifdef SYS_WINNT
+ char *alt_config_file;
+ LPTSTR temp;
+ char config_file_storage[MAX_PATH];
+ char alt_config_file_storage[MAX_PATH];
+#endif /* SYS_WINNT */
+ struct server *server, *srvlist;
+
+ /*
+ * Initialize, initialize
+ */
+ srvcnt = 0;
+ srvlist = 0;
+ errflg = 0;
+#ifdef DEBUG
+ debug = 0;
+#endif /* DEBUG */
+#ifndef SYS_WINNT
+ config_file = cfgpath ? cfgpath : CONFIG_FILE;
+#else
+ if (cfgpath) {
+ config_file = cfgpath;
+ } else {
+ temp = CONFIG_FILE;
+ if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n");
+ exit(1);
+ }
+ config_file = config_file_storage;
+ }
+
+ temp = ALT_CONFIG_FILE;
+ if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n");
+ exit(1);
+ }
+ alt_config_file = alt_config_file_storage;
+M
+#endif /* SYS_WINNT */
+
+ if ((fp = fopen(FindConfig(config_file), "r")) == NULL)
+ {
+ fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file));
+ msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file));
+#ifdef SYS_WINNT
+ /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */
+
+ if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) {
+
+ /*
+ * Broadcast clients can sometimes run without
+ * a configuration file.
+ */
+
+ fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file));
+ msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file));
+ return;
+ }
+#else /* not SYS_WINNT */
+ return;
+#endif /* not SYS_WINNT */
+ }
+
+ while ((tok = gettokens(fp, line, tokens, &ntokens))
+ != CONFIG_UNKNOWN) {
+ switch(tok) {
+ case CONFIG_PEER:
+ case CONFIG_SERVER:
+
+ if (ntokens < 2) {
+ msyslog(LOG_ERR,
+ "No address for %s, line ignored",
+ tokens[0]);
+ break;
+ }
+
+ if (!getnetnum(tokens[1], &peeraddr, 1)) {
+ /* Resolve now, or lose! */
+ break;
+ } else {
+ errflg = 0;
+
+ /* Shouldn't be able to specify multicast */
+ if (IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr))
+ || ISBADADR(&peeraddr)) {
+ msyslog(LOG_ERR,
+ "attempt to configure invalid address %s",
+ ntoa(&peeraddr));
+ break;
+ }
+ }
+
+ peerversion = NTP_VERSION;
+ minpoll = NTP_MINDPOLL;
+ maxpoll = NTP_MAXDPOLL;
+ /* peerkey = 0; */
+ peerflags = 0;
+ /* ttl = 0; */
+ for (i = 2; i < ntokens; i++)
+ switch (matchkey(tokens[i], mod_keywords)) {
+ case CONF_MOD_VERSION:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "peer/server version requires an argument");
+ errflg = 1;
+ break;
+ }
+ peerversion = atoi(tokens[++i]);
+ if ((u_char)peerversion > NTP_VERSION
+ || (u_char)peerversion < NTP_OLDVERSION) {
+ msyslog(LOG_ERR,
+ "inappropriate version number %s, line ignored",
+ tokens[i]);
+ errflg = 1;
+ }
+ break;
+
+ case CONF_MOD_KEY:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "key: argument required");
+ errflg = 1;
+ break;
+ }
+ ++i;
+ /* peerkey = (int)atol(tokens[i]); */
+ peerflags |= FLAG_AUTHENABLE;
+ break;
+
+ case CONF_MOD_MINPOLL:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "minpoll: argument required");
+ errflg = 1;
+ break;
+ }
+ minpoll = atoi(tokens[++i]);
+ if (minpoll < NTP_MINPOLL)
+ minpoll = NTP_MINPOLL;
+ break;
+
+ case CONF_MOD_MAXPOLL:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "maxpoll: argument required"
+ );
+ errflg = 1;
+ break;
+ }
+ maxpoll = atoi(tokens[++i]);
+ if (maxpoll > NTP_MAXPOLL)
+ maxpoll = NTP_MAXPOLL;
+ break;
+
+ case CONF_MOD_PREFER:
+ peerflags |= FLAG_PREFER;
+ break;
+
+ case CONF_MOD_BURST:
+ peerflags |= FLAG_BURST;
+ break;
+
+ case CONF_MOD_SKEY:
+ peerflags |= FLAG_SKEY | FLAG_AUTHENABLE;
+ break;
+
+ case CONF_MOD_TTL:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "ttl: argument required");
+ errflg = 1;
+ break;
+ }
+ ++i;
+ /* ttl = atoi(tokens[i]); */
+ break;
+
+ case CONF_MOD_MODE:
+ if (i >= ntokens-1) {
+ msyslog(LOG_ERR,
+ "mode: argument required");
+ errflg = 1;
+ break;
+ }
+ ++i;
+ /* ttl = atoi(tokens[i]); */
+ break;
+
+ case CONFIG_UNKNOWN:
+ errflg = 1;
+ break;
+ }
+ if (minpoll > maxpoll) {
+ msyslog(LOG_ERR, "config error: minpoll > maxpoll");
+ errflg = 1;
+ }
+ if (errflg == 0) {
+ server = (struct server *)emalloc(sizeof(struct server));
+ memset((char *)server, 0, sizeof(struct server));
+ server->srcadr = peeraddr;
+ server->version = peerversion;
+ server->dispersion = PEER_MAXDISP;
+ server->next_server = srvlist;
+ srvlist = server;
+ srvcnt++;
+ }
+ break;
+
+ case CONFIG_KEYS:
+ if (ntokens >= 2) {
+ key_file = (char *) emalloc(strlen(tokens[1]) + 1);
+ strcpy(key_file, tokens[1]);
+ }
+ break;
+ }
+ }
+ (void) fclose(fp);
+
+ /* build final list */
+ sys_numservers = srvcnt;
+ sys_servers = (struct server **)
+ emalloc(sys_numservers * sizeof(struct server *));
+ for(i=0;i<sys_numservers;i++) {
+ sys_servers[i] = srvlist;
+ srvlist = srvlist->next_server;
+ }
+}
+
+
+
+/*
+ * gettokens - read a line and return tokens
+ */
+static int
+gettokens(
+ FILE *fp,
+ char *line,
+ char **tokenlist,
+ int *ntokens
+ )
+{
+ register char *cp;
+ register int eol;
+ register int ntok;
+ register int quoted = 0;
+
+ /*
+ * Find start of first token
+ */
+ again:
+ while ((cp = fgets(line, MAXLINE, fp)) != NULL) {
+ cp = line;
+ while (ISSPACE(*cp))
+ cp++;
+ if (!ISEOL(*cp))
+ break;
+ }
+ if (cp == NULL) {
+ *ntokens = 0;
+ return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */
+ }
+
+ /*
+ * Now separate out the tokens
+ */
+ eol = 0;
+ ntok = 0;
+ while (!eol) {
+ tokenlist[ntok++] = cp;
+ while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted))
+ quoted ^= (*cp++ == '"');
+
+ if (ISEOL(*cp)) {
+ *cp = '\0';
+ eol = 1;
+ } else { /* must be space */
+ *cp++ = '\0';
+ while (ISSPACE(*cp))
+ cp++;
+ if (ISEOL(*cp))
+ eol = 1;
+ }
+ if (ntok == MAXTOKENS)
+ eol = 1;
+ }
+
+ /*
+ * Return the match
+ */
+ *ntokens = ntok;
+ ntok = matchkey(tokenlist[0], keywords);
+ if (ntok == CONFIG_UNKNOWN)
+ goto again;
+ return ntok;
+}
+
+
+
+/*
+ * matchkey - match a keyword to a list
+ */
+static int
+matchkey(
+ register char *word,
+ register struct keyword *keys
+ )
+{
+ for (;;) {
+ if (keys->keytype == CONFIG_UNKNOWN) {
+ return CONFIG_UNKNOWN;
+ }
+ if (STRSAME(word, keys->text))
+ return keys->keytype;
+ keys++;
+ }
+}
+
+
+/*
+ * getnetnum - return a net number (this is crude, but careful)
+ */
+static int
+getnetnum(
+ const char *num,
+ struct sockaddr_in *addr,
+ int complain
+ )
+{
+ register const char *cp;
+ register char *bp;
+ register int i;
+ register int temp;
+ char buf[80]; /* will core dump on really stupid stuff */
+ u_int32 netnum;
+
+ /* XXX ELIMINATE replace with decodenetnum */
+ cp = num;
+ netnum = 0;
+ for (i = 0; i < 4; i++) {
+ bp = buf;
+ while (isdigit((int)*cp))
+ *bp++ = *cp++;
+ if (bp == buf)
+ break;
+
+ if (i < 3) {
+ if (*cp++ != '.')
+ break;
+ } else if (*cp != '\0')
+ break;
+
+ *bp = '\0';
+ temp = atoi(buf);
+ if (temp > 255)
+ break;
+ netnum <<= 8;
+ netnum += temp;
+#ifdef DEBUG
+ if (debug > 3)
+ printf("getnetnum %s step %d buf %s temp %d netnum %lu\n",
+ num, i, buf, temp, (u_long)netnum);
+#endif
+ }
+
+ if (i < 4) {
+ if (complain)
+ msyslog(LOG_ERR,
+ "getnetnum: \"%s\" invalid host number, line ignored",
+ num);
+#ifdef DEBUG
+ if (debug > 3)
+ printf(
+ "getnetnum: \"%s\" invalid host number, line ignored\n",
+ num);
+#endif
+ return 0;
+ }
+
+ /*
+ * make up socket address. Clear it out for neatness.
+ */
+ memset((void *)addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(NTP_PORT);
+ addr->sin_addr.s_addr = htonl(netnum);
+#ifdef DEBUG
+ if (debug > 1)
+ printf("getnetnum given %s, got %s (%lx)\n",
+ num, ntoa(addr), (u_long)netnum);
+#endif
+ return 1;
+}
diff --git a/ntpdate/ntptimeset.c b/ntpdate/ntptimeset.c
new file mode 100644
index 0000000..6d9332f
--- /dev/null
+++ b/ntpdate/ntptimeset.c
@@ -0,0 +1,2171 @@
+/*
+ * ntptimeset - get/set the time via ntp
+ *
+ * GOAL:
+ * The goal of ntptime is to set the current time on system startup
+ * to the best possible time using the network very wisely. It is assumed
+ * that after a resonable time has been sett then ntp daemon will
+ * maintain it.
+ *
+ * PROBLEM DOMAIN:
+ * We have three sets of issues related to acheiving the goal. The first
+ * issue is using the network when normal traffic is happening or when
+ * the entire network world is recovering from a campus wide power failure
+ * and is restarting. The second issue is the class of machine whether it
+ * is a user's office workstation being handled by an uneducated user or
+ * a server computer being handled by a trained operations staff. The third
+ * issue is whether the ratio of people to computers and whether the
+ * environment is stable and viable or not.
+ *
+ * NETWORK USAGE:
+ * The first issue of using the network wisely is a question of whether
+ * the network load and time server load and state are normal. If things
+ * are normal ntptime can do what ntpdate does of sending out 4 packets
+ * quickly to each server (new transmit done with each ack). However
+ * if network or time load is high then this scheme will simply contribute
+ * to problems. Given we have minimal state, we simply weight lost packets
+ * significantly and make sure we throttle output as much as possible
+ * without performance lost for quick startups.
+ *
+ * TRAINING AND KNOWLEDGE:
+ * The second issue of uneducated user of a office workstation versus a
+ * trained operation staff of a server machine translates into simply an
+ * issue of untrained and trained users.
+ *
+ * The training issue implies that for the sake of the users involved in the
+ * handling of their office workstation, problems and options should be
+ * communicated simply and effectively and not in terse expert related
+ * descriptions without possible options to be taken. The operator's training
+ * and education enables them to deal with either type of communication and
+ * control.
+ *
+ * AUTOMATION AND MANUAL CONTROL:
+ * The last issue boils down to a design problem. If the design tends to go
+ * into a manual mode when the environment is non-viable then one person
+ * handling many computers all at the same time will be heavily impacted. On
+ * the other hand, if the design tends to be automatic and does not indicate
+ * a way for the user to take over control then the computer will be
+ * unavailable for the user until the proble is resolved by someone else or
+ * the user.
+ *
+ * NOTE: Please do not have this program print out every minute some line,
+ * of output. If this happens and the environment is in trouble then
+ * many pages of paper on many different machines will be filled up.
+ * Save some tress in your lifetime.
+ *
+ * CONCLUSION:
+ * The behavior of the program derived from these three issues should be
+ * that during normal situations it quickly sets the time and allow the
+ * system to startup.
+ *
+ * However during abnormal conditions as detected by unresponsive servers,
+ * out-of-sync or bad responses and other detections, it should print out
+ * a simple but clear message and continue in a mellow way to get the best
+ * possible time. It may never get the time and if so should also indicate
+ * this.
+ *
+ * Rudy Nedved
+ * 18-May-1993
+ *
+ ****************************************************************
+ *
+ * Much of the above is confusing or no longer relevant. For example,
+ * it is rare these days for a machine's console to be a printing terminal,
+ * so the comment about saving trees doesn't mean much. Nonetheless,
+ * the basic principles still stand:
+ *
+ * - Work automatically, without human control or intervention. To
+ * this end, we use the same configuration file as ntpd itself, so
+ * you don't have to specify servers or other information on the
+ * command line. We also recognize that sometimes we won't be able
+ * to contact any servers, and give up in that event instead of
+ * hanging forever.
+ *
+ * - Behave in a sane way, both internally and externally, even in the
+ * face of insane conditions. That means we back off quickly when
+ * we don't hear a response, to avoid network congestion. Like
+ * ntpd, we verify responses from several servers before accepting
+ * the new time data.
+ *
+ * However, we don't assume that the local clock is right, or even
+ * close, because it might not be at boot time, and we want to catch
+ * and correct that situation. This behaviour has saved us in several
+ * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which
+ * would cause the time to be set to some wild value, making the machine
+ * essentially unusable (we use Kerberos authentication pervasively,
+ * and it requires workstations and servers to have a time within five
+ * minutes of the Kerberos server). We also have problems on PC's
+ * running both Linux and some Microsoft OS -- they tend to disagree
+ * on what the BIOS clock should say, and who should update it, and
+ * when. On those systems, we not only run ntptimeset at boot, we
+ * also reset the BIOS clock based on the result, so the correct
+ * time will be retained across reboots.
+ *
+ * For these reasons, and others, we have continued to use this tool
+ * rather than ntpdate. It is run automatically at boot time on every
+ * workstation and server in our facility.
+ *
+ * In the past, we called this program 'ntptime'. Unfortunately, the
+ * ntp v4 distribution also includes a program with that name. In
+ * order to avoid confusion, we have renamed our program 'ntptimeset',
+ * which more accurately describes what it does.
+ *
+ * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu>
+ * School of Computer Science - Research Computing Facility
+ * Carnegie Mellon University - Pittsburgh, PA
+ * 16-Aug-1999
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "ntp_machine.h"
+#include "ntp_fp.h"
+#include "ntp.h"
+#include "ntp_io.h"
+#include "iosignal.h"
+#include "ntp_unixtime.h"
+#include "ntpdate.h"
+#include "ntp_string.h"
+#include "ntp_syslog.h"
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#ifndef SYS_WINNT
+# include <netdb.h>
+# ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+# else
+# include <signal.h>
+# endif
+# include <sys/ioctl.h>
+#endif /* SYS_WINNT */
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#ifdef SYS_VXWORKS
+# include "ioLib.h"
+# include "sockLib.h"
+# include "timers.h"
+#endif
+
+#include "recvbuff.h"
+
+#ifdef SYS_WINNT
+# define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy
+ on Windows NT timers. */
+#pragma comment(lib, "winmm")
+#endif /* SYS_WINNT */
+
+/*
+ * Scheduling priority we run at
+ */
+#ifndef SYS_VXWORKS
+# define NTPDATE_PRIO (-12)
+#else
+# define NTPDATE_PRIO (100)
+#endif
+
+#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
+/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
+static timer_t ntpdate_timerid;
+#endif
+
+/*
+ * Compatibility stuff for Version 2
+ */
+#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */
+#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */
+#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */
+#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */
+#define NTP_MAXLIST 5 /* maximum select list size */
+#define PEER_SHIFT 8 /* 8 suitable for crystal time base */
+
+/*
+ * Debugging flag
+ */
+volatile int debug = 0;
+
+/*
+ * File descriptor masks etc. for call to select
+ */
+int fd;
+fd_set fdmask;
+
+/*
+ * Initializing flag. All async routines watch this and only do their
+ * thing when it is clear.
+ */
+int initializing = 1;
+
+/*
+ * Alarm flag. Set when an alarm occurs
+ */
+volatile int alarm_flag = 0;
+
+/*
+ * Set the time if valid time determined
+ */
+int set_time = 0;
+
+/*
+ * transmission rate control
+ */
+#define MINTRANSMITS (3) /* minimum total packets per server */
+#define MAXXMITCOUNT (2) /* maximum packets per time interrupt */
+
+/*
+ * time setting constraints
+ */
+#define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */
+int max_period = DEFMAXPERIOD;
+int min_servers = DEFMINSERVERS;
+int min_valid = DEFMINVALID;
+
+/*
+ * counters related to time setting constraints
+ */
+int contacted = 0; /* # of servers we have sent to */
+int responding = 0; /* servers responding */
+int validcount = 0; /* servers with valid time */
+int valid_n_low = 0; /* valid time servers with low dispersion */
+
+/*
+ * Unpriviledged port flag.
+ */
+int unpriv_port = 0;
+
+/*
+ * Program name.
+ */
+char *progname;
+
+/*
+ * Systemwide parameters and flags
+ */
+struct server **sys_servers; /* the server list */
+int sys_numservers = 0; /* number of servers to poll */
+int sys_authenticate = 0; /* true when authenticating */
+u_int32 sys_authkey = 0; /* set to authentication key in use */
+u_long sys_authdelay = 0; /* authentication delay */
+
+/*
+ * The current internal time
+ */
+u_long current_time = 0;
+
+/*
+ * File of encryption keys
+ */
+
+#ifndef KEYFILE
+# ifndef SYS_WINNT
+#define KEYFILE "/etc/ntp.keys"
+# else
+#define KEYFILE "%windir%\\ntp.keys"
+# endif /* SYS_WINNT */
+#endif /* KEYFILE */
+
+#ifndef SYS_WINNT
+const char *key_file = KEYFILE;
+#else
+char key_file_storage[MAX_PATH+1], *key_file ;
+#endif /* SYS_WINNT */
+
+/*
+ * total packet counts
+ */
+u_long total_xmit = 0;
+u_long total_recv = 0;
+
+/*
+ * Miscellaneous flags
+ */
+int verbose = 0;
+#define HORRIBLEOK 3 /* how many packets to let out */
+int horrible = 0; /* how many packets we drop for testing */
+int secondhalf = 0; /* second half of timeout period */
+int printmsg = 0; /* print time response analysis */
+
+/*
+ * The half time and finish time in internal time
+ */
+u_long half_time = 0;
+u_long finish_time = 0;
+
+
+int ntptimesetmain P((int argc, char *argv[]));
+static void analysis P((int final));
+static int have_enough P((void));
+static void transmit P((register struct server *server));
+static void receive P((struct recvbuf *rbufp));
+static void clock_filter P((register struct server *server, s_fp d, l_fp *c));
+static void clock_count P((void));
+static struct server *clock_select P((void));
+static void set_local_clock P((void));
+static struct server *findserver P((struct sockaddr_in *addr));
+static void timer P((void));
+#ifndef SYS_WINNT
+static RETSIGTYPE alarming P((int sig));
+#endif /* SYS_WINNT */
+static void init_alarm P((void));
+static void init_io P((void));
+static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len));
+ void input_handler P((l_fp *xts));
+static void printserver P((register struct server *pp, FILE *fp));
+#if !defined(HAVE_VSPRINTF)
+int vsprintf P((char *str, const char *fmt, va_list ap));
+#endif
+
+#ifdef HAVE_SIGNALED_IO
+extern void wait_for_signal P((void));
+extern void unblock_io_and_alarm P((void));
+extern void block_io_and_alarm P((void));
+#endif
+
+
+#ifdef NO_MAIN_ALLOWED
+CALL(ntptimeset,"ntptimeset",ntptimesetmain);
+
+void clear_globals()
+{
+ /*
+ * Debugging flag
+ */
+ debug = 0;
+
+ ntp_optind = 0;
+
+ /*
+ * Initializing flag. All async routines watch this and only do their
+ * thing when it is clear.
+ */
+ initializing = 1;
+
+ /*
+ * Alarm flag. Set when an alarm occurs
+ */
+ alarm_flag = 0;
+
+ /*
+ * Unpriviledged port flag.
+ */
+ unpriv_port = 0;
+
+ /*
+ * Systemwide parameters and flags
+ */
+ sys_numservers = 0; /* number of servers to poll */
+ sys_authenticate = 0; /* true when authenticating */
+ sys_authkey = 0; /* set to authentication key in use */
+ sys_authdelay = 0; /* authentication delay */
+
+ /*
+ * The current internal time
+ */
+ current_time = 0;
+
+ verbose = 0;
+}
+#endif /* NO_MAIN_ALLOWED */
+
+/*
+ * Main program. Initialize us and loop waiting for I/O and/or
+ * timer expiries.
+ */
+#ifndef NO_MAIN_ALLOWED
+int
+main(
+ int argc,
+ char *argv[]
+ )
+{
+ return ntptimesetmain(argc, argv);
+}
+#endif /* NO_MAIN_ALLOWED */
+
+
+int
+ntptimesetmain(
+ int argc,
+ char *argv[]
+ )
+{
+ int was_alarmed;
+ struct recvbuf *rbuflist;
+ struct recvbuf *rbuf;
+ l_fp tmp;
+ int errflg;
+ int c;
+ extern char *ntp_optarg;
+ extern int ntp_optind;
+ int ltmp;
+ char *cfgpath;
+
+#ifdef SYS_WINNT
+ HANDLE process_handle;
+
+ wVersionRequested = MAKEWORD(1,1);
+ if (WSAStartup(wVersionRequested, &wsaData)) {
+ msyslog(LOG_ERR, "No useable winsock.dll: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+
+#ifdef NO_MAIN_ALLOWED
+ clear_globals();
+#endif
+
+ errflg = 0;
+ cfgpath = 0;
+ progname = argv[0];
+ syslogit = 0;
+
+ /*
+ * Decode argument list
+ */
+ while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF)
+ switch (c)
+ {
+ case 'a':
+ c = atoi(ntp_optarg);
+ sys_authenticate = 1;
+ sys_authkey = c;
+ break;
+ case 'c':
+ cfgpath = ntp_optarg;
+ break;
+ case 'd':
+ ++debug;
+ break;
+ case 'e':
+ if (!atolfp(ntp_optarg, &tmp)
+ || tmp.l_ui != 0) {
+ (void) fprintf(stderr,
+ "%s: encryption delay %s is unlikely\n",
+ progname, ntp_optarg);
+ errflg++;
+ } else {
+ sys_authdelay = tmp.l_uf;
+ }
+ break;
+ case 's':
+ set_time = 1;
+ break;
+ case 'l':
+ syslogit = 1;
+ break;
+ case 't':
+ ltmp = atoi(ntp_optarg);
+ if (ltmp <= 0) {
+ (void) fprintf(stderr,
+ "%s: maximum time period (%d) is invalid\n",
+ progname, ltmp);
+ errflg++;
+ }
+ else
+ max_period = ltmp;
+ break;
+ case 'u':
+ unpriv_port = 1;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'H':
+ horrible++;
+ break;
+ case 'S':
+ ltmp = atoi(ntp_optarg);
+ if (ltmp <= 0) {
+ (void) fprintf(stderr,
+ "%s: minimum responding (%d) is invalid\n",
+ progname, ltmp);
+ errflg++;
+ }
+ else
+ min_servers = ltmp;
+ break;
+ case 'V':
+ ltmp = atoi(ntp_optarg);
+ if (ltmp <= 0) {
+ (void) fprintf(stderr,
+ "%s: minimum valid (%d) is invalid\n",
+ progname, ltmp);
+ errflg++;
+ }
+ else
+ min_valid = ltmp;
+ break;
+ case '?':
+ ++errflg;
+ break;
+ default:
+ break;
+ }
+
+
+ if (errflg || ntp_optind < argc) {
+ fprintf(stderr,"usage: %s [switches...]\n",progname);
+ fprintf(stderr," -v (verbose)\n");
+ fprintf(stderr," -c path (set config file path)\n");
+ fprintf(stderr," -a key (authenticate using key)\n");
+ fprintf(stderr," -e delay (authentication delay)\n");
+ fprintf(stderr," -S num (# of servers that must respond)\n");
+ fprintf(stderr," -V num (# of servers that must valid)\n");
+ fprintf(stderr," -s (set the time based if okay)\n");
+ fprintf(stderr," -t secs (time period before ending)\n");
+ fprintf(stderr," -l (use syslog facility)\n");
+ fprintf(stderr," -u (use unprivileged port)\n");
+ fprintf(stderr," -H (drop packets for debugging)\n");
+ fprintf(stderr," -d (debug output)\n");
+ exit(2);
+ }
+
+ /*
+ * Logging. Open the syslog if we have to
+ */
+ if (syslogit) {
+#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
+# ifndef LOG_DAEMON
+ openlog("ntptimeset", LOG_PID);
+# else
+
+# ifndef LOG_NTP
+# define LOG_NTP LOG_DAEMON
+# endif
+ openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP);
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ else
+ setlogmask(LOG_UPTO(LOG_INFO));
+# endif /* LOG_DAEMON */
+#endif /* SYS_WINNT */
+ }
+
+ if (debug || verbose)
+ msyslog(LOG_INFO, "%s", Version);
+
+ if (horrible)
+ msyslog(LOG_INFO, "Dropping %d out of %d packets",
+ horrible,horrible+HORRIBLEOK);
+ /*
+ * Add servers we are going to be polling
+ */
+ loadservers(cfgpath);
+
+ if (sys_numservers < min_servers) {
+ msyslog(LOG_ERR, "Found %d servers, require %d servers",
+ sys_numservers,min_servers);
+ exit(2);
+ }
+
+ /*
+ * determine when we will end at least
+ */
+ finish_time = max_period * TIMER_HZ;
+ half_time = finish_time >> 1;
+
+ /*
+ * Initialize the time of day routines and the I/O subsystem
+ */
+ if (sys_authenticate) {
+ init_auth();
+#ifdef SYS_WINNT
+ if (!key_file) key_file = KEYFILE;
+ if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH))
+ {
+ msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n",
+ key_file);
+ } else {
+ key_file = key_file_storage;
+ }
+#endif /* SYS_WINNT */
+
+ if (!authreadkeys(key_file)) {
+ msyslog(LOG_ERR, "no key file, exiting");
+ exit(1);
+ }
+ if (!authistrusted(sys_authkey)) {
+ char buf[10];
+
+ (void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
+ msyslog(LOG_ERR, "authentication key %s unknown", buf);
+ exit(1);
+ }
+ }
+ init_io();
+ init_alarm();
+
+ /*
+ * Set the priority.
+ */
+#ifdef SYS_VXWORKS
+ taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
+#endif
+#if defined(HAVE_ATT_NICE)
+ nice (NTPDATE_PRIO);
+#endif
+#if defined(HAVE_BSD_NICE)
+ (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
+#endif
+#ifdef SYS_WINNT
+ process_handle = GetCurrentProcess();
+ if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
+ msyslog(LOG_ERR, "SetPriorityClass failed: %m");
+ }
+#endif /* SYS_WINNT */
+
+ initializing = 0;
+
+ /*
+ * Use select() on all on all input fd's for unlimited
+ * time. select() will terminate on SIGALARM or on the
+ * reception of input. Using select() means we can't do
+ * robust signal handling and we get a potential race
+ * between checking for alarms and doing the select().
+ * Mostly harmless, I think.
+ * Keep going until we have enough information, or time is up.
+ */
+ /* On VMS, I suspect that select() can't be interrupted
+ * by a "signal" either, so I take the easy way out and
+ * have select() time out after one second.
+ * System clock updates really aren't time-critical,
+ * and - lacking a hardware reference clock - I have
+ * yet to learn about anything else that is.
+ */
+ was_alarmed = 0;
+ rbuflist = (struct recvbuf *)0;
+ while (finish_time > current_time) {
+#if !defined(HAVE_SIGNALED_IO)
+ fd_set rdfdes;
+ int nfound;
+#elif defined(HAVE_SIGNALED_IO)
+ block_io_and_alarm();
+#endif
+
+ rbuflist = getrecvbufs(); /* get received buffers */
+ if (printmsg) {
+ printmsg = 0;
+ analysis(0);
+ }
+ if (alarm_flag) { /* alarmed? */
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+
+ if (!was_alarmed && rbuflist == (struct recvbuf *)0) {
+ /*
+ * Nothing to do. Wait for something.
+ */
+#ifndef HAVE_SIGNALED_IO
+ rdfdes = fdmask;
+# if defined(VMS) || defined(SYS_VXWORKS)
+ /* make select() wake up after one second */
+ {
+ struct timeval t1;
+
+ t1.tv_sec = 1; t1.tv_usec = 0;
+ nfound = select(fd+1, &rdfdes, (fd_set *)0,
+ (fd_set *)0, &t1);
+ }
+# else
+ nfound = select(fd+1, &rdfdes, (fd_set *)0,
+ (fd_set *)0, (struct timeval *)0);
+# endif /* VMS */
+ if (nfound > 0) {
+ l_fp ts;
+ get_systime(&ts);
+ (void)input_handler(&ts);
+ }
+ else if (nfound == -1 && errno != EINTR)
+ msyslog(LOG_ERR, "select() error: %m");
+ else if (debug) {
+# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */
+ msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
+# endif
+ }
+#else /* HAVE_SIGNALED_IO */
+
+ wait_for_signal();
+#endif /* HAVE_SIGNALED_IO */
+ if (alarm_flag) /* alarmed? */
+ {
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+ rbuflist = getrecvbufs(); /* get received buffers */
+ }
+#ifdef HAVE_SIGNALED_IO
+ unblock_io_and_alarm();
+#endif /* HAVE_SIGNALED_IO */
+
+ /*
+ * Out here, signals are unblocked. Call timer routine
+ * to process expiry.
+ */
+ if (was_alarmed)
+ {
+ timer();
+ was_alarmed = 0;
+ }
+
+ /*
+ * Call the data procedure to handle each received
+ * packet.
+ */
+ while (rbuflist != (struct recvbuf *)0)
+ {
+ rbuf = rbuflist;
+ rbuflist = rbuf->next;
+ receive(rbuf);
+ freerecvbuf(rbuf);
+ }
+#if defined DEBUG && defined SYS_WINNT
+ if (debug > 4)
+ printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
+ handler_calls, handler_pkts);
+#endif
+
+ /*
+ * Do we have enough information to stop now?
+ */
+ if (have_enough())
+ break; /* time to end */
+
+ /*
+ * Go around again
+ */
+ }
+
+ /*
+ * adjust the clock and exit accordingly
+ */
+ set_local_clock();
+
+ /*
+ * if we get here then we are in trouble
+ */
+ return(1);
+}
+
+
+/*
+ * analysis - print a message indicating what is happening with time service
+ * must mimic have_enough() procedure.
+ */
+static void
+analysis(
+ int final
+ )
+{
+ if (contacted < sys_numservers) {
+ printf("%d servers of %d have been probed with %d packets\n",
+ contacted,sys_numservers,MINTRANSMITS);
+ return;
+ }
+ if (!responding) {
+ printf("No response from any of %d servers, network problem?\n",
+ sys_numservers);
+ return;
+ }
+ else if (responding < min_servers) {
+ printf("%d servers out of %d responding, need at least %d.\n",
+ responding, sys_numservers, min_servers);
+ return;
+ }
+ if (!validcount) {
+ printf("%d servers responding but none have valid time\n",
+ responding);
+ return;
+ }
+ else if (validcount < min_valid) {
+ printf("%d servers responding, %d are valid, need %d valid\n",
+ responding,validcount,min_valid);
+ return;
+ }
+ if (!final && valid_n_low != validcount) {
+ printf("%d valid servers but only %d have low dispersion\n",
+ validcount,valid_n_low);
+ return;
+ }
+}
+
+
+/* have_enough - see if we have enough information to terminate probing
+ */
+static int
+have_enough(void)
+{
+ /* have we contacted all servers yet? */
+ if (contacted < sys_numservers)
+ return 0; /* no...try some more */
+
+ /* have we got at least minimum servers responding? */
+ if (responding < min_servers)
+ return 0; /* no...try some more */
+
+ /* count the clocks */
+ (void) clock_count();
+
+ /* have we got at least minimum valid clocks? */
+ if (validcount <= 0 || validcount < min_valid)
+ return 0; /* no...try some more */
+
+ /* do we have all valid servers with low dispersion */
+ if (!secondhalf && valid_n_low != validcount)
+ return 0;
+
+ /* if we get into the secondhalf then we ignore dispersion */
+
+ /* all conditions have been met...end */
+ return 1;
+}
+
+
+/*
+ * transmit - transmit a packet to the given server, or mark it completed.
+ * This is called by the timeout routine and by the receive
+ * procedure.
+ */
+static void
+transmit(
+ register struct server *server
+ )
+{
+ struct pkt xpkt;
+ int timeout;
+
+ if (debug > 2)
+ printf("transmit(%s)\n", ntoa(&server->srcadr));
+
+ if ((server->reach & 01) == 0) {
+ l_fp ts;
+ /*
+ * Last message to this server timed out. Shift
+ * zeros into the filter.
+ */
+ L_CLR(&ts);
+ clock_filter(server, 0, &ts);
+ }
+
+ /*
+ * shift reachable register over
+ */
+ server->reach <<= 1;
+
+ /*
+ * If we're here, send another message to the server. Fill in
+ * the packet and let 'er rip.
+ */
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
+ server->version, MODE_CLIENT);
+ xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
+ xpkt.ppoll = NTP_MINPOLL;
+ xpkt.precision = NTPDATE_PRECISION;
+ xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
+ xpkt.rootdispersion = htonl(NTPDATE_DISP);
+ xpkt.refid = htonl(NTPDATE_REFID);
+ L_CLR(&xpkt.reftime);
+ L_CLR(&xpkt.org);
+ L_CLR(&xpkt.rec);
+
+ /*
+ * Determine whether to authenticate or not. If so,
+ * fill in the extended part of the packet and do it.
+ * If not, just timestamp it and send it away.
+ */
+ if (sys_authenticate) {
+ int len;
+
+ xpkt.exten[0] = htonl(sys_authkey);
+ get_systime(&server->xmt);
+ L_ADDUF(&server->xmt, sys_authdelay);
+ HTONL_FP(&server->xmt, &xpkt.xmt);
+ len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
+ if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) {
+ if (debug > 1)
+ printf("failed transmit auth to %s\n",
+ ntoa(&(server->srcadr)));
+ return;
+ }
+
+ if (debug > 1)
+ printf("transmit auth to %s\n",
+ ntoa(&(server->srcadr)));
+ } else {
+ get_systime(&(server->xmt));
+ HTONL_FP(&server->xmt, &xpkt.xmt);
+ if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) {
+ if (debug > 1)
+ printf("failed transmit to %s\n",
+ ntoa(&(server->srcadr)));
+ return;
+ }
+
+ if (debug > 1)
+ printf("transmit to %s\n", ntoa(&(server->srcadr)));
+ }
+
+ /*
+ * count transmits, record contacted count and set transmit time
+ */
+ if (++server->xmtcnt == MINTRANSMITS)
+ contacted++;
+ server->last_xmit = current_time;
+
+ /*
+ * determine timeout for this packet. The more packets we send
+ * to the host, the slower we get. If the host indicates that
+ * it is not "sane" then we expect even less.
+ */
+ if (server->xmtcnt < MINTRANSMITS) {
+ /* we have not sent enough */
+ timeout = TIMER_HZ; /* 1 second probe */
+ }
+ else if (server->rcvcnt <= 0) {
+ /* we have heard nothing */
+ if (secondhalf)
+ timeout = TIMER_HZ<<4; /* 16 second probe */
+ else
+ timeout = TIMER_HZ<<3; /* 8 second probe */
+ }
+ else {
+ /* if we have low dispersion then probe infrequently */
+ if (server->dispersion <= DESIREDDISP)
+ timeout = TIMER_HZ<<4; /* 16 second probe */
+ /* if the server is not in sync then let it alone */
+ else if (server->leap == LEAP_NOTINSYNC)
+ timeout = TIMER_HZ<<4; /* 16 second probe */
+ /* if the server looks broken ignore it */
+ else if (server->org.l_ui < server->reftime.l_ui)
+ timeout = TIMER_HZ<<5; /* 32 second probe */
+ else if (secondhalf)
+ timeout = TIMER_HZ<<2; /* 4 second probe */
+ else
+ timeout = TIMER_HZ<<1; /* 2 second probe */
+ }
+
+ /*
+ * set next transmit time based on timeout
+ */
+ server->event_time = current_time + timeout;
+}
+
+
+/*
+ * receive - receive and process an incoming frame
+ */
+static void
+receive(
+ struct recvbuf *rbufp
+ )
+{
+ register struct pkt *rpkt;
+ register struct server *server;
+ register s_fp di;
+ l_fp t10, t23;
+ l_fp org;
+ l_fp rec;
+ l_fp ci;
+ int has_mac;
+ int is_authentic;
+
+ if (debug > 2)
+ printf("receive(%s)\n", ntoa(&rbufp->srcadr));
+ /*
+ * Check to see if the packet basically looks like something
+ * intended for us.
+ */
+ if (rbufp->recv_length == LEN_PKT_NOMAC)
+ has_mac = 0;
+ else if (rbufp->recv_length >= LEN_PKT_NOMAC)
+ has_mac = 1;
+ else {
+ if (debug > 2)
+ printf("receive: packet length %d\n",
+ rbufp->recv_length);
+ return; /* funny length packet */
+ }
+
+ rpkt = &(rbufp->recv_pkt);
+ if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
+ PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
+ if (debug > 1)
+ printf("receive: bad version %d\n",
+ PKT_VERSION(rpkt->li_vn_mode));
+ return;
+ }
+
+ if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
+ && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
+ || rpkt->stratum >=STRATUM_UNSPEC) {
+ if (debug > 1)
+ printf("receive: mode %d stratum %d\n",
+ PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
+ return;
+ }
+
+ /*
+ * So far, so good. See if this is from a server we know.
+ */
+ server = findserver(&(rbufp->srcadr));
+ if (server == NULL) {
+ if (debug > 1)
+ printf("receive: server not found\n");
+ return;
+ }
+
+ /*
+ * Decode the org timestamp and make sure we're getting a response
+ * to our last request.
+ */
+ NTOHL_FP(&rpkt->org, &org);
+ if (!L_ISEQU(&org, &server->xmt)) {
+ if (debug > 1)
+ printf("receive: pkt.org and peer.xmt differ\n");
+ return;
+ }
+
+ /*
+ * Check out the authenticity if we're doing that.
+ */
+ if (!sys_authenticate)
+ is_authentic = 1;
+ else {
+ is_authentic = 0;
+
+ if (debug > 3)
+ printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
+ (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
+ (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
+ LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
+
+ if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
+ authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
+ (int)(rbufp->recv_length - LEN_PKT_NOMAC)))
+ is_authentic = 1;
+ if (debug)
+ printf("receive: authentication %s\n",
+ is_authentic ? "passed" : "failed");
+ }
+ server->trust <<= 1;
+ if (!is_authentic)
+ server->trust |= 1;
+
+ /*
+ * Looks good. Record info from the packet.
+ */
+ server->leap = PKT_LEAP(rpkt->li_vn_mode);
+ server->stratum = PKT_TO_STRATUM(rpkt->stratum);
+ server->precision = rpkt->precision;
+ server->rootdelay = ntohl(rpkt->rootdelay);
+ server->rootdispersion = ntohl(rpkt->rootdispersion);
+ server->refid = rpkt->refid;
+ NTOHL_FP(&rpkt->reftime, &server->reftime);
+ NTOHL_FP(&rpkt->rec, &rec);
+ NTOHL_FP(&rpkt->xmt, &server->org);
+
+ /*
+ * count this guy as responding
+ */
+ server->reach |= 1;
+ if (server->rcvcnt++ == 0)
+ responding++;
+
+ /*
+ * Make sure the server is at least somewhat sane. If not, ignore
+ * it for later.
+ */
+ if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
+ if (debug > 1)
+ printf("receive: pkt insane\n");
+ return;
+ }
+
+ /*
+ * Calculate the round trip delay (di) and the clock offset (ci).
+ * We use the equations (reordered from those in the spec):
+ *
+ * d = (t2 - t3) - (t1 - t0)
+ * c = ((t2 - t3) + (t1 - t0)) / 2
+ */
+ t10 = server->org; /* pkt.xmt == t1 */
+ L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
+
+ t23 = rec; /* pkt.rec == t2 */
+ L_SUB(&t23, &org); /* pkt->org == t3 */
+
+ /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
+ ci = t10;
+ L_ADD(&ci, &t23);
+ L_RSHIFT(&ci);
+
+ /*
+ * Calculate di in t23 in full precision, then truncate
+ * to an s_fp.
+ */
+ L_SUB(&t23, &t10);
+ di = LFPTOFP(&t23);
+
+ if (debug > 3)
+ printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
+
+ di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
+ + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
+
+ if (di <= 0) { /* value still too raunchy to use? */
+ L_CLR(&ci);
+ di = 0;
+ } else {
+ di = max(di, NTP_MINDIST);
+ }
+
+
+ /*
+ * This one is valid. Give it to clock_filter(),
+ */
+ clock_filter(server, di, &ci);
+ if (debug > 1)
+ printf("receive from %s\n", ntoa(&rbufp->srcadr));
+
+ /*
+ * See if we should goes the transmission. If not return now
+ * otherwise have the next event time be shortened
+ */
+ if (server->stratum <= NTP_INFIN)
+ return; /* server does not have a stratum */
+ if (server->leap == LEAP_NOTINSYNC)
+ return; /* just booted server or out of sync */
+ if (!L_ISHIS(&server->org, &server->reftime))
+ return; /* broken host */
+ if (server->trust != 0)
+ return; /* can not trust it */
+
+ if (server->dispersion < DESIREDDISP)
+ return; /* we have the desired dispersion */
+
+ server->event_time -= (TIMER_HZ+1);
+}
+
+
+/*
+ * clock_filter - add clock sample, determine a server's delay, dispersion
+ * and offset
+ */
+static void
+clock_filter(
+ register struct server *server,
+ s_fp di,
+ l_fp *c
+ )
+{
+ register int i, j;
+ int ord[NTP_SHIFT];
+
+ /*
+ * Insert sample and increment nextpt
+ */
+
+ i = server->filter_nextpt;
+ server->filter_delay[i] = di;
+ server->filter_offset[i] = *c;
+ server->filter_soffset[i] = LFPTOFP(c);
+ server->filter_nextpt++;
+ if (server->filter_nextpt >= NTP_SHIFT)
+ server->filter_nextpt = 0;
+
+ /*
+ * Sort indices into increasing delay order
+ */
+ for (i = 0; i < NTP_SHIFT; i++)
+ ord[i] = i;
+
+ for (i = 0; i < (NTP_SHIFT-1); i++) {
+ for (j = i+1; j < NTP_SHIFT; j++) {
+ if (server->filter_delay[ord[j]] == 0)
+ continue;
+ if (server->filter_delay[ord[i]] == 0
+ || (server->filter_delay[ord[i]]
+ > server->filter_delay[ord[j]])) {
+ register int tmp;
+
+ tmp = ord[i];
+ ord[i] = ord[j];
+ ord[j] = tmp;
+ }
+ }
+ }
+
+ /*
+ * Now compute the dispersion, and assign values to delay and
+ * offset. If there are no samples in the register, delay and
+ * offset go to zero and dispersion is set to the maximum.
+ */
+ if (server->filter_delay[ord[0]] == 0) {
+ server->delay = 0;
+ L_CLR(&server->offset);
+ server->soffset = 0;
+ server->dispersion = PEER_MAXDISP;
+ } else {
+ register s_fp d;
+
+ server->delay = server->filter_delay[ord[0]];
+ server->offset = server->filter_offset[ord[0]];
+ server->soffset = LFPTOFP(&server->offset);
+ server->dispersion = 0;
+ for (i = 1; i < NTP_SHIFT; i++) {
+ if (server->filter_delay[ord[i]] == 0)
+ d = PEER_MAXDISP;
+ else {
+ d = server->filter_soffset[ord[i]]
+ - server->filter_soffset[ord[0]];
+ if (d < 0)
+ d = -d;
+ if (d > PEER_MAXDISP)
+ d = PEER_MAXDISP;
+ }
+ /*
+ * XXX This *knows* PEER_FILTER is 1/2
+ */
+ server->dispersion += (u_fp)(d) >> i;
+ }
+ }
+ /*
+ * We're done
+ */
+}
+
+
+/* clock_count - count the clock sources we have
+ */
+static void
+clock_count(void)
+{
+ register struct server *server;
+ register int n;
+
+ /* reset counts */
+ validcount = valid_n_low = 0;
+
+ /* go through the list of servers and count the clocks we believe
+ * and that have low dispersion
+ */
+ for (n = 0; n < sys_numservers; n++) {
+ server = sys_servers[n];
+ if (server->delay == 0) {
+ continue; /* no data */
+ }
+ if (server->stratum > NTP_INFIN) {
+ continue; /* stratum no good */
+ }
+ if (server->delay > NTP_MAXWGT) {
+ continue; /* too far away */
+ }
+ if (server->leap == LEAP_NOTINSYNC)
+ continue; /* he's in trouble */
+ if (!L_ISHIS(&server->org, &server->reftime)) {
+ continue; /* very broken host */
+ }
+ if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) {
+ continue; /* too long without sync */
+ }
+ if (server->trust != 0) {
+ continue;
+ }
+
+ /*
+ * This one is a valid time source..
+ */
+ validcount++;
+
+ /*
+ * See if this one has a okay low dispersion
+ */
+ if (server->dispersion <= DESIREDDISP)
+ valid_n_low++;
+ }
+
+ if (debug > 1)
+ printf("have %d, valid %d, low %d\n",
+ responding, validcount, valid_n_low);
+}
+
+
+/*
+ * clock_select - select the pick-of-the-litter clock from the samples
+ * we've got.
+ */
+static struct server *
+clock_select(void)
+{
+ register struct server *server;
+ register int i;
+ register int nlist;
+ register s_fp d;
+ register int j;
+ register int n;
+ s_fp local_threshold;
+ struct server *server_list[NTP_MAXCLOCK];
+ u_fp server_badness[NTP_MAXCLOCK];
+ struct server *sys_server;
+
+ /*
+ * This first chunk of code is supposed to go through all
+ * servers we know about to find the NTP_MAXLIST servers which
+ * are most likely to succeed. We run through the list
+ * doing the sanity checks and trying to insert anyone who
+ * looks okay. We are at all times aware that we should
+ * only keep samples from the top two strata and we only need
+ * NTP_MAXLIST of them.
+ */
+ nlist = 0; /* none yet */
+ for (n = 0; n < sys_numservers; n++) {
+ server = sys_servers[n];
+ if (server->delay == 0)
+ continue; /* no data */
+ if (server->stratum > NTP_INFIN)
+ continue; /* stratum no good */
+ if (server->delay > NTP_MAXWGT) {
+ continue; /* too far away */
+ }
+ if (server->leap == LEAP_NOTINSYNC)
+ continue; /* he's in trouble */
+ if (!L_ISHIS(&server->org, &server->reftime)) {
+ continue; /* very broken host */
+ }
+ if ((server->org.l_ui - server->reftime.l_ui)
+ >= NTP_MAXAGE) {
+ continue; /* too long without sync */
+ }
+ if (server->trust != 0) {
+ continue;
+ }
+
+ /*
+ * This one seems sane. Find where he belongs
+ * on the list.
+ */
+ d = server->dispersion + server->dispersion;
+ for (i = 0; i < nlist; i++)
+ if (server->stratum <= server_list[i]->stratum)
+ break;
+ for ( ; i < nlist; i++) {
+ if (server->stratum < server_list[i]->stratum)
+ break;
+ if (d < (s_fp) server_badness[i])
+ break;
+ }
+
+ /*
+ * If i points past the end of the list, this
+ * guy is a loser, else stick him in.
+ */
+ if (i >= NTP_MAXLIST)
+ continue;
+ for (j = nlist; j > i; j--)
+ if (j < NTP_MAXLIST) {
+ server_list[j] = server_list[j-1];
+ server_badness[j]
+ = server_badness[j-1];
+ }
+
+ server_list[i] = server;
+ server_badness[i] = d;
+ if (nlist < NTP_MAXLIST)
+ nlist++;
+ }
+
+ /*
+ * Got the five-or-less best. Cut the list where the number of
+ * strata exceeds two.
+ */
+ j = 0;
+ for (i = 1; i < nlist; i++)
+ if (server_list[i]->stratum > server_list[i-1]->stratum)
+ if (++j == 2) {
+ nlist = i;
+ break;
+ }
+
+ /*
+ * Whew! What we should have by now is 0 to 5 candidates for
+ * the job of syncing us. If we have none, we're out of luck.
+ * If we have one, he's a winner. If we have more, do falseticker
+ * detection.
+ */
+
+ if (nlist == 0)
+ sys_server = 0;
+ else if (nlist == 1) {
+ sys_server = server_list[0];
+ } else {
+ /*
+ * Re-sort by stratum, bdelay estimate quality and
+ * server.delay.
+ */
+ for (i = 0; i < nlist-1; i++)
+ for (j = i+1; j < nlist; j++) {
+ if (server_list[i]->stratum
+ < server_list[j]->stratum)
+ break; /* already sorted by stratum */
+ if (server_list[i]->delay
+ < server_list[j]->delay)
+ continue;
+ server = server_list[i];
+ server_list[i] = server_list[j];
+ server_list[j] = server;
+ }
+
+ /*
+ * Calculate the fixed part of the dispersion limit
+ */
+ local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
+ + NTP_MAXSKW;
+
+ /*
+ * Now drop samples until we're down to one.
+ */
+ while (nlist > 1) {
+ for (n = 0; n < nlist; n++) {
+ server_badness[n] = 0;
+ for (j = 0; j < nlist; j++) {
+ if (j == n) /* with self? */
+ continue;
+ d = server_list[j]->soffset
+ - server_list[n]->soffset;
+ if (d < 0) /* absolute value */
+ d = -d;
+ /*
+ * XXX This code *knows* that
+ * NTP_SELECT is 3/4
+ */
+ for (i = 0; i < j; i++)
+ d = (d>>1) + (d>>2);
+ server_badness[n] += d;
+ }
+ }
+
+ /*
+ * We now have an array of nlist badness
+ * coefficients. Find the badest. Find
+ * the minimum precision while we're at
+ * it.
+ */
+ i = 0;
+ n = server_list[0]->precision;;
+ for (j = 1; j < nlist; j++) {
+ if (server_badness[j] >= server_badness[i])
+ i = j;
+ if (n > server_list[j]->precision)
+ n = server_list[j]->precision;
+ }
+
+ /*
+ * i is the index of the server with the worst
+ * dispersion. If his dispersion is less than
+ * the threshold, stop now, else delete him and
+ * continue around again.
+ */
+ if (server_badness[i] < (local_threshold
+ + (FP_SECOND >> (-n))))
+ break;
+ for (j = i + 1; j < nlist; j++)
+ server_list[j-1] = server_list[j];
+ nlist--;
+ }
+
+ /*
+ * What remains is a list of less than 5 servers. Take
+ * the best.
+ */
+ sys_server = server_list[0];
+ }
+
+ /*
+ * That's it. Return our server.
+ */
+ return sys_server;
+}
+
+
+/*
+ * set_local_clock -- handle setting the local clock or displaying info.
+ */
+static void
+set_local_clock(void)
+{
+ register int i;
+ register struct server *server;
+ time_t tmp;
+ double dtemp;
+
+ /*
+ * if setting time then print final analysis
+ */
+ if (set_time)
+ analysis(1);
+
+ /*
+ * pick a clock
+ */
+ server = clock_select();
+
+ /*
+ * do some display of information
+ */
+ if (debug || verbose) {
+ for (i = 0; i < sys_numservers; i++)
+ printserver(sys_servers[i], stdout);
+ if (debug)
+ printf("packets sent %ld, received %ld\n",
+ total_xmit, total_recv);
+ }
+
+ /*
+ * see if we have a server to set the time with
+ */
+ if (server == 0) {
+ if (!set_time || verbose)
+ fprintf(stdout,"No servers available to sync time with\n");
+ exit(1);
+ }
+
+ /*
+ * we have a valid and selected time to use!!!!!
+ */
+
+ /*
+ * if we are not setting the time then display offset and exit
+ */
+ if (!set_time) {
+ fprintf(stdout,
+ "Your clock is off by %s seconds. (%s) [%ld/%ld]\n",
+ lfptoa(&server->offset, 7),
+ ntoa(&server->srcadr),
+ total_xmit, total_recv);
+ exit(0);
+ }
+
+ /*
+ * set the clock
+ * XXX: Examine the more flexible approach used by ntpdate.
+ * Note that a design consideration here is that we sometimes
+ * _want_ to step the clock by a _huge_ amount in either
+ * direction, because the local clock is completely bogus.
+ * This condition must be recognized and dealt with, so
+ * that we always get a good time when this completes.
+ * -- jhutz+@cmu.edu, 16-Aug-1999
+ */
+ LFPTOD(&server->offset, dtemp);
+ step_systime(dtemp);
+ time(&tmp);
+ fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n",
+ ctime(&tmp)+4,
+ ntoa(&server->srcadr),
+ lfptoa(&server->offset, 7),
+ total_xmit, total_recv);
+ exit(0);
+}
+
+
+/*
+ * findserver - find a server in the list given its address
+ */
+static struct server *
+findserver(
+ struct sockaddr_in *addr
+ )
+{
+ register int i;
+ register u_int32 netnum;
+
+ if (htons(addr->sin_port) != NTP_PORT)
+ return 0;
+ netnum = addr->sin_addr.s_addr;
+
+ for (i = 0; i < sys_numservers; i++) {
+ if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr)
+ return sys_servers[i];
+ }
+ return 0;
+}
+
+
+/*
+ * timer - process a timer interrupt
+ */
+static void
+timer(void)
+{
+ register int k;
+
+ /*
+ * Bump the current idea of the time
+ */
+ current_time++;
+
+ /*
+ * see if we have reached half time
+ */
+ if (current_time >= half_time && !secondhalf) {
+ secondhalf++;
+ if (debug)
+ printf("\nSecond Half of Timeout!\n");
+ printmsg++;
+ }
+
+ /*
+ * We only want to send a few packets per transmit interrupt
+ * to throttle things
+ */
+ for(k = 0;k < MAXXMITCOUNT;k++) {
+ register int i, oldi;
+ register u_long oldxtime;
+
+ /*
+ * We want to send a packet out for a server that has an
+ * expired event time. However to be mellow about this, we only
+ * use one expired event timer and to avoid starvation we use
+ * the one with the oldest last transmit time.
+ */
+ oldi = -1;
+ oldxtime = 0;
+ for (i = 0; i < sys_numservers; i++) {
+ if (sys_servers[i]->event_time <= current_time) {
+ if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) {
+ oldxtime = sys_servers[i]->last_xmit;
+ oldi = i;
+ }
+ }
+ }
+ if (oldi >= 0)
+ transmit(sys_servers[oldi]);
+ else
+ break; /* no expired event */
+ } /* end of transmit loop */
+}
+
+
+#ifndef SYS_WINNT
+/*
+ * alarming - record the occurance of an alarm interrupt
+ */
+static RETSIGTYPE
+alarming(
+ int sig
+ )
+#else
+void CALLBACK
+alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+#endif /* SYS_WINNT */
+{
+ alarm_flag++;
+}
+
+
+/*
+ * init_alarm - set up the timer interrupt
+ */
+static void
+init_alarm(void)
+{
+#ifndef SYS_WINNT
+# ifndef HAVE_TIMER_SETTIME
+ struct itimerval itimer;
+# else
+ struct itimerspec ntpdate_itimer;
+# endif
+#else
+ TIMECAPS tc;
+ UINT wTimerRes, wTimerID;
+# endif /* SYS_WINNT */
+#if defined SYS_CYGWIN32 || defined SYS_WINNT
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tkp;
+ DWORD dwUser = 0;
+#endif /* SYS_WINNT */
+
+ alarm_flag = 0;
+
+#ifndef SYS_WINNT
+# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
+ alarm_flag = 0;
+ /* this code was put in as setitimer() is non existant this us the
+ * POSIX "equivalents" setup - casey
+ */
+ /* ntpdate_timerid is global - so we can kill timer later */
+ if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
+# ifdef SYS_VXWORKS
+ ERROR
+# else
+ -1
+# endif
+ )
+ {
+ fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
+ return;
+ }
+
+ /* TIMER_HZ = (5)
+ * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
+ * seconds from now and they continue on every 1/TIMER_HZ seconds.
+ */
+ (void) signal_no_reset(SIGALRM, alarming);
+ ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
+ ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
+ ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
+ timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
+# else
+ /*
+ * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
+ * seconds from now and they continue on every 1/TIMER_HZ seconds.
+ */
+ (void) signal_no_reset(SIGALRM, alarming);
+ itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
+ itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
+ itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+# endif
+#if defined SYS_CYGWIN32
+ /*
+ * Get previleges needed for fiddling with the clock
+ */
+
+ /* get the current process token handle */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ msyslog(LOG_ERR, "OpenProcessToken failed: %m");
+ exit(1);
+ }
+ /* get the LUID for system-time privilege. */
+ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; /* one privilege to set */
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ /* get set-time privilege for this process. */
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
+ /* cannot test return value of AdjustTokenPrivileges. */
+ if (GetLastError() != ERROR_SUCCESS)
+ msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
+#endif
+#else /* SYS_WINNT */
+ _tzset();
+
+ /*
+ * Get previleges needed for fiddling with the clock
+ */
+
+ /* get the current process token handle */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
+ msyslog(LOG_ERR, "OpenProcessToken failed: %m");
+ exit(1);
+ }
+ /* get the LUID for system-time privilege. */
+ LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; /* one privilege to set */
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ /* get set-time privilege for this process. */
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
+ /* cannot test return value of AdjustTokenPrivileges. */
+ if (GetLastError() != ERROR_SUCCESS)
+ msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
+
+ /*
+ * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
+ * Under Win/NT, expiry of timer interval leads to invocation
+ * of a callback function (on a different thread) rather than
+ * generating an alarm signal
+ */
+
+ /* determine max and min resolution supported */
+ if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
+ msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
+ exit(1);
+ }
+ wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
+ /* establish the minimum timer resolution that we'll use */
+ timeBeginPeriod(wTimerRes);
+
+ /* start the timer event */
+ wTimerID = timeSetEvent(
+ (UINT) (1000/TIMER_HZ), /* Delay */
+ wTimerRes, /* Resolution */
+ (LPTIMECALLBACK) alarming, /* Callback function */
+ (DWORD) dwUser, /* User data */
+ TIME_PERIODIC); /* Event type (periodic) */
+ if (wTimerID == 0) {
+ msyslog(LOG_ERR, "timeSetEvent failed: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+}
+
+
+/*
+ * init_io - initialize I/O data and open socket
+ */
+static void
+init_io(void)
+{
+#ifdef SYS_WINNT
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ init_transmitbuff();
+#endif /* SYS_WINNT */
+
+ /*
+ * Init buffer free list and stat counters
+ */
+ init_recvbuff(sys_numservers + 2);
+
+#if defined(HAVE_SIGNALED_IO)
+ set_signal();
+#endif
+
+#ifdef SYS_WINNT
+ wVersionRequested = MAKEWORD(1,1);
+ if (WSAStartup(wVersionRequested, &wsaData))
+ {
+ msyslog(LOG_ERR, "No useable winsock.dll: %m");
+ exit(1);
+ }
+#endif /* SYS_WINNT */
+
+ BLOCKIO();
+
+ /* create a datagram (UDP) socket */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ msyslog(LOG_ERR, "socket() failed: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * bind the socket to the NTP port
+ */
+ if (!debug && set_time && !unpriv_port) {
+ struct sockaddr_in addr;
+
+ memset((char *)&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(NTP_PORT);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+#ifndef SYS_WINNT
+ if (errno == EADDRINUSE)
+#else
+ if (WSAGetLastError() == WSAEADDRINUSE)
+#endif
+ msyslog(LOG_ERR,
+ "the NTP socket is in use, exiting");
+ else
+ msyslog(LOG_ERR, "bind() fails: %m");
+ exit(1);
+ }
+ }
+
+ FD_ZERO(&fdmask);
+ FD_SET(fd, &fdmask);
+
+ /*
+ * set non-blocking,
+ */
+
+#ifdef USE_FIONBIO
+ /* in vxWorks we use FIONBIO, but the others are defined for old systems, so
+ * all hell breaks loose if we leave them defined
+ */
+#undef O_NONBLOCK
+#undef FNDELAY
+#undef O_NDELAY
+#endif
+
+#if defined(O_NONBLOCK) /* POSIX */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#elif defined(FNDELAY)
+ if (fcntl(fd, F_SETFL, FNDELAY) < 0)
+ {
+ msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#elif defined(O_NDELAY) /* generally the same as FNDELAY */
+ if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
+ {
+ msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#elif defined(FIONBIO)
+ if (
+# if defined(VMS)
+ (ioctl(fd,FIONBIO,&1) < 0)
+# elif defined(SYS_WINNT)
+ (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
+# else
+ (ioctl(fd,FIONBIO,&on) < 0)
+# endif
+ )
+ {
+ msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#elif defined(FIOSNBIO)
+ if (ioctl(fd,FIOSNBIO,&on) < 0)
+ {
+ msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
+ exit(1);
+ /*NOTREACHED*/
+ }
+#else
+# include "Bletch: Need non-blocking I/O!"
+#endif
+
+#ifdef HAVE_SIGNALED_IO
+ init_socket_sig(fd);
+#endif /* not HAVE_SIGNALED_IO */
+
+ UNBLOCKIO();
+}
+
+
+/*
+ * sendpkt - send a packet to the specified destination
+ */
+static int
+sendpkt(
+ struct sockaddr_in *dest,
+ struct pkt *pkt,
+ int len
+ )
+{
+ int cc;
+ static int horriblecnt = 0;
+#ifdef SYS_WINNT
+ DWORD err;
+#endif /* SYS_WINNT */
+
+ total_xmit++; /* count it */
+
+ if (horrible) {
+ if (++horriblecnt > HORRIBLEOK) {
+ if (debug > 3)
+ printf("dropping send (%s)\n", ntoa(dest));
+ if (horriblecnt >= HORRIBLEOK+horrible)
+ horriblecnt = 0;
+ return 0;
+ }
+ }
+
+
+ cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
+ sizeof(struct sockaddr_in));
+#ifndef SYS_WINNT
+ if (cc == -1) {
+ if (errno != EWOULDBLOCK && errno != ENOBUFS)
+#else
+ if (cc == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
+#endif /* SYS_WINNT */
+ msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * input_handler - receive packets asynchronously
+ */
+void
+input_handler(l_fp *xts)
+{
+ register int n;
+ register struct recvbuf *rb;
+ struct timeval tvzero;
+ int fromlen;
+ fd_set fds;
+ l_fp ts;
+ ts = *xts; /* we ignore xts, but make the compiler happy */
+
+ /*
+ * Do a poll to see if we have data
+ */
+ for (;;) {
+ fds = fdmask;
+ tvzero.tv_sec = tvzero.tv_usec = 0;
+ n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
+
+ /*
+ * If nothing to do, just return. If an error occurred,
+ * complain and return. If we've got some, freeze a
+ * timestamp.
+ */
+ if (n == 0)
+ return;
+ else if (n == -1) {
+ if (errno != EINTR) {
+ msyslog(LOG_ERR, "select() error: %m");
+ }
+ return;
+ }
+ get_systime(&ts);
+
+ /*
+ * Get a buffer and read the frame. If we
+ * haven't got a buffer, or this is received
+ * on the wild card socket, just dump the packet.
+ */
+ if (initializing || free_recvbuffs == 0) {
+ char buf[100];
+
+#ifndef SYS_WINNT
+ (void) read(fd, buf, sizeof buf);
+#else
+ /* NT's _read does not operate on nonblocking sockets
+ * either recvfrom or ReadFile() has to be used here.
+ * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
+ * just to be different use recvfrom() here
+ */
+ recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
+#endif /* SYS_WINNT */
+ continue;
+ }
+
+ rb = get_free_recv_buffer();
+
+ fromlen = sizeof(struct sockaddr_in);
+ rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
+ sizeof(rb->recv_pkt), 0,
+ (struct sockaddr *)&rb->srcadr, &fromlen);
+ if (rb->recv_length == -1) {
+ freerecvbuf(rb);
+ continue;
+ }
+
+ /*
+ * Got one. Mark how and when it got here,
+ * put it on the full list.
+ */
+ rb->recv_time = ts;
+ add_full_recv_buffer(rb);
+ total_recv++; /* count it */
+ }
+}
+
+
+/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
+/*
+ * printserver - print detail information for a server
+ */
+static void
+printserver(
+ register struct server *pp,
+ FILE *fp
+ )
+{
+ register int i;
+ char junk[5];
+ char *str;
+
+ if (!debug) {
+ (void) fprintf(fp,
+ "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n",
+ ntoa(&pp->srcadr),
+ pp->xmtcnt,pp->rcvcnt,pp->reach,
+ pp->version,pp->stratum,
+ lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5),
+ ufptoa(pp->dispersion, 4));
+ return;
+ }
+
+ (void) fprintf(fp, "server %s, port %d\n",
+ ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
+
+ (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
+ pp->stratum, pp->precision,
+ pp->leap & 0x2 ? '1' : '0',
+ pp->leap & 0x1 ? '1' : '0',
+ pp->trust);
+
+ if (pp->stratum == 1) {
+ junk[4] = 0;
+ memmove(junk, (char *)&pp->refid, 4);
+ str = junk;
+ } else {
+ str = numtoa(pp->refid);
+ }
+ (void) fprintf(fp,
+ "refid [%s], delay %s, dispersion %s\n",
+ str, fptoa((s_fp)pp->delay, 5),
+ ufptoa(pp->dispersion, 5));
+
+ (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n",
+ pp->xmtcnt, pp->rcvcnt, pp->reach);
+
+ (void) fprintf(fp, "reference time: %s\n",
+ prettydate(&pp->reftime));
+ (void) fprintf(fp, "originate timestamp: %s\n",
+ prettydate(&pp->org));
+ (void) fprintf(fp, "transmit timestamp: %s\n",
+ prettydate(&pp->xmt));
+
+ (void) fprintf(fp, "filter delay: ");
+ for (i = 0; i < NTP_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
+ if (i == (NTP_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "filter offset:");
+ for (i = 0; i < PEER_SHIFT; i++) {
+ (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
+ if (i == (PEER_SHIFT>>1)-1)
+ (void) fprintf(fp, "\n ");
+ }
+ (void) fprintf(fp, "\n");
+
+ (void) fprintf(fp, "delay %s, dispersion %s\n",
+ fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
+
+ (void) fprintf(fp, "offset %s\n\n",
+ lfptoa(&pp->offset, 6));
+}
+
+#if !defined(HAVE_VSPRINTF)
+int
+vsprintf(
+ char *str,
+ const char *fmt,
+ va_list ap
+ )
+{
+ FILE f;
+ int len;
+
+ f._flag = _IOWRT+_IOSTRG;
+ f._ptr = str;
+ f._cnt = 32767;
+ len = _doprnt(fmt, ap, &f);
+ *f._ptr = 0;
+ return (len);
+}
+#endif
OpenPOWER on IntegriCloud