Remove files not present in 4.1.1a import.
This commit is contained in:
parent
ce265a549d
commit
eaabcee53b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/ntp/dist/; revision=106167 svn path=/vendor/ntp/4.1.1a/; revision=106165; tag=vendor/ntp/4.1.1a
@ -1,207 +0,0 @@
|
||||
-------------
|
||||
INTRODUCTION:
|
||||
-------------
|
||||
Last revision 27 July 1999 Version 4.0.95.
|
||||
|
||||
This version compiles under WINNT with Visual C 6.0.
|
||||
|
||||
Greg Brackley and Sven Dietrich
|
||||
|
||||
Significant changes:
|
||||
-Visual Studio v6.0 support
|
||||
-Winsock 2.0 support
|
||||
-Use of I/O completion ports for sockets and comm port I/O
|
||||
-Removed the use of multimedia timers (from ntpd, others need removing)
|
||||
-Use of waitable timers (with user mode APC) and performance counters to fake getting a better time
|
||||
-Trimble Palisade NTP Reference Clock support
|
||||
-General cleanup, prototyping of functions
|
||||
-Moved receiver buffer code to a separate module (removed unused members from the recvbuff struct)
|
||||
-Moved io signal code to a separate module
|
||||
|
||||
Compiling Instructions:
|
||||
1. Requires Perl to be installed, and the Perl environment variable to be set correctly
|
||||
2. Open the .\ports\winnt\ntp.dsw
|
||||
3. Batch build of all debug projects compile
|
||||
|
||||
|
||||
Last revision: 20-Oct-1996
|
||||
|
||||
This version corrects problems with building the XNTP
|
||||
version 3.5-86 distribution under Windows NT.
|
||||
|
||||
The following files were modified:
|
||||
blddbg.bat
|
||||
bldrel.bat
|
||||
include\ntp_machine.h
|
||||
xntpd\ntp_unixclock.c
|
||||
xntpd\ntp_refclock.c
|
||||
scripts\wininstall\build.bat
|
||||
scripts\wininstall\setup.rul
|
||||
scripts\wininstall\readme.nt
|
||||
scripts\wininstall\distrib\ntpog.wri
|
||||
html\hints\winnt (this file)
|
||||
|
||||
In order to build the entire Windows NT distribution you
|
||||
need to modify the file scripts\wininstall\build.bat
|
||||
with the installation directory of the InstallShield
|
||||
software. Then, simply type "bldrel" for non-debug
|
||||
or "blddbg" for debug executables.
|
||||
|
||||
|
||||
|
||||
Greg Schueman
|
||||
<schueman@acm.org>
|
||||
|
||||
|
||||
Last revision: 07-May-1996
|
||||
|
||||
This set of changes fixes all known bugs, and it includes
|
||||
several major enhancements.
|
||||
|
||||
Many changes have been made both to the build environment as
|
||||
well as the code. There is no longer an ntp.mak file, instead
|
||||
there is a buildntall.bat file that will build the entire
|
||||
release in one shot. The batch file requires Perl. Perl
|
||||
is easily available from the NT Resource Kit or on the Net.
|
||||
|
||||
The multiple interface support was adapted from Larry Kahn's
|
||||
work on the BIND NT port. I have not been able to test it
|
||||
adequately as I only have NT servers with one network
|
||||
interfaces on which to test.
|
||||
|
||||
Enhancements:
|
||||
* Event Logging now works correctly.
|
||||
* Version numbers now work (requires Perl during build)
|
||||
* Support for multiple network interface cards (untested)
|
||||
* NTP.CONF now default, but supports ntp.ini if not found
|
||||
* Installation procedure automated.
|
||||
* All paths now allow environment variables such as %windir%
|
||||
|
||||
Bug fixes:
|
||||
* INSTSRV replaced, works correctly
|
||||
* Cleaned up many warnings
|
||||
* Corrected use of an uninitialized variable in XNTPD
|
||||
* Fixed ntpdate -b option
|
||||
* Fixed ntpdate to accept names as well as IP addresses
|
||||
(Winsock WSAStartup was called after a gethostbyname())
|
||||
* Fixed problem with "longjmp" in xntpdc/ntpdc.c that
|
||||
caused a software exception on doing a Control-C in xntpdc.
|
||||
A Cntrl-C now terminates the program.
|
||||
|
||||
See below for more detail:
|
||||
|
||||
Note: SIGINT is not supported for any Win32 application including
|
||||
Windows NT and Windows 95. When a CTRL+C interrupt occurs, Win32
|
||||
operating systems generate a new thread to specifically handle that
|
||||
interrupt. This can cause a single-thread application such as UNIX,
|
||||
to become multithreaded, resulting in unexpected behavior.
|
||||
|
||||
|
||||
Possible enhancements and things left to do:
|
||||
* Reference clock drivers for NT (at least Local Clock support)
|
||||
* Control Panel Applet
|
||||
* InstallShield based installation, like NT BIND has
|
||||
* Integration with NT Performance Monitor
|
||||
* SNMP integration
|
||||
* Fully test multiple interface support
|
||||
|
||||
|
||||
Known problems:
|
||||
* bug in ntptrace - if no Stratum 1 servers are available,
|
||||
such as on an IntraNet, the application crashes.
|
||||
|
||||
|
||||
|
||||
|
||||
Last revision: 12-Apr-1995
|
||||
|
||||
|
||||
This NTPv3 distribution includes a sample configuration file and the project
|
||||
makefiles for WindowsNT 3.5 platform using Microsoft Visual C++ 2.0 compiler.
|
||||
Also included is a small routine to install the NTP daemon as a "service"
|
||||
on a WindowsNT box. Besides xntpd, the utilities that have been ported are
|
||||
ntpdate and xntpdc. The port to WindowsNT 3.5 has been tested using a Bancomm
|
||||
TimeServe2000 GPS receiver clock that acts as a strata 1 NTP server with no
|
||||
authentication (it has not been tested with any refclock drivers compiled in).
|
||||
Following are the known flaws in this port:
|
||||
1) currently, I do not know of a way in NT to get information about multiple
|
||||
network interface cards. The current port uses just one socket bound to
|
||||
INADDR_ANY address. Therefore when dealing with a multihomed NT time server,
|
||||
clients should point to the default address on the server (otherwise the
|
||||
reply is not guaranteed to come from the same interface to which the
|
||||
request was sent). Working with Microsoft to get this resolved.
|
||||
2) There is some problem with "longjmp" in xntpdc/ntpdc.c that causes a
|
||||
software exception on doing a Control-C in xntpdc. Be patient!
|
||||
3) The error messages logged by xntpd currently contain only the numerical
|
||||
error code. Corresponding error message string has to be looked up in
|
||||
"Books Online" on Visual C++ 2.0 under the topic "Numerical List of Error
|
||||
Codes".
|
||||
|
||||
|
||||
----------------------------------------------------
|
||||
MAKING XNTPD FOR WindowsNT 3.5 using Visual C++ 2.0:
|
||||
----------------------------------------------------
|
||||
|
||||
Separate projects are needed for xntpd, ntpdate, xntpdc, and the library
|
||||
containing routines used by them.
|
||||
|
||||
1) First build the static library composed of routines in the lib
|
||||
subdirectory of the distribution. Load the project by opening the
|
||||
corresponding makefile libntp.mak (in the lib subdirectory of the
|
||||
distribution) by choosing the Open option in the File menu. This should
|
||||
display a list of files contained in this project. Then choose the
|
||||
"Rebuild All" option from the Project menu in order to compile the
|
||||
routines into a library. The libntp.lib static library is created in
|
||||
the lib/WinDebug directory
|
||||
|
||||
You can now choose to build xntpd, ntpdate, and xntpdc in any order.
|
||||
|
||||
2) To build xntpd, load the project by opening the corresponding makefile
|
||||
xntpd.mak (in the xntpd subdirectory of the distribution), and rebuild
|
||||
all files. The xntpd.exe executable is created in the xntpd/WinDebug
|
||||
directory.
|
||||
|
||||
3) repeat the above step for ntpdate and xntpdc
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
INSTALLING XNTPD AS A SERVICE UNDER WindowsNT 3.5
|
||||
-------------------------------------------------
|
||||
|
||||
At this point you need to install 'xntpd' as a service. First modify the
|
||||
sample configuration file conf/config.winnt35 in the distribution to
|
||||
suit your needs. Then install it as "%SystemRoot%\NTP.INI" (%SystemRoot%
|
||||
is an environmental variable that can be determined by typing "set" at
|
||||
the "Command Prompt" or from the "System" icon in the "Control Panel",
|
||||
NTP.INI is the suggested name for the "ntp.conf" file in Windows environment).
|
||||
The instsrv.c program in the util subdirectory of the distribution can
|
||||
be used to install 'xntpd' as a service and start automatically at boot
|
||||
time. Compile instsrv.c, and enter form the command prompt
|
||||
"instsrv.exe NetWorkTimeProtocol <pathname_for_xntd.exe>"
|
||||
Clicking on the "Services" icon in the "Control Panel" ("Main" group
|
||||
in the "Program Manager") will display the list of currently installed
|
||||
services in a dialog box. The NetworkTimeProtocol service should show
|
||||
up in this list. Select it in the list and hit the "Start" button in
|
||||
the dialog box. The NTP service should start. View the event log by
|
||||
clicking on the "Event Viewer" icon in the "Administrative Tools" group
|
||||
of the "Program Manager", there should be several successful startup
|
||||
messages from NTP. NTP will keep running and restart automatically when
|
||||
the machine is rebooted.
|
||||
|
||||
You can change the start mode (automatic/manual) and other startup
|
||||
parameters correponding to the NTP service (eg. location of conf file)
|
||||
also in the "Services" dialog box if you wish.
|
||||
|
||||
There is no clean way to run 'ntpdate' before starting 'xntpd' at boot
|
||||
time, unlike the Unix environment. 'xntpd' will step the clock upto
|
||||
a 1000 seconds. While there is no reason that the system clock should
|
||||
be that much off during bootup if 'xntpd' was running before bootup,
|
||||
you may want to increase the CLOCK_WAYTOOBIG parameter in include/ntp.h
|
||||
from 1000 to, say, MAXINT.
|
||||
|
||||
You can also use instsrv.c to delete the NTP service
|
||||
"instsrv.exe NetworkTimeProtocol remove"
|
||||
|
||||
|
||||
Viraj Bais
|
||||
<vbais@mailman1.intel.com>
|
@ -1,153 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>vxWorks Port of NTP</TITLE>
|
||||
</HEAD>
|
||||
<BODY LINK="#00008B" VLINK="#8B0000">
|
||||
|
||||
<H1>VxWorks port of NTP </H1>
|
||||
|
||||
<P>Creating a port for vxWorks posed some problems. This port may help
|
||||
as a starting point for similar ports to real-time OS's and other embeddable
|
||||
kernels, particularly where main() is not allowed, and where the configure
|
||||
scripts need to be altered. </P>
|
||||
|
||||
<H1><B>Configuration issues</B></H1>
|
||||
|
||||
<P>I decided to do as little invasive surgery as possible on the NTP code,
|
||||
so I brought the vxWorks header tree in line with the standard unix tree.
|
||||
The following changes were needed, as a side effect these changes will
|
||||
allow for easy porting of other autoconfigure enabled code. </P>
|
||||
|
||||
<P>Where I have 386 you will need to put in your target type. The vxWorks
|
||||
tree entry point is /usr/wind. If these are the same for your system, you
|
||||
should be able to cut and paste the changes. </P>
|
||||
|
||||
<P><BLINK>WARNING: Check you are not overwriting files, before entering
|
||||
the following: there should be no conflict, but check first... </BLINK></P>
|
||||
|
||||
<P>export CC="cc386 -nostdlib -m486 -DCPU=I80486 -I/usr/wind/target/h"
|
||||
<BR>
|
||||
export RANLIB=ranlib386 <BR>
|
||||
export AR=ar386 <BR>
|
||||
export VX_KERNEL=/usr/wind/target/config/ims_std_bsp/vxWorks <BR>
|
||||
cd /usr/wind/target/sys <BR>
|
||||
ln -s ../signal.h <BR>
|
||||
ln -s ../time.h <BR>
|
||||
ln -s socket.h sockio.h <BR>
|
||||
ln -s ../selectLib.h select.h <BR>
|
||||
ln -s ../timers.h <BR>
|
||||
touch file.h param.h resource.h utsname.h var.h ../netdb.h ../a.out.h ../termios.h
|
||||
<BR>
|
||||
echo " ******ADD #include \"sys/times.h\" to sys/time.h
|
||||
" </P>
|
||||
|
||||
<P>The configure script must be changed in the following way to get the
|
||||
linking tests to work, once in the correct directory issue the following
|
||||
commands: <BR>
|
||||
sed -e 's%main.*()%vxmain()%' configure > configure.vxnew <BR>
|
||||
mv configure.vxnew configure <BR>
|
||||
chmod 755 configure </P>
|
||||
<P>The new version 4 of NTP requires some maths functions so it links in the
|
||||
maths library (-lm) in the ntpd <a href="../ntpd/Makefile.am">Makefile.am</a>
|
||||
change the line "ntpd_LDADD = $(LDADD) -lm" by removing the "-lm".<BR>
|
||||
You are now ready to compile</P>
|
||||
|
||||
|
||||
<P><BR>
|
||||
The <A HREF="../configure.in">configure.in </A>file needed to be altered
|
||||
to allow for a host-target configuration to take place. </P>
|
||||
|
||||
<UL>
|
||||
<LI>The define SYS_VXWORKS was added to the compilation flags. </LI>
|
||||
|
||||
<LI>Little endianess is set if the target is of type iX86. </LI>
|
||||
|
||||
<LI>The size of char, integer, long values are all set. If Wind River ever
|
||||
changes these values they will need to be updated. </LI>
|
||||
|
||||
<LI>clock_settime() is defined to be used for setting the clock. </LI>
|
||||
|
||||
<LI>The Linking flags have -r added to allow for relinking into the vxWorks
|
||||
kernel </LI>
|
||||
</UL>
|
||||
|
||||
<P>Unfortunately I have had to make use of the <A HREF="../include/ntp_machine.h">ntp_machine.h
|
||||
</A>file to add in the checks that would have been checked at linking stage
|
||||
by autoconf, a better method should be devised. </P>
|
||||
|
||||
<UL>
|
||||
<LI>There is now a NO_MAIN_ALLOWED define that simulates command line args,
|
||||
this allows the use of the normal startup sysntax. </LI>
|
||||
|
||||
<LI>POSIX timers have been added. </LI>
|
||||
|
||||
<LI>Structures normally found in netdb.h have been added with, the corresponding
|
||||
code is in <A HREF="../libntp/machines.c">machines.c </A>. Where possible
|
||||
the defines for these have been kept non-vxWorks specific.</LI>
|
||||
</UL>
|
||||
|
||||
<P>Unfortunately there are still quite a few SYS_VXWORKS type defines in
|
||||
the source, but I have eliminated as many as possible. You have the choice
|
||||
of using the usrtime.a library avaliable from the vxworks archives or forgoing
|
||||
adjtime() and using the clock_[get|set]time().The <A HREF="../include/ntp_machine.h">ntp_machine.h
|
||||
</A>file clearly marks how to do this. </P>
|
||||
|
||||
<H1><B>Compilation issues</B> </H1>
|
||||
|
||||
<P>You will need autoconf and automake ... available free from the gnu
|
||||
archives worldwide. </P>
|
||||
|
||||
<P>The variable arch is the target architecture (e.g. i486) </P>
|
||||
|
||||
<P>mkdir A.vxworks (or whatever....) <BR>
|
||||
cd A.vxworks <BR>
|
||||
../configure --target=arch-wrs-vxworks [any other options] <BR>
|
||||
make </P>
|
||||
|
||||
<P>Options I normally use are the --disable-all-clocks --enable-LOCAL-CLOCK flags.
|
||||
The program should proceed to compile without problem. The daemon ntpd,
|
||||
ntpdate, ntptrace, ntpdc, ntpq programs and of course the libraries are
|
||||
all fully ported. The other utilities are not, but they should be easy
|
||||
to port. </P>
|
||||
|
||||
<H1>Running the software </H1>
|
||||
|
||||
<P>Load in the various files, call them in the normal vxWorks function
|
||||
type manner. Here are some examples. Refer to the man pages for further
|
||||
information. </P>
|
||||
|
||||
<P>ld < ntpdate/ntpdate <BR>
|
||||
ld < ntpd/ntpd <BR>
|
||||
ld < ntptrace/ntptrace <BR>
|
||||
ld < ntpq/ntpq <BR>
|
||||
ld < ntpdc/ntpdc <BR>
|
||||
ntpdate ("-b", "192.168.0.245") <BR>
|
||||
sp(ntpd, "-c", "/export/home/casey/ntp/ntp.conf")
|
||||
<BR>
|
||||
ntpdc("-c", "monlist", "192.168.0.244")
|
||||
<BR>
|
||||
ntpq("-c", "peers", "192.168.0.244") <BR>
|
||||
ntptrace("192.168.0.244") <BR>
|
||||
</P>
|
||||
|
||||
<H1>Bugs and such </H1>
|
||||
|
||||
<P>Should you happen across any bugs, please let me know, or better yet
|
||||
fix them and submit a patch. Remember to make you patch general for Vxworks,
|
||||
not just for your particular architecture.
|
||||
<A HREF="http://www.ccii.co.za">CCII Systems
|
||||
(Pty) Ltd</A>, my ex employers, sponsored the time to this port.
|
||||
Please let me know how it goes, I would be most interested in offsets
|
||||
and configurations. </P>
|
||||
|
||||
<P><BR>
|
||||
</P>
|
||||
|
||||
<P>Casey Crellin</A> <BR>
|
||||
<A HREF="mailto:casey@csc.co.za">casey@csc.co.za</A> </P>
|
||||
|
||||
<P><BR>
|
||||
</P>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
@ -1,141 +0,0 @@
|
||||
<html><head<title>
|
||||
Network Time Protocol Year 2000 Conformance Statement
|
||||
</title></head><body><h3>
|
||||
Network Time Protocol Year 2000 Conformance Statement
|
||||
</h3>
|
||||
|
||||
<img align=left src=pic/alice15.gif>
|
||||
from <i>Alice's Adventures in Wonderland</i>, by Lewis Carroll,
|
||||
illustrations by Sir John Tenniel
|
||||
|
||||
<p>The Mad Hatter and the March Hare are discussing whether the Teapot
|
||||
serial number should have two or four digits.
|
||||
|
||||
<br clear=left><hr>
|
||||
|
||||
<h4>Introduction</h4>
|
||||
|
||||
By the year 2000, the Network Time Protocol (NTP) will have been in
|
||||
use for over two decades and remain the longest running, continuously
|
||||
operating application protocol in the Internet. There is some concern,
|
||||
especially in government and financial institutions, that NTP might
|
||||
cause Internet applications to misbehave in terrible ways on the epoch
|
||||
of the next century. This document presents an analysis of the various
|
||||
hazards that might result in incorrect time values upon this epoch. It
|
||||
concludes that incorrect time values due to the NTP timescale, protocol
|
||||
design and reference implementation are highly unlikely. However, it is
|
||||
possible that external reference time sources used by NTP could
|
||||
misbehave and cause NTP servers to distribute incorrect time values to
|
||||
significant portions of the Internet. Note that, while this document
|
||||
addresses the issues specifically with respect to Unix systems, the
|
||||
issues are equally applicable to Windows and VMS systems.
|
||||
|
||||
<h4>The NTP Timescale</h4>
|
||||
|
||||
It will be helpful in understanding the issues raised in this document
|
||||
to consider the concept of a universal timescale. The conventional civil
|
||||
timescale used in most parts of the world is based on Universal
|
||||
Coordinated Time (UTC sic), formerly known as Greenwich Mean Time (GMT).
|
||||
UTC is based on International Atomic Time (TAI sic), which is derived
|
||||
from hundreds of cesium clocks in the national standards laboratories of
|
||||
many countries. Deviations of UTC from TAI are implemented in the form
|
||||
of leap seconds, which occur on average every eighteen months. For
|
||||
almost every computer application today, UTC represents the universal
|
||||
timescale extending into the indefinite past and indefinite future. We
|
||||
know of course that the UTC timescale did not exist prior to 1972, the
|
||||
Gregorian calendar did not exist prior to 1582, the Julian calendar did
|
||||
not exist prior to 54 BC and we cannot predict exactly when the next
|
||||
leap second will occur. Nevertheless, most folks would prefer that, even
|
||||
if we can't get future seconds numbering right beyond the next leap
|
||||
second, at least we can get the days numbering right until the end of
|
||||
reason.
|
||||
|
||||
<p>The universal timescale can be implemented using a binary counter of
|
||||
indefinite width and with the unit seconds bit placed somewhere in the
|
||||
middle. The counter is synchronized to UTC such that it runs at the same
|
||||
rate and the units increment coincides with the UTC seconds tick. The
|
||||
NTP timescale is constructed from 64 bits of this counter, of which 32
|
||||
bits number the seconds and 32 bits represent the fraction. With this
|
||||
design, the counter runs in 136-year cycles, called eras, the latest of
|
||||
which began with a counter value of zero at 0h 1 January 1900. The
|
||||
design assumption is that further low order bits, if required, are
|
||||
provided by local interpolation, while further high order bits, when
|
||||
required, are provided by external means. The important point to be made
|
||||
here is that the high order bits must ultimately be provided by
|
||||
astronomers and disseminated to the population by international means.
|
||||
Ultimately, should a need exist to align a particular NTP era to the
|
||||
current calendar, the operating system in which NTP is embedded must
|
||||
provide the necessary high order bits, most conveniently from the file
|
||||
system or flash memory.
|
||||
|
||||
<h4>The Year 2000 Era</h4>
|
||||
|
||||
With respect to the year 2000 issue, the most important thing to observe
|
||||
about the NTP timescale is that it knows nothing about days, years or
|
||||
centuries, only the seconds since the beginning of the latest era, the
|
||||
current one of which began on 1 January 1900. On 1 January 1970 when
|
||||
Unix life began, the NTP timescale showed 2,208,988,800 and on 1 January
|
||||
1972 when UTC life began, it showed 2,272,060,800. On the last second of
|
||||
year 1999, the NTP timescale will show 3,155,672,599 and one second
|
||||
later on the first second of the next century will show 3,155,672,600.
|
||||
Other than this observation, the NTP timescale has no knowledge of or
|
||||
provision for any of these eclectic seconds.
|
||||
|
||||
<p>The NTP timescale is almost never used directly by system or
|
||||
application programs. The generic Unix kernel keeps time in seconds and
|
||||
microseconds (or nanoseconds) to provide both time of day and interval
|
||||
timer functions. In order to synchronize the Unix clock, NTP must
|
||||
convert to and from its representation and Unix representation. Unix
|
||||
kernels implement the time of day function using two 32-bit counters,
|
||||
one representing the seconds since Unix life began and the other the
|
||||
microseconds or nanoseconds of the second. In principle, the seconds
|
||||
counter will wrap around in 136-year eras, the next of which will begin
|
||||
in 2106. How the particular Unix semantics interprets the counter values
|
||||
is of concern, but is beyond the scope of discussion here.
|
||||
|
||||
<p>While incorrect time values due to the NTP timescale and protocol
|
||||
design or reference implementation upon the epoch of the next century
|
||||
are highly unlikely, hazards remain due to incorrect software external
|
||||
to NTP. These hazards include the Unix kernel and library routines which
|
||||
convert Unix time to and from conventional civil time in seconds,
|
||||
minutes, hours, days and years. Although NTP uses these routines to
|
||||
format monitoring data displays, they are not used to read or set the
|
||||
NTP clock. They may in fact cause problems with certain application
|
||||
programs, but this is not an issue which concerns NTP correctness.
|
||||
|
||||
<p>While it is extremely unlikely that NTP will produce incorrect time
|
||||
values upon the epoch, it is possible that some external source to which
|
||||
NTP synchronizes may produce a discontinuity which could then induce a
|
||||
NTP discontinuity. The NTP primary (stratum 1) time servers, which are
|
||||
the ultimate time references for the entire NTP population, obtain time
|
||||
from various sources, including radio and satellite receivers and
|
||||
telephone modems. Not all sources provide year information and not all
|
||||
of these provide time in four-digit form. In point of fact, the NTP
|
||||
reference implementation does not use the year information, even if
|
||||
available. Instead, the year information is provided from the file
|
||||
system, which itself depends on the Unix clock.
|
||||
|
||||
<p>The NTP protocol specification requires the apparent NTP time derived
|
||||
from external servers to be compared to the file system time before the
|
||||
clock is set. If the discrepancy is over 1000 seconds, an error alarm is
|
||||
raised requiring manual intervention. This makes it very unlikely that
|
||||
even a clique of seriously corrupted NTP servers will result in
|
||||
incorrect time values. In the case of embedded computers with no file
|
||||
system, the design assumption is that the current era be established
|
||||
from flash memory or a clock chip previously set by manual means.
|
||||
|
||||
<p>It is essential that any clock synchronization protocol, including
|
||||
NTP, include provisions for multiple-server redundancy and multiple-
|
||||
route diversity. Past experience has demonstrated the wisdom of this
|
||||
approach, which protects clients against hardware and software faults,
|
||||
as well as incorrectly operating reference sources and sometimes even
|
||||
buggy software. For the most reliable service, we recommend multiple
|
||||
reference sources for primary servers, including a backup radio or
|
||||
satellite receiver or telephone modem. We also recommend that primary
|
||||
servers run NTP with other primary servers to provide additional
|
||||
redundancy and mutual backup should the reference sources themselves
|
||||
fail or operate incorrectly.
|
||||
|
||||
<hr><a href=index.htm><img align=left src=pic/home.gif></a><address><a
|
||||
href=mailto:mills@udel.edu> David L. Mills <mills@udel.edu></a>
|
||||
</address></a></body></html>
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* mexit - Used to exit the NTPD daemon
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
HANDLE hServDoneEvent = NULL;
|
||||
|
||||
void
|
||||
service_exit(
|
||||
int status
|
||||
)
|
||||
{
|
||||
extern int debug;
|
||||
|
||||
if (debug) /* did not become a service, simply exit */
|
||||
ExitThread((DWORD)status);
|
||||
else {
|
||||
/* service mode, need to have the service_main routine
|
||||
* register with the service control manager that the
|
||||
* service has stopped running, before exiting
|
||||
*/
|
||||
if ((status > 0) && (hServDoneEvent != NULL))
|
||||
SetEvent(hServDoneEvent);
|
||||
ExitThread((DWORD)status);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* not SYS_WINNT */
|
||||
int mexit_bs;
|
||||
#endif /* not SYS_WINNT */
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_computime.c,v 4.2 1998/07/11 10:05:27 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 09:58:27 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_computime.c"
|
||||
/*
|
||||
* kclk_computime.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:27 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:27 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_dcf7000.c,v 4.2 1998/07/11 10:05:27 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 09:59:11 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_dcf7000.c"
|
||||
/*
|
||||
* kclk_dcf7000.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:27 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:28 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_hopf6021.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 09:59:57 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_hopf6021.c"
|
||||
/*
|
||||
* kclk_hopf6021.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:28 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:29 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_meinberg.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:00:28 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_meinberg.c"
|
||||
/*
|
||||
* kclk_meinberg.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:28 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:29 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_rawdcf.c,v 4.1 1998/06/13 12:07:55 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:03:35 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_rawdcf.c"
|
||||
/*
|
||||
* kclk_rawdcf.c,v
|
||||
* Revision 4.1 1998/06/13 12:07:55 kardel
|
||||
* standard format
|
||||
*
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_rcc8000.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:01:11 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_rcc8000.c"
|
||||
/*
|
||||
* kclk_rcc8000.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:28 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:29 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_schmid.c,v 4.2 1998/07/11 10:05:28 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:01:42 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_schmid.c"
|
||||
/*
|
||||
* kclk_schmid.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:28 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:30 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_trimtaip.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:02:35 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_trimtaip.c"
|
||||
/*
|
||||
* kclk_trimtaip.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:29 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:30 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_trimtsip.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:04:12 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_trimtsip.c"
|
||||
/*
|
||||
* kclk_trimtsip.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:29 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:08:02 kardel
|
||||
* standard format
|
||||
*/
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* $Header: /cvs/ntp/libparse/kclk_varitext.c,v 1.1 1999/07/25 09:21:16 stenn Exp $
|
||||
*
|
||||
* $Created: Sat Jun 13 09:58:27 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_varitext.c"
|
||||
/*
|
||||
* $Log: kclk_varitext.c,v $
|
||||
* Revision 1.1 1999/07/25 09:21:16 stenn
|
||||
* * configure.in: 4.0.94b
|
||||
*
|
||||
* * acconfig.h:
|
||||
* * configure.in:
|
||||
* * libparse/Makefile.am:
|
||||
* * libparse/parse_conf.c:
|
||||
* * libparse/clk_varitext.c:
|
||||
* * libparse/kclk_varitext.c:
|
||||
* * ntpd/refclock_parse.c: VARITEXT parse clock
|
||||
* * ntpdate/ntpdate.c: bugfix
|
||||
* From: Tony McConnell <tonym@datel-technology.co.uk>
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:09:27 kardel
|
||||
* hack to compile the source for kernel/user-land
|
||||
*
|
||||
*/
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kclk_wharton.c,v 4.1 1999/02/28 15:50:08 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sun Feb 28 16:46:14 MET 1999 $
|
||||
*
|
||||
* Copyright (C) 1999 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "clk_wharton.c"
|
||||
/*
|
||||
* kclk_wharton.c,v
|
||||
* Revision 4.1 1999/02/28 15:50:08 kardel
|
||||
* new clock input machine
|
||||
*
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kparse.c,v 4.2 1998/07/11 10:05:29 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:04:47 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "parse.c"
|
||||
/*
|
||||
* kparse.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:29 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:08:12 kardel
|
||||
* standard format
|
||||
*/
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* /src/NTP/ntp-4/libparse/kparse_conf.c,v 4.2 1998/07/11 10:05:30 kardel RELEASE_19990228_A
|
||||
*
|
||||
* $Created: Sat Jun 13 10:05:32 1998 $
|
||||
*
|
||||
* Copyright (C) 1998 by Frank Kardel
|
||||
*/
|
||||
#define PARSESTREAM
|
||||
#include "parse_conf.c"
|
||||
/*
|
||||
* kparse_conf.c,v
|
||||
* Revision 4.2 1998/07/11 10:05:30 kardel
|
||||
* Release 4.0.73d reconcilation
|
||||
*
|
||||
* Revision 4.1 1998/06/13 12:08:12 kardel
|
||||
* standard format
|
||||
*/
|
@ -1,987 +0,0 @@
|
||||
/*
|
||||
** Ancestor was ripped off from ../ntpres/ntpres.c by Greg Troxel 4/2/92
|
||||
**
|
||||
** The previous resolver only needed to do forward lookups, and all names
|
||||
** were known before we started the resolver process.
|
||||
**
|
||||
** The new code must be able to handle reverse lookups, and the requests can
|
||||
** show up at any time.
|
||||
**
|
||||
** Here's the drill for the new logic.
|
||||
**
|
||||
** We want to be able to do forward or reverse lookups. Forward lookups
|
||||
** require one set of information to be sent back to the daemon, reverse
|
||||
** lookups require a different set of information. The caller knows this.
|
||||
**
|
||||
** The daemon must not block. This includes communicating with the resolver
|
||||
** process (if the resolver process is a separate task).
|
||||
**
|
||||
** Current resolver code blocks waiting for the response, so the
|
||||
** alternatives are:
|
||||
**
|
||||
** - Find a nonblocking resolver library
|
||||
** - Do each (initial) lookup in a separate process
|
||||
** - - subsequent lookups *could* be handled by a different process that has
|
||||
** a queue of pending requests
|
||||
**
|
||||
** We could use nonblocking lookups in a separate process (just to help out
|
||||
** with timers).
|
||||
**
|
||||
** If we don't have nonblocking resolver calls we have more opportunities
|
||||
** for denial-of-service problems.
|
||||
**
|
||||
** - too many fork()s
|
||||
** - communications path
|
||||
**
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ntpd.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_request.h"
|
||||
#include "ntp_stdlib.h"
|
||||
#include "ntp_syslog.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
|
||||
|
||||
/*
|
||||
* Each item we are to resolve and configure gets one of these
|
||||
* structures defined for it.
|
||||
*/
|
||||
struct dns_entry {
|
||||
int de_done;
|
||||
#define DE_NAME 001
|
||||
#define DE_ADDR 002
|
||||
#define DE_NA (DE_NAME | DE_ADDR)
|
||||
#define DE_PENDING 000
|
||||
#define DE_GOT 010
|
||||
#define DE_FAIL 020
|
||||
#define DE_RESULT (DE_PENDING | DE_GOT | DE_FAIL)
|
||||
struct dns_entry *de_next;
|
||||
struct info_dns_assoc de_info; /* DNS info for peer */
|
||||
};
|
||||
#define de_associd de_info.associd
|
||||
#define de_peeraddr de_info.peeraddr
|
||||
#define de_hostname de_info.hostname
|
||||
|
||||
/*
|
||||
* dns_entries is a pointer to the list of configuration entries
|
||||
* we have left to do.
|
||||
*/
|
||||
static struct dns_entry *dns_entries = NULL;
|
||||
|
||||
/*
|
||||
* We take an interrupt every thirty seconds, at which time we decrement
|
||||
* config_timer and resolve_timer. The former is set to 2, so we retry
|
||||
* unsucessful reconfigurations every minute. The latter is set to
|
||||
* an exponentially increasing value which starts at 2 and increases to
|
||||
* 32. When this expires we retry failed name resolutions.
|
||||
*
|
||||
* We sleep SLEEPTIME seconds before doing anything, to give the server
|
||||
* time to arrange itself.
|
||||
*/
|
||||
#define MINRESOLVE 2
|
||||
#define MAXRESOLVE 32
|
||||
#define CONFIG_TIME 2
|
||||
#define ALARM_TIME 30
|
||||
|
||||
#define SLEEPTIME 2
|
||||
|
||||
static volatile int config_timer = 0;
|
||||
static volatile int resolve_timer = 0;
|
||||
|
||||
static int resolve_value; /* next value of resolve timer */
|
||||
|
||||
/*
|
||||
* Big hack attack
|
||||
*/
|
||||
#define LOCALHOST 0x7f000001 /* 127.0.0.1, in hex, of course */
|
||||
#define SKEWTIME 0x08000000 /* 0.03125 seconds as a l_fp fraction */
|
||||
|
||||
/*
|
||||
* Select time out. Set to 2 seconds. The server is on the local machine,
|
||||
* after all.
|
||||
*/
|
||||
#define TIMEOUT_SEC 2
|
||||
#define TIMEOUT_USEC 0
|
||||
|
||||
/*
|
||||
* File descriptor for ntp request code.
|
||||
*/
|
||||
static int sockfd = -1;
|
||||
|
||||
/*
|
||||
* Pipe descriptors
|
||||
*/
|
||||
int p_fd[2] = { -1, -1 };
|
||||
|
||||
/* stuff to be filled in by caller */
|
||||
|
||||
extern keyid_t req_keyid; /* request keyid */
|
||||
|
||||
/* end stuff to be filled in */
|
||||
|
||||
void ntp_res P((void));
|
||||
static RETSIGTYPE bong P((int));
|
||||
static void checkparent P((void));
|
||||
static void removeentry P((struct dns_entry *));
|
||||
static void addentry P((char *, u_int32, u_short));
|
||||
static void findhostaddr P((struct dns_entry *));
|
||||
static void openntp P((void));
|
||||
static int tell_ntpd P((struct info_dns_assoc *));
|
||||
static void doconfigure P((int));
|
||||
|
||||
struct ntp_res_t_pkt { /* Tagged packet: */
|
||||
void *tag; /* For the caller */
|
||||
u_int32 paddr; /* IP to look up, or 0 */
|
||||
char name[NTP_MAXHOSTNAME]; /* Name to look up (if 1st byte is not 0) */
|
||||
};
|
||||
|
||||
struct ntp_res_c_pkt { /* Control packet: */
|
||||
char name[NTP_MAXHOSTNAME];
|
||||
u_int32 paddr;
|
||||
int mode;
|
||||
int version;
|
||||
int minpoll;
|
||||
int maxpoll;
|
||||
int flags;
|
||||
int ttl;
|
||||
keyid_t keyid;
|
||||
u_char keystr[MAXFILENAME];
|
||||
};
|
||||
|
||||
/*
|
||||
* ntp_res_name
|
||||
*/
|
||||
|
||||
void
|
||||
ntp_res_name(
|
||||
u_int32 paddr, /* Address to resolve */
|
||||
u_short associd /* Association ID */
|
||||
)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
/*
|
||||
* fork.
|
||||
* - parent returns
|
||||
* - child stuffs data and calls ntp_res()
|
||||
*/
|
||||
|
||||
for (pid = -1; pid == -1;) {
|
||||
#ifdef RES_TEST
|
||||
pid = 0;
|
||||
#else
|
||||
pid = fork();
|
||||
#endif
|
||||
if (pid == -1) {
|
||||
msyslog(LOG_ERR, "ntp_res_name: fork() failed: %m");
|
||||
sleep(2);
|
||||
}
|
||||
}
|
||||
switch (pid) {
|
||||
case -1: /* Error */
|
||||
msyslog(LOG_INFO, "ntp_res_name: error...");
|
||||
/* Can't happen */
|
||||
break;
|
||||
|
||||
case 0: /* Child */
|
||||
closelog();
|
||||
kill_asyncio();
|
||||
(void) signal_no_reset(SIGCHLD, SIG_DFL);
|
||||
#ifndef LOG_DAEMON
|
||||
openlog("ntp_res", LOG_PID);
|
||||
# else /* LOG_DAEMON */
|
||||
# ifndef LOG_NTP
|
||||
# define LOG_NTP LOG_DAEMON
|
||||
# endif
|
||||
openlog("ntp_res_name", LOG_PID | LOG_NDELAY, LOG_NTP);
|
||||
#endif
|
||||
|
||||
addentry(NULL, paddr, associd);
|
||||
ntp_res();
|
||||
break;
|
||||
|
||||
default: /* Parent */
|
||||
/* Nothing to do. (In Real Life, this never happens.) */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ntp_res needs;
|
||||
*
|
||||
* req_key(???), req_keyid valid
|
||||
* syslog still open
|
||||
*/
|
||||
|
||||
void
|
||||
ntp_res(void)
|
||||
{
|
||||
#ifdef HAVE_SIGSUSPEND
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
#endif /* HAVE_SIGSUSPEND */
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debug) {
|
||||
msyslog(LOG_INFO, "NTP_RESOLVER running");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check out auth stuff */
|
||||
if (sys_authenticate) {
|
||||
if (!authistrusted(req_keyid)) {
|
||||
msyslog(LOG_ERR, "invalid request keyid %08x",
|
||||
req_keyid );
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a first cut at resolving the bunch
|
||||
*/
|
||||
doconfigure(1);
|
||||
if (dns_entries == NULL) {
|
||||
if (debug) {
|
||||
msyslog(LOG_INFO, "NTP_RESOLVER done!");
|
||||
}
|
||||
#if defined SYS_WINNT
|
||||
ExitThread(0); /* Don't want to kill whole NT process */
|
||||
#else
|
||||
exit(0); /* done that quick */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we've got some problem children. Set up the timer
|
||||
* and wait for it.
|
||||
*/
|
||||
resolve_value = resolve_timer = MINRESOLVE;
|
||||
config_timer = CONFIG_TIME;
|
||||
#ifndef SYS_WINNT
|
||||
(void) signal_no_reset(SIGALRM, bong);
|
||||
alarm(ALARM_TIME);
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
for (;;) {
|
||||
if (dns_entries == NULL)
|
||||
exit(0);
|
||||
|
||||
checkparent();
|
||||
|
||||
if (resolve_timer == 0) {
|
||||
if (resolve_value < MAXRESOLVE)
|
||||
resolve_value <<= 1;
|
||||
resolve_timer = resolve_value;
|
||||
#ifdef DEBUG
|
||||
msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
|
||||
#endif
|
||||
config_timer = CONFIG_TIME;
|
||||
doconfigure(1);
|
||||
continue;
|
||||
} else if (config_timer == 0) {
|
||||
config_timer = CONFIG_TIME;
|
||||
#ifdef DEBUG
|
||||
msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
|
||||
#endif
|
||||
doconfigure(0);
|
||||
continue;
|
||||
}
|
||||
#ifndef SYS_WINNT
|
||||
/*
|
||||
* There is a race in here. Is okay, though, since
|
||||
* all it does is delay things by 30 seconds.
|
||||
*/
|
||||
# ifdef HAVE_SIGSUSPEND
|
||||
sigsuspend(&set);
|
||||
# else
|
||||
sigpause(0);
|
||||
# endif /* HAVE_SIGSUSPEND */
|
||||
#else
|
||||
if (config_timer > 0)
|
||||
config_timer--;
|
||||
if (resolve_timer > 0)
|
||||
resolve_timer--;
|
||||
sleep(ALARM_TIME);
|
||||
#endif /* SYS_WINNT */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
/*
|
||||
* bong - service and reschedule an alarm() interrupt
|
||||
*/
|
||||
static RETSIGTYPE
|
||||
bong(
|
||||
int sig
|
||||
)
|
||||
{
|
||||
if (config_timer > 0)
|
||||
config_timer--;
|
||||
if (resolve_timer > 0)
|
||||
resolve_timer--;
|
||||
alarm(ALARM_TIME);
|
||||
}
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
/*
|
||||
* checkparent - see if our parent process is still running
|
||||
*
|
||||
* No need to worry in the Windows NT environment whether the
|
||||
* main thread is still running, because if it goes
|
||||
* down it takes the whole process down with it (in
|
||||
* which case we won't be running this thread either)
|
||||
* Turn function into NOP;
|
||||
*/
|
||||
|
||||
static void
|
||||
checkparent(void)
|
||||
{
|
||||
#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS)
|
||||
|
||||
/*
|
||||
* If our parent (the server) has died we will have been
|
||||
* inherited by init. If so, exit.
|
||||
*/
|
||||
if (getppid() == 1) {
|
||||
msyslog(LOG_INFO, "parent died before we finished, exiting");
|
||||
exit(0);
|
||||
}
|
||||
#endif /* SYS_WINNT && SYS_VXWORKS*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* removeentry - we are done with an entry, remove it from the list
|
||||
*/
|
||||
static void
|
||||
removeentry(
|
||||
struct dns_entry *entry
|
||||
)
|
||||
{
|
||||
register struct dns_entry *de;
|
||||
|
||||
de = dns_entries;
|
||||
if (de == entry) {
|
||||
dns_entries = de->de_next;
|
||||
return;
|
||||
}
|
||||
|
||||
while (de != NULL) {
|
||||
if (de->de_next == entry) {
|
||||
de->de_next = entry->de_next;
|
||||
return;
|
||||
}
|
||||
de = de->de_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* addentry - add an entry to the configuration list
|
||||
*/
|
||||
static void
|
||||
addentry(
|
||||
char *name,
|
||||
u_int32 paddr,
|
||||
u_short associd
|
||||
)
|
||||
{
|
||||
register struct dns_entry *de;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debug > 1) {
|
||||
struct in_addr si;
|
||||
|
||||
si.s_addr = paddr;
|
||||
msyslog(LOG_INFO,
|
||||
"ntp_res_name: <%s> %s associd %d\n",
|
||||
(name) ? name : "", inet_ntoa(si), associd);
|
||||
}
|
||||
#endif
|
||||
|
||||
de = (struct dns_entry *)emalloc(sizeof(struct dns_entry));
|
||||
if (name) {
|
||||
strncpy(de->de_hostname, name, sizeof de->de_hostname);
|
||||
de->de_done = DE_PENDING | DE_ADDR;
|
||||
} else {
|
||||
de->de_hostname[0] = 0;
|
||||
de->de_done = DE_PENDING | DE_NAME;
|
||||
}
|
||||
de->de_peeraddr = paddr;
|
||||
de->de_associd = associd;
|
||||
de->de_next = NULL;
|
||||
|
||||
if (dns_entries == NULL) {
|
||||
dns_entries = de;
|
||||
} else {
|
||||
register struct dns_entry *dep;
|
||||
|
||||
for (dep = dns_entries; dep->de_next != NULL;
|
||||
dep = dep->de_next)
|
||||
/* nothing */;
|
||||
dep->de_next = de;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* findhostaddr - resolve a host name into an address (Or vice-versa)
|
||||
*
|
||||
* sets entry->de_done appropriately when we're finished. We're finished if
|
||||
* we either successfully look up the missing name or address, or if we get a
|
||||
* "permanent" failure on the lookup.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
findhostaddr(
|
||||
struct dns_entry *entry
|
||||
)
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
checkparent(); /* make sure our guy is still running */
|
||||
|
||||
/*
|
||||
* The following should never trip - this subroutine isn't
|
||||
* called if hostname and peeraddr are "filled".
|
||||
*/
|
||||
if (entry->de_hostname[0] && entry->de_peeraddr) {
|
||||
struct in_addr si;
|
||||
|
||||
si.s_addr = entry->de_peeraddr;
|
||||
msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are defined: <%s>/%s: state %#x",
|
||||
&entry->de_hostname[0], inet_ntoa(si), entry->de_done);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following should never trip.
|
||||
*/
|
||||
if (!entry->de_hostname[0] && !entry->de_peeraddr) {
|
||||
msyslog(LOG_ERR, "findhostaddr: both de_hostname and de_peeraddr are undefined!");
|
||||
entry->de_done |= DE_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry->de_hostname[0]) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 2)
|
||||
msyslog(LOG_INFO, "findhostaddr: Resolving <%s>",
|
||||
&entry->de_hostname[0]);
|
||||
#endif /* DEBUG */
|
||||
hp = gethostbyname(&entry->de_hostname[0]);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
if (debug > 2) {
|
||||
struct in_addr si;
|
||||
|
||||
si.s_addr = entry->de_peeraddr;
|
||||
msyslog(LOG_INFO, "findhostaddr: Resolving %s",
|
||||
inet_ntoa(si));
|
||||
}
|
||||
#endif
|
||||
hp = gethostbyaddr((const char *)&entry->de_peeraddr,
|
||||
sizeof entry->de_peeraddr,
|
||||
AF_INET);
|
||||
}
|
||||
|
||||
if (hp == NULL) {
|
||||
/*
|
||||
* Bail if we should TRY_AGAIN.
|
||||
* Otherwise, we have a permanent failure.
|
||||
*/
|
||||
if (h_errno == TRY_AGAIN)
|
||||
return;
|
||||
entry->de_done |= DE_FAIL;
|
||||
} else {
|
||||
entry->de_done |= DE_GOT;
|
||||
}
|
||||
|
||||
if (entry->de_done & DE_GOT) {
|
||||
switch (entry->de_done & DE_NA) {
|
||||
case DE_NAME:
|
||||
#ifdef DEBUG
|
||||
if (debug > 2)
|
||||
msyslog(LOG_INFO,
|
||||
"findhostaddr: name resolved.");
|
||||
#endif
|
||||
/*
|
||||
* Use the first address. We don't have any way to
|
||||
* tell preferences and older gethostbyname()
|
||||
* implementations only return one.
|
||||
*/
|
||||
memmove((char *)&(entry->de_peeraddr),
|
||||
(char *)hp->h_addr,
|
||||
sizeof(struct in_addr));
|
||||
break;
|
||||
case DE_ADDR:
|
||||
#ifdef DEBUG
|
||||
if (debug > 2)
|
||||
msyslog(LOG_INFO,
|
||||
"findhostaddr: address resolved.");
|
||||
#endif
|
||||
strncpy(&entry->de_hostname[0], hp->h_name,
|
||||
sizeof entry->de_hostname);
|
||||
break;
|
||||
default:
|
||||
msyslog(LOG_ERR, "findhostaddr: Bogus de_done: %#x",
|
||||
entry->de_done);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
if (debug > 2) {
|
||||
struct in_addr si;
|
||||
const char *hes;
|
||||
#ifndef HAVE_HSTRERROR
|
||||
char hnum[20];
|
||||
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
hes = "Authoritive Answer Host not found";
|
||||
break;
|
||||
case TRY_AGAIN:
|
||||
hes = "Non-Authoritative Host not found, or SERVERFAIL";
|
||||
break;
|
||||
case NO_RECOVERY:
|
||||
hes = "Non recoverable errors, FORMERR, REFUSED, NOTIMP";
|
||||
break;
|
||||
case NO_DATA:
|
||||
hes = "Valid name, no data record of requested type";
|
||||
break;
|
||||
default:
|
||||
snprintf(hnum, sizeof hnum, "%d", h_errno);
|
||||
hes = hnum;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
hes = hstrerror(h_errno);
|
||||
#endif
|
||||
|
||||
si.s_addr = entry->de_peeraddr;
|
||||
msyslog(LOG_INFO,
|
||||
"findhostaddr: Failed resolution on <%s>/%s: %s",
|
||||
entry->de_hostname, inet_ntoa(si), hes);
|
||||
}
|
||||
#endif
|
||||
/* Send a NAK message back to the daemon */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* openntp - open a socket to the ntp server
|
||||
*/
|
||||
static void
|
||||
openntp(void)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
|
||||
if (sockfd >= 0)
|
||||
return;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == -1) {
|
||||
msyslog(LOG_ERR, "socket() failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset((char *)&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(NTP_PORT); /* trash */
|
||||
saddr.sin_addr.s_addr = htonl(LOCALHOST); /* garbage */
|
||||
|
||||
/*
|
||||
* Make the socket non-blocking. We'll wait with select()
|
||||
*/
|
||||
#ifndef SYS_WINNT
|
||||
# if defined(O_NONBLOCK)
|
||||
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
# else
|
||||
# if defined(FNDELAY)
|
||||
if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
|
||||
msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
# else
|
||||
# include "Bletch: NEED NON BLOCKING IO"
|
||||
# endif /* FNDDELAY */
|
||||
# endif /* O_NONBLOCK */
|
||||
#else /* SYS_WINNT */
|
||||
{
|
||||
int on = 1;
|
||||
|
||||
if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) {
|
||||
msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
|
||||
exit(1); /* Windows NT - set socket in non-blocking mode */
|
||||
}
|
||||
}
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
|
||||
msyslog(LOG_ERR, "openntp: connect() failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* tell_ntpd: Tell ntpd what we discovered.
|
||||
*/
|
||||
static int
|
||||
tell_ntpd(
|
||||
struct info_dns_assoc *conf
|
||||
)
|
||||
{
|
||||
fd_set fdset;
|
||||
struct timeval tvout;
|
||||
struct req_pkt reqpkt;
|
||||
l_fp ts;
|
||||
int n;
|
||||
#ifdef SYS_WINNT
|
||||
HANDLE hReadWriteEvent = NULL;
|
||||
BOOL ret;
|
||||
DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait;
|
||||
OVERLAPPED overlap;
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
checkparent(); /* make sure our guy is still running */
|
||||
|
||||
if (sockfd < 0)
|
||||
openntp();
|
||||
|
||||
#ifdef SYS_WINNT
|
||||
hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
/*
|
||||
* Try to clear out any previously received traffic so it
|
||||
* doesn't fool us. Note the socket is nonblocking.
|
||||
*/
|
||||
tvout.tv_sec = 0;
|
||||
tvout.tv_usec = 0;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sockfd, &fdset);
|
||||
while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
|
||||
0) {
|
||||
recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sockfd, &fdset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make up a request packet with the configuration info
|
||||
*/
|
||||
memset((char *)&reqpkt, 0, sizeof(reqpkt));
|
||||
|
||||
reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
|
||||
reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */
|
||||
reqpkt.implementation = IMPL_XNTPD; /* local implementation */
|
||||
reqpkt.request = REQ_HOSTNAME_ASSOCID; /* Hostname for associd */
|
||||
reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */
|
||||
reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct info_dns_assoc));
|
||||
memmove(reqpkt.data, (char *)conf, sizeof(struct info_dns_assoc));
|
||||
reqpkt.keyid = htonl(req_keyid);
|
||||
|
||||
get_systime(&ts);
|
||||
L_ADDUF(&ts, SKEWTIME);
|
||||
HTONL_FP(&ts, &reqpkt.tstamp);
|
||||
n = 0;
|
||||
if (sys_authenticate)
|
||||
n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC);
|
||||
|
||||
/*
|
||||
* Done. Send it.
|
||||
*/
|
||||
#ifndef SYS_WINNT
|
||||
n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0);
|
||||
if (n < 0) {
|
||||
msyslog(LOG_ERR, "send to NTP server failed: %m");
|
||||
return 0; /* maybe should exit */
|
||||
}
|
||||
#else
|
||||
/* In the NT world, documentation seems to indicate that there
|
||||
* exist _write and _read routines that can be used to do blocking
|
||||
* I/O on sockets. Problem is these routines require a socket
|
||||
* handle obtained through the _open_osf_handle C run-time API
|
||||
* of which there is no explanation in the documentation. We need
|
||||
* nonblocking write's and read's anyway for our purpose here.
|
||||
* We're therefore forced to deviate a little bit from the Unix
|
||||
* model here and use the ReadFile and WriteFile Win32 I/O API's
|
||||
* on the socket
|
||||
*/
|
||||
overlap.Offset = overlap.OffsetHigh = (DWORD)0;
|
||||
overlap.hEvent = hReadWriteEvent;
|
||||
ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n,
|
||||
(LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap);
|
||||
if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
|
||||
msyslog(LOG_ERR, "send to NTP server failed: %m");
|
||||
return 0;
|
||||
}
|
||||
dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
|
||||
if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
|
||||
if (dwWait == WAIT_FAILED)
|
||||
msyslog(LOG_ERR, "WaitForSingleObject failed: %m");
|
||||
return 0;
|
||||
}
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
|
||||
/*
|
||||
* Wait for a response. A weakness of the mode 7 protocol used
|
||||
* is that there is no way to associate a response with a
|
||||
* particular request, i.e. the response to this configuration
|
||||
* request is indistinguishable from that to any other. I should
|
||||
* fix this some day. In any event, the time out is fairly
|
||||
* pessimistic to make sure that if an answer is coming back
|
||||
* at all, we get it.
|
||||
*/
|
||||
for (;;) {
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sockfd, &fdset);
|
||||
tvout.tv_sec = TIMEOUT_SEC;
|
||||
tvout.tv_usec = TIMEOUT_USEC;
|
||||
|
||||
n = select(sockfd + 1, &fdset, (fd_set *)0,
|
||||
(fd_set *)0, &tvout);
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
msyslog(LOG_ERR, "select() fails: %m");
|
||||
return 0;
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
if(debug)
|
||||
msyslog(LOG_INFO, "select() returned 0.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
|
||||
if (n <= 0) {
|
||||
if (n < 0) {
|
||||
msyslog(LOG_ERR, "recv() fails: %m");
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#else /* Overlapped I/O used on non-blocking sockets on Windows NT */
|
||||
ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC,
|
||||
(LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap);
|
||||
if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
|
||||
msyslog(LOG_ERR, "ReadFile() fails: %m");
|
||||
return 0;
|
||||
}
|
||||
dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
|
||||
if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
|
||||
if (dwWait == WAIT_FAILED) {
|
||||
msyslog(LOG_ERR, "WaitForSingleObject fails: %m");
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
n = NumberOfBytesRead;
|
||||
#endif /* SYS_WINNT */
|
||||
|
||||
/*
|
||||
* Got one. Check through to make sure it is what
|
||||
* we expect.
|
||||
*/
|
||||
if (n < RESP_HEADER_SIZE) {
|
||||
msyslog(LOG_ERR, "received runt response (%d octets)",
|
||||
n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ISRESPONSE(reqpkt.rm_vn_mode)) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO, "received non-response packet");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ISMORE(reqpkt.rm_vn_mode)) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO, "received fragmented packet");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2)
|
||||
|| (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION))
|
||||
|| INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO,
|
||||
"version (%d/%d) or mode (%d/%d) incorrect",
|
||||
INFO_VERSION(reqpkt.rm_vn_mode),
|
||||
NTP_VERSION,
|
||||
INFO_MODE(reqpkt.rm_vn_mode),
|
||||
MODE_PRIVATE);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (INFO_SEQ(reqpkt.auth_seq) != 0) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO,
|
||||
"nonzero sequence number (%d)",
|
||||
INFO_SEQ(reqpkt.auth_seq));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reqpkt.implementation != IMPL_XNTPD ||
|
||||
reqpkt.request != REQ_HOSTNAME_ASSOCID) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO,
|
||||
"implementation (%d/%d) or request (%d/%d) incorrect",
|
||||
reqpkt.implementation, IMPL_XNTPD,
|
||||
reqpkt.request, REQ_HOSTNAME_ASSOCID);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (INFO_NITEMS(reqpkt.err_nitems) != 0 ||
|
||||
INFO_MBZ(reqpkt.mbz_itemsize) != 0 ||
|
||||
INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1)
|
||||
msyslog(LOG_INFO,
|
||||
"nitems (%d) mbz (%d) or itemsize (%d) nonzero",
|
||||
INFO_NITEMS(reqpkt.err_nitems),
|
||||
INFO_MBZ(reqpkt.mbz_itemsize),
|
||||
INFO_ITEMSIZE(reqpkt.mbz_itemsize));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
n = INFO_ERR(reqpkt.err_nitems);
|
||||
switch (n) {
|
||||
case INFO_OKAY:
|
||||
/* success */
|
||||
return 1;
|
||||
|
||||
case INFO_ERR_IMPL:
|
||||
msyslog(LOG_ERR,
|
||||
"server reports implementation mismatch!!");
|
||||
return 0;
|
||||
|
||||
case INFO_ERR_REQ:
|
||||
msyslog(LOG_ERR,
|
||||
"server claims configuration request is unknown");
|
||||
return 0;
|
||||
|
||||
case INFO_ERR_FMT:
|
||||
msyslog(LOG_ERR,
|
||||
"server indicates a format error occurred(!!)");
|
||||
return 0;
|
||||
|
||||
case INFO_ERR_NODATA:
|
||||
msyslog(LOG_ERR,
|
||||
"server indicates no data available (shouldn't happen)");
|
||||
return 0;
|
||||
|
||||
case INFO_ERR_AUTH:
|
||||
msyslog(LOG_ERR,
|
||||
"server returns a permission denied error");
|
||||
return 0;
|
||||
|
||||
default:
|
||||
msyslog(LOG_ERR,
|
||||
"server returns unknown error code %d", n);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* doconfigure - attempt to resolve names/addresses
|
||||
*/
|
||||
static void
|
||||
doconfigure(
|
||||
int dores
|
||||
)
|
||||
{
|
||||
register struct dns_entry *de;
|
||||
register struct dns_entry *deremove;
|
||||
char *done_msg = "";
|
||||
|
||||
de = dns_entries;
|
||||
while (de != NULL) {
|
||||
#ifdef DEBUG
|
||||
if (debug > 1) {
|
||||
struct in_addr si;
|
||||
|
||||
si.s_addr = de->de_peeraddr;
|
||||
msyslog(LOG_INFO,
|
||||
"doconfigure: name: <%s> peeraddr: %s",
|
||||
de->de_hostname, inet_ntoa(si));
|
||||
}
|
||||
#endif
|
||||
if (dores && (de->de_hostname[0] == 0 || de->de_peeraddr == 0)) {
|
||||
findhostaddr(de);
|
||||
}
|
||||
|
||||
switch (de->de_done & DE_RESULT) {
|
||||
case DE_PENDING:
|
||||
done_msg = "";
|
||||
break;
|
||||
case DE_GOT:
|
||||
done_msg = "succeeded";
|
||||
break;
|
||||
case DE_FAIL:
|
||||
done_msg = "failed";
|
||||
break;
|
||||
default:
|
||||
done_msg = "(error - shouldn't happen)";
|
||||
break;
|
||||
}
|
||||
if (done_msg[0]) {
|
||||
/* Send the answer */
|
||||
if (tell_ntpd(&de->de_info)) {
|
||||
struct in_addr si;
|
||||
|
||||
si.s_addr = de->de_peeraddr;
|
||||
#ifdef DEBUG
|
||||
if (debug > 1) {
|
||||
msyslog(LOG_INFO,
|
||||
"DNS resolution on <%s>/%s %s",
|
||||
de->de_hostname, inet_ntoa(si),
|
||||
done_msg);
|
||||
}
|
||||
#endif
|
||||
deremove = de;
|
||||
de = deremove->de_next;
|
||||
removeentry(deremove);
|
||||
}
|
||||
} else {
|
||||
de = de->de_next;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#! /usr/local/bin/perl
|
||||
#
|
||||
# drift of 104.8576 -> +1 tick. Base of 10000 ticks.
|
||||
#
|
||||
# 970306 HMS Deal with nanoseconds. Fix sign of adjustments.
|
||||
|
||||
$df="/etc/ntp.drift";
|
||||
# Assumes a 100Hz box with "tick" of 10000
|
||||
# Someday, we might call "tickadj" for better values...
|
||||
$base=10000; # tick: 1,000,000 / HZ
|
||||
$cvt=104.8576; # 2 ** 20 / $base
|
||||
$v1=0.;
|
||||
$v2="";
|
||||
|
||||
if (open(DF, $df))
|
||||
{
|
||||
if ($_=<DF>)
|
||||
{
|
||||
($v1, $v2) = split;
|
||||
}
|
||||
|
||||
while ($v1 < 0)
|
||||
{
|
||||
$v1 += $cvt;
|
||||
$base--;
|
||||
}
|
||||
|
||||
while ($v1 > $cvt)
|
||||
{
|
||||
$v1 -= $cvt;
|
||||
$base++;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%.3f (drift)\n", $v1);
|
||||
|
||||
printf("%d usec; %d nsec\n", $base, ($base + ($v1/$cvt)) * 1000);
|
||||
|
@ -1,79 +0,0 @@
|
||||
#!/usr/local/bin/perl
|
||||
#!/usr/local/bin/perl -d
|
||||
#
|
||||
# This script compares the time of several machines with the
|
||||
# time on the local host.
|
||||
#
|
||||
# Use or modify it as you wish.
|
||||
#
|
||||
# As the original author is only expecting 14 minutes of fame,
|
||||
# leaving his name attached would be appreciated.
|
||||
#
|
||||
# R. Gary Cutbill <rgary@chrysalis.com>
|
||||
# 21 April 1999
|
||||
#
|
||||
$tol=2.0;
|
||||
$|=1;
|
||||
print "Time Check";
|
||||
|
||||
open(HOSTS,"ypcat hosts.byaddr |"); # get a list of hosts from the yp server.
|
||||
|
||||
while ($line=<HOSTS>) { # loop for each host getting the offset compared to localhost
|
||||
($addr,$host,$aliases)=split(/\s+/,$line,3);
|
||||
$res=`/usr/local/bin/ntptrace -m 1 -r 1 -t 1 $host`;
|
||||
print ".";
|
||||
chop $res;
|
||||
push (@results,$res);
|
||||
}
|
||||
print "\n";
|
||||
|
||||
|
||||
#
|
||||
# Sort the list of hosts, and print out there offsets
|
||||
# from the local host.
|
||||
#
|
||||
@list=sort appropriately @results;
|
||||
foreach $i ( @list ) {
|
||||
|
||||
@dargs=split(/\s+/,$i);
|
||||
if ( $dargs[1] eq "\*Timeout\*" ) {
|
||||
print "$i\n";
|
||||
chop $dargs[0];
|
||||
push(@down,$dargs[0]);
|
||||
} else {
|
||||
printf "%-25s %7s %3s %6s %10s %5s %8s %8s\n",@dargs;
|
||||
if ( ( $dargs[4] > $tol ) || ( $dargs[4] < -$tol ) ) {
|
||||
chop $dargs[0];
|
||||
push(@toofarout,$dargs[0]); }
|
||||
}
|
||||
}
|
||||
#
|
||||
# When the above list finishes, hosts that are different by +/- $tol (two seconds)
|
||||
# are in @toofarout. Hosts that are down are in @down. They are treated the same
|
||||
# way here, but you might want to do something different depending on your site.
|
||||
#
|
||||
# print a set of suggested rsh commands to run on the hosts that
|
||||
# don't have "good" time. "restartntp" is left as an excersize to the reader.
|
||||
# I usually use it to kill a running xntpd, ntpdate some server, and the start xntp
|
||||
# again.
|
||||
#
|
||||
print "\nConsider:\n";
|
||||
foreach $i ( (@down,@toofarout) ) {
|
||||
print " rsh $i sudo restartntp\n";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# sort the results from the list. First by stratum, then by time deviation
|
||||
# Put hosts that didn't respond (timed out) on the bottom.
|
||||
#
|
||||
sub appropriately {
|
||||
@af=split(/\s+/,$a);
|
||||
@bf=split(/\s+/,$b);
|
||||
$aba= ($af[4]<0)?-$af[4]:$af[4];
|
||||
$abb= ($bf[4]<0)?-$bf[4]:$bf[4];
|
||||
|
||||
( $af[1] ne $bf[1] ) ? $bf[1] cmp $af[1] :
|
||||
( ( $af[2] != $bf[2] ) ? ( $bf[2] <=> $af[2] ) :
|
||||
( ( $aba != $abb ) ? ( $abb <=> $aba ) : ($af[0] cmp $bf[0] ) ) );
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
die "perl5 needed\n" unless ($] > 5);
|
||||
|
||||
use Getopt::Std;
|
||||
use vars qw($opt_n);
|
||||
|
||||
getopts('d:nt:');
|
||||
|
||||
#chop($ncpu = `sysctl -n hw.ncpu`);
|
||||
#die "Found $ncpu CPUs; can only be run on systems with 1 CPU.\n" if ($ncpu > 1);
|
||||
|
||||
$driftfile = "/etc/ntp.drift";
|
||||
$driftfile = $opt_d if defined($opt_d);
|
||||
|
||||
chop($timer = `sysctl -n kern.timecounter.hardware 2> /dev/null`);
|
||||
|
||||
$timer =~ tr/\U/\L/;
|
||||
|
||||
if ($timer eq '') {
|
||||
open(DM, "/var/run/dmesg.boot");
|
||||
while(<DM>) {
|
||||
# Timecounter "i8254" frequency 1193182 Hz
|
||||
if (/^Timecounter "(\w+)"\s+/) {
|
||||
$timer = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close(DM);
|
||||
}
|
||||
|
||||
$opt_t = $timer if !defined($opt_t);
|
||||
|
||||
if ($timer ne '') { # $timer found...
|
||||
if ($opt_t ne '') { # - and $opt_t found
|
||||
if ($timer ne $opt_t) { # - - and they differ
|
||||
warn "You specified a $opt_t timer but I detected a $timer timer.\n";
|
||||
usage();
|
||||
exit 1;
|
||||
} else { # - - and they are the same
|
||||
;
|
||||
}
|
||||
} else { # - but no $opt_t specified; this is OK
|
||||
;
|
||||
}
|
||||
} else { # No $timer found...
|
||||
if ($opt_t ne '') { # - but $opt_t was specified
|
||||
$timer = $opt_t; # - - so use it.
|
||||
} else { # - and neither was $opt_t
|
||||
warn "I can't tell what timer you have. Please specify one.\n";
|
||||
usage();
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
open(DF, $driftfile) || die "Can't open driftfile ($driftfile): $!\n";
|
||||
while(<DF>) {
|
||||
chop;
|
||||
if (/^(-?\d+\.\d+)(\s\d)?$/) {
|
||||
$drift = $1;
|
||||
} else {
|
||||
die "Bogus value in driftfile $driftfile: <$_>\n";
|
||||
}
|
||||
}
|
||||
close(DF);
|
||||
|
||||
print "NTP drift is <$drift>\n";
|
||||
|
||||
# Convert from NTP's idea of PPM to a decimal equivalent
|
||||
$freq_adj = int ( $drift * ( 10 ** 6 / 2 ** 20) );
|
||||
print "normalized freq_adj is <$freq_adj>\n";
|
||||
|
||||
$freq_adj = int ( ( $freq_adj - 1 ) / 2 );
|
||||
print "Applying freq_adj of <".-$freq_adj.">\n";
|
||||
|
||||
$sysctl = "machdep.".$timer."_freq";
|
||||
|
||||
chop($mach_freq = `sysctl -n $sysctl`);
|
||||
|
||||
print "$sysctl is <$mach_freq>\n";
|
||||
|
||||
$n_mach_freq = $mach_freq - $freq_adj;
|
||||
|
||||
if (defined($opt_n)) {
|
||||
print "$sysctl $mach_freq -> $n_mach_freq\n";
|
||||
} else {
|
||||
print "i8254: ".`sysctl -w $sysctl=$n_mach_freq`;
|
||||
}
|
||||
|
||||
sub usage {
|
||||
print STDERR <<EOUsage
|
||||
Usage: $0 [-d drift_file] [-n] [-t timer]
|
||||
where "drift_file" defaults to /etc/ntp.drift
|
||||
and "timer" is usually "tsc" or "i8254"
|
||||
and "-n" says "don't really change anything, just say what would happen".
|
||||
EOUsage
|
||||
}
|
@ -1,301 +0,0 @@
|
||||
#!/usr/local/bin/perl -w
|
||||
#
|
||||
# $Id: ntpsweep,v 1.3 2000/01/15 07:37:52 stenn Exp $
|
||||
#
|
||||
# DISCLAIMER
|
||||
#
|
||||
# Copyright (C) 1999,2000 Hans Lambermont and Origin B.V.
|
||||
#
|
||||
# Permission to use, copy, modify and distribute this software and its
|
||||
# documentation for any purpose and without fee is hereby granted,
|
||||
# provided that the above copyright notice appears in all copies and
|
||||
# that both the copyright notice and this permission notice appear in
|
||||
# supporting documentation. This software is supported as is and without
|
||||
# any express or implied warranties, including, without limitation, the
|
||||
# implied warranties of merchantability and fitness for a particular
|
||||
# purpose. The name Origin B.V. must not be used to endorse or promote
|
||||
# products derived from this software without prior written permission.
|
||||
#
|
||||
# Hans Lambermont <Hans.Lambermont@nl.origin-it.com>/<H.Lambermont@chello.nl>
|
||||
# 14 Jan 2000
|
||||
|
||||
require 5.0; # But actually tested on 5.004 ;)
|
||||
use Getopt::Long; # GetOptions()
|
||||
use strict;
|
||||
|
||||
my $version = 1.3;
|
||||
(my $program = $0) =~ s%.*/(.+?)(.pl)?$%$1%;
|
||||
|
||||
# Hardcoded paths/program names
|
||||
my $ntpdate = "ntpdate";
|
||||
my $ntpq = "ntpq";
|
||||
|
||||
# no STDOUT buffering
|
||||
$| = 1;
|
||||
|
||||
my ($help, $single_host, $showpeers, $maxlevel, $strip, $askversion);
|
||||
my $res = GetOptions("help!" => \$help,
|
||||
"host=s" => \$single_host,
|
||||
"peers!" => \$showpeers,
|
||||
"maxlevel=s" => \$maxlevel,
|
||||
"strip=s" => \$strip,
|
||||
"version!" => \$askversion);
|
||||
|
||||
if ($askversion) {
|
||||
print("$version\n");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($help || ((@ARGV != 1) && !$single_host)) {
|
||||
warn <<EOF;
|
||||
This is $program, version $version
|
||||
Copyright (C) 1999,2000 Hans Lambermont and Origin B.V. Disclaimer inside.
|
||||
|
||||
Usage:
|
||||
$program [--help|--peers|--strip <string>|--maxlevel <level>|--version] \\
|
||||
<file>|[--host <hostname>]
|
||||
|
||||
Description:
|
||||
$program prints per host given in <file> the NTP stratum level, the
|
||||
clock offset in seconds, the daemon version, the operating system and
|
||||
the processor. Optionally recursing through all peers.
|
||||
|
||||
Options:
|
||||
--help
|
||||
Print this short help text and exit.
|
||||
--version
|
||||
Print version ($version) and exit.
|
||||
<file>
|
||||
Specify hosts file. File format is one hostname or ip number per line.
|
||||
Lines beginning with # are considered as comment.
|
||||
--host <hostname>
|
||||
Speficy a single host, bypassing the need for a hosts file.
|
||||
--peers
|
||||
Recursively list all peers a host synchronizes to.
|
||||
An '= ' before a peer means a loop. Recursion stops here.
|
||||
--maxlevel <level>
|
||||
Traverse peers up to this level (4 is a reasonable number).
|
||||
--strip <string>
|
||||
Strip <string> from hostnames.
|
||||
|
||||
Examples:
|
||||
$program myhosts.txt --strip .foo.com
|
||||
$program --host some.host --peers --maxlevel 4
|
||||
EOF
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $hostsfile = shift;
|
||||
my (@hosts, @known_hosts);
|
||||
my (%known_host_info, %known_host_peers);
|
||||
|
||||
sub read_hosts()
|
||||
{
|
||||
local *HOSTS;
|
||||
open (HOSTS, $hostsfile) ||
|
||||
die "$program: FATAL: unable to read $hostsfile: $!\n";
|
||||
while (<HOSTS>) {
|
||||
next if /^\s*(#|$)/; # comment/empty
|
||||
chomp;
|
||||
push(@hosts, $_);
|
||||
}
|
||||
close(HOSTS);
|
||||
}
|
||||
|
||||
# translate IP to hostname if possible
|
||||
sub ip2name {
|
||||
my($ip) = @_;
|
||||
my($addr, $name, $aliases, $addrtype, $length, @addrs);
|
||||
$addr = pack('C4', split(/\./, $ip));
|
||||
($name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr($addr, 2);
|
||||
if ($name) {
|
||||
# return lower case name
|
||||
return("\L$name");
|
||||
} else {
|
||||
return($ip);
|
||||
}
|
||||
}
|
||||
|
||||
# item_in_list($item, @list): returns 1 if $item is in @list, 0 if not
|
||||
sub item_in_list {
|
||||
my($item, @list) = @_;
|
||||
my($i);
|
||||
foreach $i (@list) {
|
||||
return 1 if ($item eq $i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub scan_host($;$;$) {
|
||||
my($host, $level, @trace) = @_;
|
||||
my $stratum = 0;
|
||||
my $offset = 0;
|
||||
my $daemonversion = "";
|
||||
my $system = "";
|
||||
my $processor = "";
|
||||
my @peers;
|
||||
my $known_host = 0;
|
||||
|
||||
if (&item_in_list($host, @known_hosts)) {
|
||||
$known_host = 1;
|
||||
} else {
|
||||
# ntpdate part
|
||||
open(NTPDATE, "$ntpdate -bd $host 2>/dev/null |") ||
|
||||
die "Cannot open ntpdate pipe: $!\n";
|
||||
while (<NTPDATE>) {
|
||||
/^stratum\s+(\d+).*$/ && do {
|
||||
$stratum = $1;
|
||||
};
|
||||
/^offset\s+([0-9.-]+)$/ && do {
|
||||
$offset = $1;
|
||||
};
|
||||
}
|
||||
close(NTPDATE);
|
||||
|
||||
# got answers ? If so, go on.
|
||||
if ($stratum) {
|
||||
# ntpq part
|
||||
my $ntpqparams = "-c 'rv 0 processor,system,daemon_version'";
|
||||
open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
|
||||
die "Cannot open ntpq pipe: $!\n";
|
||||
while (<NTPQ>) {
|
||||
/daemon_version="(.*)"/ && do {
|
||||
$daemonversion = $1;
|
||||
};
|
||||
/system="([^"]*)"/ && do {
|
||||
$system = $1;
|
||||
};
|
||||
/processor="([^"]*)"/ && do {
|
||||
$processor = $1;
|
||||
};
|
||||
}
|
||||
close(NTPQ);
|
||||
|
||||
# Shorten daemon_version string.
|
||||
$daemonversion =~ s/(;|Mon|Tue|Wed|Thu|Fri|Sat|Sun).*$//;
|
||||
$daemonversion =~ s/version=//;
|
||||
$daemonversion =~ s/(x|)ntpd //;
|
||||
$daemonversion =~ s/(\(|\))//g;
|
||||
$daemonversion =~ s/beta/b/;
|
||||
$daemonversion =~ s/multicast/mc/;
|
||||
|
||||
# Shorten system string
|
||||
$system =~ s/UNIX\///;
|
||||
$system =~ s/RELEASE/r/;
|
||||
$system =~ s/CURRENT/c/;
|
||||
|
||||
# Shorten processor string
|
||||
$processor =~ s/unknown//;
|
||||
}
|
||||
|
||||
# got answers ? If so, go on.
|
||||
if ($daemonversion) {
|
||||
# ntpq again, find out the peers this time
|
||||
if ($showpeers) {
|
||||
my $ntpqparams = "-pn";
|
||||
open(NTPQ, "$ntpq $ntpqparams $host 2>/dev/null |") ||
|
||||
die "Cannot open ntpq pipe: $!\n";
|
||||
while (<NTPQ>) {
|
||||
/^No association ID's returned$/ && do {
|
||||
last;
|
||||
};
|
||||
/^ remote/ && do {
|
||||
next;
|
||||
};
|
||||
/^==/ && do {
|
||||
next;
|
||||
};
|
||||
/^( |x|\.|-|\+|#|\*|o)([^ ]+)/ && do {
|
||||
push(@peers, ip2name($2));
|
||||
next;
|
||||
};
|
||||
print "ERROR: $_";
|
||||
}
|
||||
close(NTPQ);
|
||||
}
|
||||
}
|
||||
|
||||
# Add scanned host to known_hosts array
|
||||
push(@known_hosts, $host);
|
||||
if ($stratum) {
|
||||
$known_host_info{$host} = sprintf("%2d %9.3f %-11s %-12s %s",
|
||||
$stratum, $offset, substr($daemonversion,0,11),
|
||||
substr($system,0,12), substr($processor,0,9));
|
||||
} else {
|
||||
# Stratum level 0 is consider invalid
|
||||
$known_host_info{$host} = sprintf(" ?");
|
||||
}
|
||||
$known_host_peers{$host} = [@peers];
|
||||
}
|
||||
|
||||
if ($stratum || $known_host) { # Valid or known host
|
||||
my $printhost = ' ' x $level . $host;
|
||||
# Shorten host string
|
||||
if ($strip) {
|
||||
$printhost =~ s/$strip//;
|
||||
}
|
||||
# append number of peers in brackets if requested and valid
|
||||
if ($showpeers && ($known_host_info{$host} ne " ?")) {
|
||||
$printhost .= " (" . @{$known_host_peers{$host}} . ")";
|
||||
}
|
||||
# Finally print complete host line
|
||||
printf("%-32s %s\n",
|
||||
substr($printhost,0,32), $known_host_info{$host});
|
||||
if ($showpeers && (eval($maxlevel ? $level < $maxlevel : 1))) {
|
||||
my $peer;
|
||||
push(@trace, $host);
|
||||
# Loop through peers
|
||||
foreach $peer (@{$known_host_peers{$host}}) {
|
||||
if (&item_in_list($peer, @trace)) {
|
||||
# we've detected a loop !
|
||||
$printhost = ' ' x ($level + 1) . "= " . $peer;
|
||||
# Shorten host string
|
||||
if ($strip) {
|
||||
$printhost =~ s/$strip//;
|
||||
}
|
||||
printf("%-32s %s\n",
|
||||
substr($printhost,0,32));
|
||||
} else {
|
||||
if (substr($peer,0,3) ne "127") {
|
||||
&scan_host($peer, $level + 1, @trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { # We did not get answers from this host
|
||||
my $printhost = ' ' x $level . $host;
|
||||
# Shorten host string
|
||||
if ($strip) {
|
||||
$printhost =~ s/$strip//;
|
||||
}
|
||||
printf("%-32s ?\n", substr($printhost,0,32));
|
||||
}
|
||||
}
|
||||
|
||||
sub scan_hosts()
|
||||
{
|
||||
my $host;
|
||||
for $host (@hosts) {
|
||||
my @trace;
|
||||
push(@trace, $host);
|
||||
scan_host($host, 0, @trace);
|
||||
}
|
||||
}
|
||||
|
||||
# Main program
|
||||
|
||||
if ($single_host) {
|
||||
push(@hosts, $single_host);
|
||||
} else {
|
||||
&read_hosts($hostsfile);
|
||||
}
|
||||
|
||||
# Print header
|
||||
print <<EOF;
|
||||
Host st offset(s) version system processor
|
||||
--------------------------------+--+---------+-----------+------------+---------
|
||||
EOF
|
||||
|
||||
&scan_hosts();
|
||||
|
||||
exit 0;
|
@ -1,337 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
# $Id: plot_summary.pl,v 1.2 1999/12/02 01:59:05 stenn Exp $
|
||||
#
|
||||
# Use Gnuplot to display data in summary files produced by summary.pl.
|
||||
# This script requires GNUPLOT 3.7!
|
||||
#
|
||||
# Copyright (c) 1997, 1999 by Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
require 5.003; # "never tested with any other version of Perl"
|
||||
use strict;
|
||||
|
||||
use Time::Local;
|
||||
use Getopt::Long;
|
||||
|
||||
# parse command line
|
||||
my $summary_dir = "/tmp";
|
||||
my $identifier = "host " . `hostname`; # origin of these data
|
||||
chomp $identifier; # remove newline
|
||||
my $offset_limit = 0.128; # limit of absolute offset
|
||||
my $output_file = ""; # output file defaults to stdout
|
||||
my $output_file_number = 1; # numbering of output files
|
||||
my $gnuplot_terminal = $ENV{DISPLAY} ? "x11" : "dumb";
|
||||
my $wait_after_plot = 1;
|
||||
my @peer_list = ();
|
||||
|
||||
my %options = ("directory|input-directory=s" => \$summary_dir,
|
||||
"identifier=s" => \$identifier,
|
||||
"offset-limit=f" => \$offset_limit,
|
||||
"output-file=s" => \$output_file,
|
||||
"peer=s@" => \@peer_list,
|
||||
"plot-term|gnuplot-term=s" => \$gnuplot_terminal,
|
||||
"wait-after-plot!" => \$wait_after_plot,
|
||||
);
|
||||
|
||||
if ( !GetOptions(%options) )
|
||||
{
|
||||
print STDERR "valid options for $0 are:\n";
|
||||
my $opt;
|
||||
foreach $opt (sort(keys %options)) {
|
||||
print STDERR "\t--$opt\t(default is ";
|
||||
if ( ref($options{$opt}) eq "ARRAY" ) {
|
||||
print STDERR join(", ", map { "'$_'" } @{$options{$opt}});
|
||||
} else {
|
||||
print STDERR "'${$options{$opt}}'";
|
||||
}
|
||||
print STDERR ")\n";
|
||||
}
|
||||
print STDERR "\n";
|
||||
die;
|
||||
}
|
||||
|
||||
chomp $identifier;
|
||||
die "illegal offset-limit: $offset_limit" unless $offset_limit > 0.0;
|
||||
$offset_limit *= 1e6; # scale to microseconds
|
||||
|
||||
# return the smallest value in the given list
|
||||
sub min
|
||||
{
|
||||
my ($result, @rest) = @_;
|
||||
map { $result = $_ if ($_ < $result) } @rest;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# return the largest value in the given list
|
||||
sub max
|
||||
{
|
||||
my ($result, @rest) = @_;
|
||||
map { $result = $_ if ($_ > $result) } @rest;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# maybe open alternate output file
|
||||
sub open_output
|
||||
{
|
||||
my $file;
|
||||
if ($output_file) {
|
||||
while ( -r ($file = "$output_file$output_file_number") ) {
|
||||
++$output_file_number;
|
||||
}
|
||||
open TOUCH, ">$file" and close TOUCH or die "$file: $!";
|
||||
print "set output \"$file\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
# make Gnuplot wait
|
||||
sub maybe_add_pause
|
||||
{
|
||||
print "pause -1 \"Press key to continue...\"\n" if $wait_after_plot;
|
||||
}
|
||||
|
||||
# plot data from loop summary
|
||||
sub do_loop
|
||||
{
|
||||
my $fname = shift;
|
||||
my $line;
|
||||
my $out_file = "/tmp/tempdata$$";
|
||||
my $cmd_file = "/tmp/tempcmd$$";
|
||||
my ($first_day, $day_out) = ("", 0);
|
||||
my ($lower_bound, $upper_bound, $rms);
|
||||
my ($min_offs, $max_offs) = (1e9, -1e9);
|
||||
my ($min_rms, $max_rms) = (1e9, -1e9);
|
||||
open INPUT, "$fname" or die "$fname: $!";
|
||||
open OUTPUT, ">$out_file" or die "$out_file: $!";
|
||||
my @Fld;
|
||||
while (<INPUT>) {
|
||||
chop; # strip record separator
|
||||
@Fld = split;
|
||||
if ($#Fld == 0) {
|
||||
# loops.19960405
|
||||
$_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/;
|
||||
m/(\d{4})(\d{2})(\d{2})/;
|
||||
$line = timegm(59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0);
|
||||
$line = int $line / 86400; # days relative to 1970
|
||||
$first_day = "$1-$2-$3 ($line)" unless $day_out;
|
||||
next;
|
||||
}
|
||||
if ($#Fld != 8) {
|
||||
warn "Illegal number of fields in file $fname, line $.";
|
||||
next;
|
||||
}
|
||||
# loop 216, 856106+/-874041.5, rms 117239.8, freq 67.52+/-10.335, var 4.850
|
||||
$_ = $Fld[1]; s/,/ /; $line .= " $_";
|
||||
$_ = $Fld[2]; m:(.+?)\+/-(.+),:;
|
||||
$lower_bound = $1 - $2;
|
||||
$upper_bound = $1 + $2;
|
||||
$line .= "$1 $lower_bound $upper_bound";
|
||||
$min_offs = min($min_offs, $lower_bound);
|
||||
$max_offs = max($max_offs, $upper_bound);
|
||||
$_ = $Fld[4]; s/,/ /; $rms = $_;
|
||||
$min_rms = min($min_rms, $rms);
|
||||
$max_rms = max($max_rms, $rms);
|
||||
$line .= " $rms";
|
||||
$_ = $Fld[6]; m:(.+?)\+/-(.+),:;
|
||||
$line .= " $1 " . ($1-$2) . " " . ($1+$2);
|
||||
$line .= " $Fld[8]";
|
||||
print OUTPUT "$line\n";
|
||||
$day_out = 1;
|
||||
# 9621 216 856106 -17935.5 1730147.5 117239.8 67.52 57.185 77.855 4.850
|
||||
}
|
||||
close INPUT;
|
||||
close OUTPUT or die "close failed on $out_file: $!";
|
||||
my $ylimit = "[";
|
||||
if ($min_offs < -$offset_limit) {
|
||||
$ylimit .= "-$offset_limit";
|
||||
}
|
||||
$ylimit .= ":";
|
||||
if ($max_offs > $offset_limit) {
|
||||
$ylimit .= "$offset_limit";
|
||||
}
|
||||
if ( $ylimit eq "[:" ) {
|
||||
$ylimit = "";
|
||||
} else {
|
||||
$ylimit = "[] $ylimit]";
|
||||
}
|
||||
# build command file for GNUplot
|
||||
open OUTPUT, "> $cmd_file" or die "$cmd_file: $!";
|
||||
my $oldfh = select OUTPUT;
|
||||
print "set term $gnuplot_terminal\n";
|
||||
open_output;
|
||||
print "set grid\n";
|
||||
print "set title \"Loop Summary for $identifier: " .
|
||||
"Daily mean values since $first_day\\n" .
|
||||
"(Offset limit is $offset_limit microseconds)\"\n";
|
||||
print "set ylabel \"[us]\"\n";
|
||||
print "set data style yerrorbars\n";
|
||||
print "set multiplot\n";
|
||||
print "set size 1, 0.5\n";
|
||||
print "set lmargin 8\n";
|
||||
print "set origin 0, 0.5\n";
|
||||
print "plot $ylimit \"$out_file\"" .
|
||||
" using 1:3:4:5 title \"mean offset\", ";
|
||||
print "\"$out_file\" using 1:(\$3-\$6/2) " .
|
||||
"title \"(sigma low)\" with lines, ";
|
||||
print "\"$out_file\" using 1:3 smooth bezier " .
|
||||
"title \"(Bezier med)\" with lines, ";
|
||||
print "\"$out_file\" using 1:(\$3+\$6/2) " .
|
||||
"title \"(sigma high)\" with lines\n";
|
||||
print "set ylabel \"[ppm]\"\n";
|
||||
print "set origin 0, 0.0\n";
|
||||
print "set title\n";
|
||||
print "set xlabel \"Days relative to 1970\"\n";
|
||||
print "plot \"$out_file\" using 1:7:8:9 title \"mean frequency\", ";
|
||||
print "\"$out_file\" using 1:(\$7-\$10/2) " .
|
||||
"title \"(sigma low)\" with lines, ";
|
||||
print "\"$out_file\" using 1:7 smooth bezier " .
|
||||
"title \"(Bezier med)\" with lines, ";
|
||||
print "\"$out_file\" using 1:(\$7+\$10/2) " .
|
||||
"title \"(sigma high)\" with lines\n";
|
||||
print "set nomultiplot\n";
|
||||
maybe_add_pause;
|
||||
|
||||
$ylimit = "[";
|
||||
if ($min_rms < -$offset_limit) {
|
||||
$ylimit .= "-$offset_limit";
|
||||
}
|
||||
$ylimit .= ":";
|
||||
if ($max_rms > $offset_limit) {
|
||||
$ylimit .= "$offset_limit";
|
||||
}
|
||||
if ( $ylimit eq "[:" ) {
|
||||
$ylimit ="";
|
||||
} else {
|
||||
$ylimit = "[] $ylimit]";
|
||||
}
|
||||
|
||||
open_output;
|
||||
print "set title \"Loop Summary for $identifier: " .
|
||||
"Standard deviation since $first_day\\n" .
|
||||
"(Offset limit is $offset_limit microseconds)\"\n";
|
||||
print "set xlabel\n";
|
||||
print "set ylabel \"[us]\"\n";
|
||||
print "set origin 0, 0.5\n";
|
||||
print "set data style linespoints\n";
|
||||
print "set multiplot\n";
|
||||
print "plot $ylimit \"$out_file\" using 1:6 title \"Offset\", ";
|
||||
print "\"$out_file\" using 1:6 smooth bezier " .
|
||||
"title \"(Bezier)\" with lines\n";
|
||||
print "set title\n";
|
||||
print "set origin 0, 0.0\n";
|
||||
print "set xlabel \"Days relative to 1970\"\n";
|
||||
print "set ylabel \"[ppm]\"\n";
|
||||
print "plot \"$out_file\" using 1:10 title \"Frequency\", ";
|
||||
print "\"$out_file\" using 1:10 smooth bezier " .
|
||||
"title \"(Bezier)\" with lines\n";
|
||||
print "set nomultiplot\n";
|
||||
maybe_add_pause;
|
||||
|
||||
close OUTPUT or die "close failed on $cmd_file: $!";
|
||||
select $oldfh;
|
||||
print `gnuplot $cmd_file`;
|
||||
unlink $cmd_file;
|
||||
unlink $out_file;
|
||||
}
|
||||
|
||||
# plot data form peer summary
|
||||
sub do_peer
|
||||
{
|
||||
my $fname = shift;
|
||||
my $peer = shift;
|
||||
my $out_file = "/tmp/tempdata$$";
|
||||
my $cmd_file = "/tmp/tempcmd$$";
|
||||
my $line;
|
||||
my ($first_day, $day_out) = ("", 0);
|
||||
open INPUT, "$fname" or die "$fname: $!";
|
||||
open OUTPUT, ">$out_file" or die "$out_file: $!";
|
||||
my @Fld;
|
||||
while (<INPUT>) {
|
||||
chop; # strip record separator
|
||||
@Fld = split;
|
||||
if ($#Fld == 0) {
|
||||
# peers.19960405
|
||||
$_ = $Fld[0]; s/.*([12]\d{3}[01]\d[0-3]\d)$/$1/;
|
||||
m/(\d{4})(\d{2})(\d{2})/ or next;
|
||||
$line = timegm(59, 59, 23, $3, $2 - 1, $1 - 1900, 0, 0, 0);
|
||||
$line = int $line / 86400; # days relative to 1970
|
||||
$first_day = "$1-$2-$3 ($line)" unless $day_out;
|
||||
next;
|
||||
}
|
||||
if ($#Fld != 7) {
|
||||
warn "Illegal number of fields in file $fname, line $.";
|
||||
next;
|
||||
}
|
||||
next if ($Fld[0] ne $peer);
|
||||
# ident cnt mean rms max delay dist disp
|
||||
# 127.127.8.1 38 30.972 189.867 1154.607 0.000 879.760 111.037
|
||||
$Fld[0] = $line;
|
||||
print OUTPUT join(' ', @Fld) . "\n";
|
||||
# 9969 38 30.972 189.867 1154.607 0.000 879.760 111.037
|
||||
$day_out = 1;
|
||||
}
|
||||
close INPUT;
|
||||
close OUTPUT or die "close failed on $out_file: $!";
|
||||
die "no data found for peer $peer" if !$day_out;
|
||||
open OUTPUT, "> $cmd_file" or die "$cmd_file: $!";
|
||||
my $oldfh = select OUTPUT;
|
||||
print "set term $gnuplot_terminal\n";
|
||||
open_output;
|
||||
print "set grid\n";
|
||||
print "set multiplot\n";
|
||||
print "set lmargin 8\n";
|
||||
print "set size 1, 0.34\n";
|
||||
print "set origin 0, 0.66\n";
|
||||
print "set title " .
|
||||
"\"Peer Summary for $peer on $identifier since $first_day\"\n";
|
||||
print "set data style linespoints\n";
|
||||
print "set ylabel \"[us]\"\n";
|
||||
print "plot \"$out_file\" using 1:3 title \"mean offset\", ";
|
||||
print "\"$out_file\" using 1:3 smooth bezier " .
|
||||
"title \"(Bezier)\" with lines, ";
|
||||
print "\"$out_file\" using 1:(\$3-\$7/2) " .
|
||||
"title \"(sigma low)\" with lines, ";
|
||||
print "\"$out_file\" using 1:(\$3+\$7/2) " .
|
||||
"title \"(sigma high)\" with lines\n";
|
||||
print "set title\n";
|
||||
print "set origin 0, 0.34\n";
|
||||
print "set size 1, 0.32\n";
|
||||
print "set ylabel\n";
|
||||
print "plot \"$out_file\" using 1:7 title \"dist\", ";
|
||||
print "\"$out_file\" using 1:7 smooth bezier " .
|
||||
"title \"(Bezier)\" with lines\n";
|
||||
print "set origin 0, 0.00\n";
|
||||
print "set size 1, 0.35\n";
|
||||
print "set xlabel \"Days relative to 1970\"\n";
|
||||
print "plot \"$out_file\" using 1:8 title \"disp\", ";
|
||||
print "\"$out_file\" using 1:8 smooth bezier " .
|
||||
"title \"(Bezier)\" with lines\n";
|
||||
print "set nomultiplot\n";
|
||||
maybe_add_pause;
|
||||
|
||||
select $oldfh;
|
||||
close OUTPUT or die "close failed on $cmd_file: $!";
|
||||
print `gnuplot $cmd_file`;
|
||||
unlink $cmd_file;
|
||||
unlink $out_file;
|
||||
}
|
||||
|
||||
|
||||
my $loop_summary ="$summary_dir/loop_summary";
|
||||
my $peer_summary ="$summary_dir/peer_summary";
|
||||
my $clock_summary="$summary_dir/clock_summary";
|
||||
|
||||
do_loop $loop_summary;
|
||||
map { do_peer $peer_summary, $_ } @peer_list;
|
File diff suppressed because it is too large
Load Diff
@ -1,373 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
# $Id: summary.pl,v 1.2 1999/12/02 01:59:07 stenn Exp $
|
||||
# Perl version of (summary.sh, loop.awk, peer.awk):
|
||||
# Create summaries from xntpd's loop and peer statistics.
|
||||
#
|
||||
# Copyright (c) 1997, 1999 by Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
require 5.003; # "never tested with any other version of Perl"
|
||||
use strict;
|
||||
|
||||
use Getopt::Long;
|
||||
|
||||
my $log_date_pattern = '[12]\d{3}[01]\d[0-3]\d';
|
||||
my $statsdir = "/var/log/ntp"; # directory with input files
|
||||
my $outputdir = "/tmp"; # directory for output files
|
||||
my $skip_time_steps = 3600.0; # ignore time offsets larger that this
|
||||
my $startdate = "19700101"; # first data file to use (YYYYMMDD)
|
||||
my $enddate=`date -u +%Y%m%d`; chomp $enddate; --$enddate;
|
||||
my $peer_dist_limit = 400.0;
|
||||
|
||||
my %options = ("directory|input-directory=s" => \$statsdir,
|
||||
"output-directory=s" => \$outputdir,
|
||||
"skip-time-steps:f" => \$skip_time_steps,
|
||||
"start-date=s" => \$startdate,
|
||||
"end-date=s" => \$enddate,
|
||||
"peer-dist-limit=f" => \$peer_dist_limit);
|
||||
|
||||
if ( !GetOptions(%options) )
|
||||
{
|
||||
print STDERR "valid options for $0 are:\n";
|
||||
my $opt;
|
||||
foreach $opt (sort(keys %options)) {
|
||||
print STDERR "\t--$opt\t(default is ";
|
||||
if ( ref($options{$opt}) eq "ARRAY" ) {
|
||||
print STDERR join(", ", map { "'$_'" } @{$options{$opt}});
|
||||
} else {
|
||||
print STDERR "'${$options{$opt}}'";
|
||||
}
|
||||
print STDERR ")\n";
|
||||
}
|
||||
print STDERR "\n";
|
||||
die;
|
||||
}
|
||||
|
||||
# check possibly current values of options
|
||||
die "$statsdir: no such directory" unless (-d $statsdir);
|
||||
die "$outputdir: no such directory" unless (-d $outputdir);
|
||||
die "$skip_time_steps: skip-time-steps must be positive"
|
||||
unless ($skip_time_steps >= 0.0);
|
||||
die "$startdate: invalid start date|$`|$&|$'"
|
||||
unless ($startdate =~ m/.*$log_date_pattern$/);
|
||||
die "$enddate: invalid end date"
|
||||
unless ($enddate =~ m/.*$log_date_pattern$/);
|
||||
|
||||
$skip_time_steps = 0.128 if ($skip_time_steps == 0);
|
||||
|
||||
sub min
|
||||
{
|
||||
my ($result, @rest) = @_;
|
||||
map { $result = $_ if ($_ < $result) } @rest;
|
||||
return($result);
|
||||
}
|
||||
|
||||
sub max
|
||||
{
|
||||
my ($result, @rest) = @_;
|
||||
map { $result = $_ if ($_ > $result) } @rest;
|
||||
return($result);
|
||||
}
|
||||
|
||||
# calculate mean, range, and standard deviation for offset and frequency
|
||||
sub do_loop
|
||||
{
|
||||
my ($directory, $fname, $out_file) = @_;
|
||||
print "$directory/$fname\n";
|
||||
open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!";
|
||||
open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
|
||||
print OUTPUT "$fname\n";
|
||||
my ($loop_tmax, $loop_fmax) = (-1e9, -1e9);
|
||||
my ($loop_tmin, $loop_fmin) = (1e9, 1e9);
|
||||
my ($loop_time_rms, $loop_freq_rms) = (0, 0);
|
||||
my $loop_count = 0;
|
||||
my $loop_time = 0;
|
||||
my $loop_freq = 0;
|
||||
my ($freq, $offs);
|
||||
my @Fld;
|
||||
while (<INPUT>) {
|
||||
chop; # strip record separator
|
||||
@Fld = split;
|
||||
next if ($#Fld < 4);
|
||||
#NTPv3: 50529 74356.259 -0.000112 16.1230 8
|
||||
#NTPv3: day, sec.msec, offset, drift_comp, sys_poll
|
||||
#NTPv4: 51333 54734.582 0.000001648 16.981964 0.000001094 0.020938 6
|
||||
#NTPv4: day, sec.msec, offset, drift_comp, sys_error, clock_stabil, sys_poll
|
||||
if ($Fld[2] > $skip_time_steps || $Fld[2] < -$skip_time_steps) {
|
||||
warn "ignoring loop offset $Fld[2] (file $fname, line $.)\n";
|
||||
next
|
||||
}
|
||||
$loop_count++;
|
||||
($offs, $freq) = ($Fld[2], $Fld[3]);
|
||||
$loop_tmax = max($loop_tmax, $offs);
|
||||
$loop_tmin = min($loop_tmin, $offs);
|
||||
$loop_fmax = max($loop_fmax, $freq);
|
||||
$loop_fmin = min($loop_fmin, $freq);
|
||||
$loop_time += $offs;
|
||||
$loop_time_rms += $offs * $offs;
|
||||
$loop_freq += $freq;
|
||||
$loop_freq_rms += $freq * $freq;
|
||||
}
|
||||
close INPUT;
|
||||
if ($loop_count > 1) {
|
||||
$loop_time /= $loop_count;
|
||||
$loop_time_rms = $loop_time_rms / $loop_count - $loop_time * $loop_time;
|
||||
if ($loop_time_rms < 0) {
|
||||
warn "loop_time_rms: $loop_time_rms < 0";
|
||||
$loop_time_rms = 0;
|
||||
}
|
||||
$loop_time_rms = sqrt($loop_time_rms);
|
||||
$loop_freq /= $loop_count;
|
||||
$loop_freq_rms = $loop_freq_rms / $loop_count - $loop_freq * $loop_freq;
|
||||
if ($loop_freq_rms < 0) {
|
||||
warn "loop_freq_rms: $loop_freq_rms < 0";
|
||||
$loop_freq_rms = 0;
|
||||
}
|
||||
$loop_freq_rms = sqrt($loop_freq_rms);
|
||||
printf OUTPUT
|
||||
("loop %d, %.0f+/-%.1f, rms %.1f, freq %.2f+/-%0.3f, var %.3f\n",
|
||||
$loop_count, ($loop_tmax + $loop_tmin) / 2 * 1e6,
|
||||
($loop_tmax - $loop_tmin) / 2 * 1e6, $loop_time_rms * 1e6,
|
||||
($loop_fmax + $loop_fmin) / 2, ($loop_fmax - $loop_fmin) / 2,
|
||||
$loop_freq_rms);
|
||||
}
|
||||
else {
|
||||
warn "no valid lines in $directory/$fname";
|
||||
}
|
||||
close OUTPUT
|
||||
}
|
||||
|
||||
# calculate mean, standard deviation, maximum offset, mean dispersion,
|
||||
# and maximum distance for each peer
|
||||
sub do_peer
|
||||
{
|
||||
my ($directory, $fname, $out_file) = @_;
|
||||
print "$directory/$fname\n";
|
||||
open INPUT, "$directory/$fname" or warn "can't open $directory/$fname: $!";
|
||||
open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
|
||||
print OUTPUT "$fname\n";
|
||||
# we toss out all distances greater than one second on the assumption the
|
||||
# peer is in initial acquisition
|
||||
my ($n, $MAXDISTANCE) = (0, 1.0);
|
||||
my %peer_time;
|
||||
my %peer_time_rms;
|
||||
my %peer_count;
|
||||
my %peer_delay;
|
||||
my %peer_disp;
|
||||
my %peer_dist;
|
||||
my %peer_ident;
|
||||
my %peer_tmin;
|
||||
my %peer_tmax;
|
||||
my @Fld;
|
||||
my ($i, $j);
|
||||
my ($dist, $offs);
|
||||
while (<INPUT>) {
|
||||
chop; # strip record separator
|
||||
@Fld = split;
|
||||
next if ($#Fld < 6);
|
||||
#NTPv3: 50529 83316.249 127.127.8.1 9674 0.008628 0.00000 0.00700
|
||||
#NTPv3: day, sec.msec, addr, status, offset, delay, dispersion
|
||||
#NTPv4: 51333 56042.037 127.127.8.1 94f5 -0.000014657 0.000000000 0.000000000 0.000013214
|
||||
#NTPv4: day, sec.msec, addr, status, offset, delay, dispersion, skew
|
||||
|
||||
$dist = $Fld[6] + $Fld[5] / 2;
|
||||
next if ($dist > $MAXDISTANCE);
|
||||
$offs = $Fld[4];
|
||||
if ($offs > $skip_time_steps || $offs < -$skip_time_steps) {
|
||||
warn "ignoring peer offset $offs (file $fname, line $.)\n";
|
||||
next
|
||||
}
|
||||
$i = $n;
|
||||
for ($j = 0; $j < $n; $j++) {
|
||||
if ($Fld[2] eq $peer_ident{$j}) {
|
||||
$i = $j; # peer found
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($i == $n) { # add new peer
|
||||
$peer_ident{$i} = $Fld[2];
|
||||
$peer_tmax{$i} = $peer_dist{$i} = -1e9;
|
||||
$peer_tmin{$i} = 1e9;
|
||||
$peer_time{$i} = $peer_time_rms{$i} = 0;
|
||||
$peer_delay{$i} = $peer_disp{$i} = 0;
|
||||
$peer_count{$i} = 0;
|
||||
$n++;
|
||||
}
|
||||
$peer_count{$i}++;
|
||||
$peer_tmax{$i} = max($peer_tmax{$i}, $offs);
|
||||
$peer_tmin{$i} = min($peer_tmin{$i}, $offs);
|
||||
$peer_dist{$i} = max($peer_dist{$i}, $dist);
|
||||
$peer_time{$i} += $offs;
|
||||
$peer_time_rms{$i} += $offs * $offs;
|
||||
$peer_delay{$i} += $Fld[5];
|
||||
$peer_disp{$i} += $Fld[6];
|
||||
}
|
||||
close INPUT;
|
||||
print OUTPUT
|
||||
" ident cnt mean rms max delay dist disp\n";
|
||||
print OUTPUT
|
||||
"==========================================================================\n";
|
||||
my @lines = ();
|
||||
for ($i = 0; $i < $n; $i++) {
|
||||
next if $peer_count{$i} < 2;
|
||||
$peer_time{$i} /= $peer_count{$i};
|
||||
eval { $peer_time_rms{$i} = sqrt($peer_time_rms{$i} / $peer_count{$i} -
|
||||
$peer_time{$i} * $peer_time{$i}); };
|
||||
$peer_time_rms{$i} = 0, warn $@ if $@;
|
||||
$peer_delay{$i} /= $peer_count{$i};
|
||||
$peer_disp{$i} /= $peer_count{$i};
|
||||
$peer_tmax{$i} = $peer_tmax{$i} - $peer_time{$i};
|
||||
$peer_tmin{$i} = $peer_time{$i} - $peer_tmin{$i};
|
||||
if ($peer_tmin{$i} > $peer_tmax{$i}) { # can this happen at all?
|
||||
$peer_tmax{$i} = $peer_tmin{$i};
|
||||
}
|
||||
push @lines, sprintf
|
||||
"%-15s %4d %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
|
||||
$peer_ident{$i}, $peer_count{$i}, $peer_time{$i} * 1e3,
|
||||
$peer_time_rms{$i} * 1e3, $peer_tmax{$i} * 1e3,
|
||||
$peer_delay{$i} * 1e3, $peer_dist{$i} * 1e3, $peer_disp{$i} * 1e3;
|
||||
}
|
||||
print OUTPUT sort @lines;
|
||||
close OUTPUT;
|
||||
}
|
||||
|
||||
sub do_clock
|
||||
{
|
||||
my ($directory, $fname, $out_file) = @_;
|
||||
print "$directory/$fname\n";
|
||||
open INPUT, "$directory/$fname";
|
||||
open OUTPUT, ">>$out_file" or die "can't open $out_file: $!";
|
||||
print OUTPUT "$fname\n";
|
||||
close INPUT;
|
||||
close OUTPUT;
|
||||
}
|
||||
|
||||
sub peer_summary
|
||||
{
|
||||
my $in_file = shift;
|
||||
my ($i, $j, $n);
|
||||
my (%peer_ident, %peer_count, %peer_mean, %peer_var, %peer_max);
|
||||
my (%peer_1, %peer_2, %peer_3, %peer_4);
|
||||
my $dist;
|
||||
my $max;
|
||||
open INPUT, "<$in_file" or die "can't open $in_file: $!";
|
||||
my @Fld;
|
||||
$n = 0;
|
||||
while (<INPUT>) {
|
||||
chop; # strip record separator
|
||||
@Fld = split;
|
||||
next if ($#Fld < 7 || $Fld[0] eq 'ident');
|
||||
$i = $n;
|
||||
for ($j = 0; $j < $n; $j++) {
|
||||
if ($Fld[0] eq $peer_ident{$j}) {
|
||||
$i = $j;
|
||||
last; # peer found
|
||||
}
|
||||
}
|
||||
if ($i == $n) { # add new peer
|
||||
$peer_count{$i} = $peer_mean{$i} = $peer_var{$i} = 0;
|
||||
$peer_max{$i} = 0;
|
||||
$peer_1{$i} = $peer_2{$i} = $peer_3{$i} = $peer_4{$i} = 0;
|
||||
$peer_ident{$i} = $Fld[0];
|
||||
++$n;
|
||||
}
|
||||
$dist = $Fld[6] - $Fld[5] / 2;
|
||||
if ($dist < $peer_dist_limit) {
|
||||
$peer_count{$i}++;
|
||||
$peer_mean{$i} += $Fld[2];
|
||||
$peer_var{$i} += $Fld[3] * $Fld[3];
|
||||
$max = $Fld[4];
|
||||
$peer_max{$i} = max($peer_max{$i}, $max);
|
||||
if ($max > 1) {
|
||||
$peer_1{$i}++;
|
||||
if ($max > 5) {
|
||||
$peer_2{$i}++;
|
||||
if ($max > 10) {
|
||||
$peer_3{$i}++;
|
||||
if ($max > 50) {
|
||||
$peer_4{$i}++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
warn "dist exceeds limit: $dist (file $in_file, line $.)\n";
|
||||
}
|
||||
}
|
||||
close INPUT;
|
||||
my @lines = ();
|
||||
print
|
||||
" host days mean rms max >1 >5 >10 >50\n";
|
||||
print
|
||||
"==================================================================\n";
|
||||
for ($i = 0; $i < $n; $i++) {
|
||||
next if ($peer_count{$i} < 2);
|
||||
$peer_mean{$i} /= $peer_count{$i};
|
||||
eval { $peer_var{$i} = sqrt($peer_var{$i} / $peer_count{$i} -
|
||||
$peer_mean{$i} * $peer_mean{$i}); };
|
||||
$peer_var{$i} = 0, warn $@ if $@;
|
||||
push @lines, sprintf
|
||||
"%-15s %3d %9.3f% 9.3f %9.3f %3d %3d %3d %3d\n",
|
||||
$peer_ident{$i}, $peer_count{$i}, $peer_mean{$i}, $peer_var{$i},
|
||||
$peer_max{$i}, $peer_1{$i}, $peer_2{$i}, $peer_3{$i}, $peer_4{$i};
|
||||
}
|
||||
print sort @lines;
|
||||
}
|
||||
|
||||
my $loop_summary="$outputdir/loop_summary";
|
||||
my $peer_summary="$outputdir/peer_summary";
|
||||
my $clock_summary="$outputdir/clock_summary";
|
||||
my (@loopfiles, @peerfiles, @clockfiles);
|
||||
|
||||
print STDERR "Creating summaries from $statsdir ($startdate to $enddate)\n";
|
||||
|
||||
opendir SDIR, $statsdir or die "directory ${statsdir}: $!";
|
||||
rewinddir SDIR;
|
||||
@loopfiles=sort grep /loop.*$log_date_pattern/, readdir SDIR;
|
||||
rewinddir SDIR;
|
||||
@peerfiles=sort grep /peer.*$log_date_pattern/, readdir SDIR;
|
||||
rewinddir SDIR;
|
||||
@clockfiles=sort grep /clock.*$log_date_pattern/, readdir SDIR;
|
||||
closedir SDIR;
|
||||
|
||||
# remove old summary files
|
||||
map { unlink $_ if -f $_ } ($loop_summary, $peer_summary, $clock_summary);
|
||||
|
||||
my $date;
|
||||
map {
|
||||
$date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
|
||||
if ($date ge $startdate && $date le $enddate) {
|
||||
do_loop $statsdir, $_, $loop_summary;
|
||||
}
|
||||
} @loopfiles;
|
||||
|
||||
map {
|
||||
$date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
|
||||
if ($date ge $startdate && $date le $enddate) {
|
||||
do_peer $statsdir, $_, $peer_summary;
|
||||
}
|
||||
} @peerfiles;
|
||||
|
||||
map {
|
||||
$date = $_; $date =~ s/.*($log_date_pattern)$/$1/;
|
||||
if ($date ge $startdate && $date le $enddate) {
|
||||
do_clock $statsdir, $_, $clock_summary;
|
||||
}
|
||||
} @clockfiles;
|
||||
|
||||
print STDERR "Creating peer summary with limit $peer_dist_limit\n";
|
||||
peer_summary $peer_summary if (-f $peer_summary);
|
Loading…
Reference in New Issue
Block a user