mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 15:45:07 -05:00
Equivalent to V1.19.99.1
This is a verbatim copy of the files at that stage of the repository that was built from the CVS import. It allows future development to see a bit of recent history, but without carrying around the baggage going back to 1997. If that is really required, git grafts can be used.
This commit is contained in:
339
COPYING
Normal file
339
COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
89
INSTALL
Normal file
89
INSTALL
Normal file
@@ -0,0 +1,89 @@
|
||||
The software is distributed as source code which has to be compiled.
|
||||
|
||||
PARTS OF THE SOFTWARE ARE HIGHLY SYSTEM-SPECIFIC AND NON-PORTABLE.
|
||||
UNLESS YOU ARE RUNNING A SUPPORTED SYSTEM, BE PREPARED FOR SOME
|
||||
PROGRAMMING!
|
||||
|
||||
After unpacking the source code, change directory into it, and type
|
||||
|
||||
./configure
|
||||
|
||||
This is a shell script that automatically determines the system type.
|
||||
There is a single optional parameter, --prefix which indicates the
|
||||
directory tree where the software should be installed. For example,
|
||||
|
||||
./configure --prefix=/opt/free
|
||||
|
||||
will install the chronyd daemon into /opt/free/sbin and the chronyc
|
||||
control program into /opt/free/bin. The default value for the prefix
|
||||
is /usr/local.
|
||||
|
||||
The configure script assumes you want to use gcc as your compiler.
|
||||
If you want to use a different compiler, you can configure this way:
|
||||
|
||||
CC=cc CFLAGS=-O ./configure --prefix=/opt/free
|
||||
|
||||
for Bourne-family shells, or
|
||||
|
||||
setenv CC cc
|
||||
setenv CFLAGS -O
|
||||
./configure --prefix=/opt/free
|
||||
|
||||
for C-family shells.
|
||||
|
||||
If the software cannot (yet) be built on your system, an error message
|
||||
will be shown. Otherwise, the files `options.h' and `Makefile' will
|
||||
be generated.
|
||||
|
||||
By default, chronyc will be built to make use of the readline library. If you
|
||||
don't want this, specify the --disable-readline flag to configure. If you have
|
||||
readline and/or ncurses installed in a non-standard location, please refer to
|
||||
the chrony.txt file for information.
|
||||
|
||||
Now type
|
||||
|
||||
make
|
||||
|
||||
to build the programs.
|
||||
|
||||
If you want to build the manual in plain text, HTML and info versions, type
|
||||
|
||||
make docs
|
||||
|
||||
Once the programs have been successfully compiled, they need to be
|
||||
installed in their target locations. This step normally needs to be
|
||||
performed by the superuser, and requires the following command to be
|
||||
entered.
|
||||
|
||||
make install
|
||||
|
||||
This will install the binaries, plain text manual and manpages.
|
||||
|
||||
To install the HTML and info versions of the manual as well, enter the command
|
||||
|
||||
make install-docs
|
||||
|
||||
If you want chrony to appear in the top level info directory listing, you need
|
||||
to run the install-info command manually after this step. install-info takes 2
|
||||
arguments. The first is the path to the chrony.info file you have just
|
||||
installed. This will be the argument you gave to --prefix when you configured
|
||||
(/usr/local by default), with /info/chrony.info on the end. The second
|
||||
argument is the location of the file called 'dir'. This will typically be
|
||||
/usr/info/dir. So the typical command line would be
|
||||
|
||||
install-info /usr/local/info/chrony.info /usr/info/dir
|
||||
|
||||
Now that the software is successfully installed, the next step is to
|
||||
set up a configuration file. The contents of this depend on the
|
||||
network environment in which the computer operates. Typical scenarios
|
||||
are described in the manual. The simplest case is for a computer with
|
||||
a permanent Internet connection - suppose you want to use the NTP
|
||||
server ntp1.foobar.com as your time reference. You would create an
|
||||
/etc/chrony.conf file containing
|
||||
|
||||
server ntp1.foobar.com
|
||||
driftfile /etc/chrony.drift
|
||||
|
||||
and then run /usr/local/sbin/chronyd.
|
||||
|
||||
|
||||
161
Makefile.in
Normal file
161
Makefile.in
Normal file
@@ -0,0 +1,161 @@
|
||||
##################################################
|
||||
#
|
||||
# $Header: /cvs/src/chrony/Makefile.in,v 1.47 2003/04/07 21:43:54 richard Exp $
|
||||
#
|
||||
# =======================================================================
|
||||
#
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# Copyright (C) Richard P. Curnow 1997-2003
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# 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.,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
#
|
||||
# =======================================================================
|
||||
#
|
||||
# Makefile template
|
||||
|
||||
INSTALL_PREFIX=@INSTALL_PREFIX@
|
||||
MANDIR=@MANDIR@
|
||||
INFODIR=@INFODIR@
|
||||
|
||||
CC = @CC@
|
||||
CCWARNFLAGS = @CCWARNFLAGS@
|
||||
OPTFLAGS = @CFLAGS@ @EXTRA_DEFS@
|
||||
|
||||
DESTDIR=
|
||||
|
||||
OBJS = util.o sched.o regress.o local.o \
|
||||
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
|
||||
sources.o sourcestats.o reference.o \
|
||||
logging.o conf.o cmdmon.o md5.o keys.o \
|
||||
nameserv.o acquire.o manual.o addrfilt.o \
|
||||
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
|
||||
broadcast.o
|
||||
|
||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||
|
||||
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \
|
||||
pktlength.o
|
||||
|
||||
SRCS = $(patsubst %.o,%.c,$(OBJS))
|
||||
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
|
||||
|
||||
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
|
||||
|
||||
LIBS = @LIBS@
|
||||
|
||||
EXTRA_LIBS=@EXTRA_LIBS@
|
||||
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
|
||||
|
||||
DEFS=@SYSDEFS@
|
||||
|
||||
CFLAGS = $(CCWARNFLAGS) $(OPTFLAGS)
|
||||
|
||||
# Until we have a main procedure we can link, just build object files
|
||||
# to test compilation
|
||||
|
||||
all : chronyd chronyc
|
||||
|
||||
chronyd : $(OBJS) $(EXTRA_OBJS)
|
||||
$(CC) $(OPTFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LIBS) $(EXTRA_LIBS)
|
||||
|
||||
chronyc : $(CLI_OBJS)
|
||||
$(CC) $(OPTFLAGS) -o chronyc $(CLI_OBJS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
|
||||
|
||||
client.o : client.c
|
||||
$(CC) $(CFLAGS) $(DEFS) @READLINE_COMPILE@ -c $<
|
||||
|
||||
.depend :
|
||||
gcc -MM $(SRCS) $(EXTRA_SRCS) > .depend
|
||||
|
||||
distclean :
|
||||
-rm -f *.o *.s chronyc chronyd core options.h Makefile *~
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~
|
||||
|
||||
version.h : version.txt
|
||||
sed -e 's/[$$]Name: \(.*\) [$$]/\1/;' < version.txt > version.h
|
||||
|
||||
|
||||
# For install, don't use the install command, because its switches
|
||||
# seem to vary between systems.
|
||||
|
||||
install: chronyd chronyc
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX) ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX)/sbin ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)/sbin
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX)/bin ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)/bin
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX)/doc ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)/doc
|
||||
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony
|
||||
cp chronyd $(DESTDIR)$(INSTALL_PREFIX)/sbin/chronyd
|
||||
chmod 555 $(DESTDIR)$(INSTALL_PREFIX)/sbin/chronyd
|
||||
cp chronyc $(DESTDIR)$(INSTALL_PREFIX)/bin/chronyc
|
||||
chmod 555 $(DESTDIR)$(INSTALL_PREFIX)/bin/chronyc
|
||||
cp chrony.txt $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.txt
|
||||
chmod 444 $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.txt
|
||||
cp COPYING $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/COPYING
|
||||
chmod 444 $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/COPYING
|
||||
cp README $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/README
|
||||
chmod 444 $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/README
|
||||
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 444 $(DESTDIR)$(MANDIR)/man1/chrony.1
|
||||
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 444 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
chmod 444 $(DESTDIR)$(MANDIR)/man8/chronyd.8
|
||||
cp chrony.conf.5 $(DESTDIR)$(MANDIR)/man5
|
||||
chmod 444 $(DESTDIR)$(MANDIR)/man5/chrony.conf.5
|
||||
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) $(DEFS) -c $<
|
||||
|
||||
%.s : %.c
|
||||
$(CC) $(CFLAGS) $(DEFS) -S $<
|
||||
|
||||
main.o logging.o client.o : version.h
|
||||
|
||||
# makeinfo v4 required to generate plain text and html
|
||||
MAKEINFO:=makeinfo
|
||||
|
||||
install-docs : docs
|
||||
[ -d $(DESTDIR)$(INSTALL_PREFIX)/doc ] || mkdir -p $(DESTDIR)$(INSTALL_PREFIX)/doc
|
||||
cp chrony.txt $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.txt
|
||||
chown root $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.txt
|
||||
chmod 444 $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.txt
|
||||
cp chrony.html $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.html
|
||||
chown root $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.html
|
||||
chmod 444 $(DESTDIR)$(INSTALL_PREFIX)/doc/chrony/chrony.html
|
||||
[ -d $(DESTDIR)$(INFODIR) ] || mkdir -p $(DESTDIR)$(INFODIR)
|
||||
cp chrony.info* $(DESTDIR)$(INFODIR)
|
||||
chown root $(DESTDIR)$(INFODIR)/chrony.info*
|
||||
chmod 444 $(DESTDIR)$(INFODIR)/chrony.info*
|
||||
|
||||
docs : chrony.txt chrony.html chrony.info
|
||||
|
||||
chrony.txt : chrony.texi
|
||||
$(MAKEINFO) --no-headers --number-sections -o chrony.txt chrony.texi
|
||||
|
||||
chrony.html : chrony.texi
|
||||
$(MAKEINFO) --no-split --html --number-sections -o chrony.html chrony.texi
|
||||
|
||||
chrony.info : chrony.texi
|
||||
$(MAKEINFO) chrony.texi
|
||||
|
||||
# This is only relevant if you're maintaining the website!
|
||||
faq.php : faq.txt faqgen.pl
|
||||
perl faqgen.pl < faq.txt > faq.php
|
||||
|
||||
267
NEWS
Normal file
267
NEWS
Normal file
@@ -0,0 +1,267 @@
|
||||
New in version 1.20
|
||||
===================
|
||||
|
||||
* Many small tidy-ups and security improvements
|
||||
* Improve documentation (RTC support in post 2.0 kernels)
|
||||
* Remove trailing \n from syslog messages
|
||||
* Syslog messages now include IP and port number when packet cannot be sent.
|
||||
* Added the "acquisitionport" directive. (Kalle Olavi Niemitalo)
|
||||
* Use uname(2) instead of /proc/version to get kernel version.
|
||||
* Merge support for Linux on Alpha
|
||||
* Merge support for 64bit architectures
|
||||
* Don't link -lm if it's not needed
|
||||
* Fix Solaris build (broken by 64bit change)
|
||||
* Fix for Linux on SH-5 (floating point denorm handling).
|
||||
* Add detection of Linux 2.5
|
||||
* Allow arbitrary value of HZ in Linux kernel
|
||||
|
||||
New in version 1.19
|
||||
===================
|
||||
|
||||
* Auto-detect kernel's timer interrupt rate (so-called 'HZ') when chronyd
|
||||
starts instead of relying on compiled-in value.
|
||||
* Fix 2 bugs in function that creates the directory for the log and dump files.
|
||||
* Amended webpage URL and contact details.
|
||||
* Generate more informative syslog messages before exiting on failed
|
||||
assertions.
|
||||
* Fix bugs in clamping code for the tick value used when slewing a large
|
||||
offset.
|
||||
* Don't chown files to root during install (should be pointless, and makes RPM
|
||||
building awkward as ordinary user.)
|
||||
* Include chrony.spec file for building RPMs
|
||||
|
||||
New in version 1.18
|
||||
===================
|
||||
* Amend homepage and mailing list information to chrony.sunsite.dk
|
||||
* Delete pidfile on exit from chronyd.
|
||||
* Improvements to readline interface to chronyc
|
||||
* Only generate syslog message when synchronisation is initially lost (instead
|
||||
of on every failed synchronisation attempt)
|
||||
* Use double fork approach when initialising daemon.
|
||||
* More things in contrib directory.
|
||||
* New options to help package builders: --infodir/--mandir for configure, and
|
||||
DESTDIR=xxx for make. (See section 2.2 of chrony.txt for details).
|
||||
* Changed the wording of the messages generated by mailonchange and logchange
|
||||
directives.
|
||||
|
||||
New in version 1.17
|
||||
===================
|
||||
* Port to NetBSD
|
||||
* Configuration supports Linux on PPC
|
||||
* Fix compilation warnings
|
||||
* Several documentation improvements
|
||||
* Bundled manpages (taken from the 'missing manpages project')
|
||||
* Cope with lack of bzero function for Solaris 2.3 systems
|
||||
* Store chronyd's pid in a file (default /var/run/chronyd.pid) and check if
|
||||
chronyd may already be running when starting up. New pidfile directive in
|
||||
configuration file.
|
||||
* Any size subnet is now allowed in allow and deny commands. (Example:
|
||||
6.7.8/20 or 6.7.8.x/20 (any x) mean a 20 bit subnet).
|
||||
* The environment variables CC and CFLAGS passed to configure can now be used
|
||||
to select the compiler and optimisation/debug options to use
|
||||
* Write syslog messages when chronyd loses synchronisation.
|
||||
* Print GPL text when chronyc is run.
|
||||
* Add NTP broadcast server capability (new broadcast directive).
|
||||
* Add 'auto_offline' option to server/peer (conf file) or add server/peer (via
|
||||
chronyc).
|
||||
* Add 'activity' command to chronyc, to report how many servers/peers are
|
||||
currently online/offline.
|
||||
* Fix long-standing bug with how the system time quantum was calculated.
|
||||
* Include support for systems with HZ!=100 (HZ is the timer interrupt
|
||||
frequency).
|
||||
* Include example chrony.conf and chrony.keys files (examples subdirectory).
|
||||
* Include support for readline in chronyc.
|
||||
|
||||
New in version 1.16.1
|
||||
=====================
|
||||
* Fix compilation problem on Linux 2.4.13 (spinlock.h / spinlock_t)
|
||||
|
||||
New in version 1.16
|
||||
===================
|
||||
* More informative captions for 'sources' and 'sourcestats' commands in chronyc
|
||||
(use 'sources -v' and 'sourcestats -v' to get them).
|
||||
* Correct behaviour for Solaris versions>=2.6 (dosynctodr not required on these
|
||||
versions.)
|
||||
* Remove some compiler warnings (Solaris)
|
||||
* If last line of keys file doesn't have end-of-line, don't truncate final
|
||||
character of that key.
|
||||
* Change timestamp format used in logfiles to make it fully numeric (to aid
|
||||
importing data into spreadsheets etc)
|
||||
* Minor documentation updates and improvements.
|
||||
|
||||
New in version 1.15
|
||||
===================
|
||||
* Add contributed change to 'configure' to support Solaris 2.8 on x86
|
||||
* Workaround for assertion failure that arises if two received packets occur
|
||||
close together. (Still need to find out why this happens at all.)
|
||||
* Hopefully fix problem where fast slewing was incompatible with machines
|
||||
that have a large background drift rate (=> tick value went out of range
|
||||
for adjtimex() on Linux.)
|
||||
* Fix rtc_linux.c compile problems with 2.4.x kernel include files.
|
||||
* Include support for RTC device not being at /dev/rtc (new rtcdevice directive
|
||||
in configuration file).
|
||||
* Include support for restricting network interfaces for commands (new
|
||||
bindcmdaddress directive in configuration file)
|
||||
* Fix potential linking fault in pktlength.c (use of CROAK macro replaced by
|
||||
normal assert).
|
||||
* Add some material on bug reporting + contributing to the chrony.texi file
|
||||
* Made the chrony.texi file "Vim6-friendly" (removed xrefs on @node lines,
|
||||
added folding markers to chapters + sections.)
|
||||
* Switched over to GPL for the licence
|
||||
|
||||
New in version 1.14
|
||||
===================
|
||||
* Fix compilation for certain other Linux distributions (including Mandrake
|
||||
7.1)
|
||||
|
||||
New in version 1.13
|
||||
===================
|
||||
* Fixed compilation problems on Redhat/SuSE installations with recent 2.2.x
|
||||
kernels.
|
||||
* Minor tidy-ups and documentation enhancements.
|
||||
* Add support for Linux 2.4 kernels
|
||||
|
||||
New in version 1.12
|
||||
===================
|
||||
|
||||
* Trial fix for long-standing bug in Linux RTC estimator when system time is
|
||||
slewed.
|
||||
* Fix bug in chronyc if -h is specified without a hostname
|
||||
* Fixes to logging various error conditions when operating in daemon mode.
|
||||
* More stuff under contrib/
|
||||
* Changes to README file (e.g. about the new chrony-users mailing list)
|
||||
|
||||
New in version 1.11a
|
||||
====================
|
||||
|
||||
* Minor changes to contact details
|
||||
* Minor changes to installation details (chrony subdirectory under doc/)
|
||||
|
||||
New in version 1.11
|
||||
===================
|
||||
|
||||
* Improve robustness of installation procedure
|
||||
* Tidy up documenation and contact details
|
||||
* Distribute manual as .txt rather than as .ps
|
||||
* Add -n option to chronyc to work with numeric IP addresses rather than
|
||||
names.
|
||||
* Add material in contrib subdirectory
|
||||
* Improve robustness of handling drift file and RTC coefficients file
|
||||
* Improve robustness of regression algorithm
|
||||
|
||||
New in version 1.1
|
||||
==================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* Made linear regression more resistant to rounding errors (old one
|
||||
occasionally generated negative variances which made everything go
|
||||
haywire). Trap infinite or 'not-a-number' values being used to
|
||||
alter system clock to increase robustness further.
|
||||
|
||||
Other changes/Enhancements
|
||||
--------------------------
|
||||
|
||||
* Support for Linux 2.1 and 2.2 kernels
|
||||
|
||||
* New command 'makestep' in chronyc to immediately jump the system
|
||||
time to match the NTP estimated time (Linux only) - a response to
|
||||
systems booting an hour wrong after summertime/wintertime changes,
|
||||
due to RTCs running on local time. Needs extending to Sun driver
|
||||
files too.
|
||||
|
||||
* New directives 'logchange' and 'mailonchange' to log to syslog or
|
||||
email to a specific address respectively if chronyd detects a clock
|
||||
offset exceeding a defined threshold.
|
||||
|
||||
* Added capability to log all client/peer NTP accesses and command
|
||||
accesses (can be turned off with conf file directive 'noclientlog').
|
||||
Added 'clients' command to chronyc to display this data.
|
||||
|
||||
* Improved manual mode to use robust regression rather than 2 point
|
||||
fit.
|
||||
|
||||
* Added 'manual list' and 'manual delete' commands to chronyc to
|
||||
allow display of entered timestamps and discretionary deletion of
|
||||
outliers.
|
||||
|
||||
* If host goes unsynchronised the dummy IP address 0.0.0.0 is detected
|
||||
to avoid attempting a reverse name lookup (to stop dial on demand IP
|
||||
links from being started)
|
||||
|
||||
* Changed chronyc/chronyd protocol so messages are now all variable
|
||||
length. Saves on network bandwidth particularly for large replies
|
||||
from chronyd to chronyc (to support the clients command).
|
||||
|
||||
* Added bindaddress directive to configuration file, to give
|
||||
additional control over limiting which hosts can access the local
|
||||
server.
|
||||
|
||||
* Groundwork done for a port to Windows NT to compile with Cygwin
|
||||
toolkit. chronyc works (to monitor another host). sys_winnt.c
|
||||
needs finishing to use NT clock control API. Program structure
|
||||
needs adapting to use Windows NT service functions, so it can be
|
||||
started at boot time. Hopefully a Windows NT / Cygwin guru with
|
||||
some spare time can take this port over :-)
|
||||
|
||||
New in version 1.02
|
||||
===================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* Fix error messages in chronyc if daemon is not reachable.
|
||||
|
||||
* Fix config file problem for 'allow all' and 'deny all' without a
|
||||
trailing machine address.
|
||||
|
||||
* Remove fatal failed assertion if command socket cannot be read from
|
||||
in daemon.
|
||||
|
||||
* Rewrote timezone handling for Linux real time clock, following
|
||||
various reported problems related to daylight saving.
|
||||
|
||||
Other changes/Enhancements
|
||||
--------------------------
|
||||
|
||||
* Configure script recognizes BSD/386 and uses SunOS 4.1 driver for
|
||||
it.
|
||||
|
||||
* Log files now print date as day-month-year rather than as a day
|
||||
number. Milliseconds removed from timestamps of logged data.
|
||||
Banners included in file to give meanings of columns.
|
||||
|
||||
* Only do 1 initial step (followed by a trimming slew) when
|
||||
initialising from RTC on Linux (previously did 2 steps).
|
||||
|
||||
New in version 1.01
|
||||
===================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* Handle timezone of RTC correctly with respect to daylight saving
|
||||
time
|
||||
|
||||
* Syntax check the chronyc 'local' command properly
|
||||
|
||||
* Fixed assertion failed fault in median finder (used by RTC
|
||||
regression fitting)
|
||||
|
||||
Other changes/Enhancements
|
||||
--------------------------
|
||||
|
||||
* Log selection of new NTP reference source to syslog.
|
||||
|
||||
* Don't zero-pad IP address fields
|
||||
|
||||
* Add new command to chronyc to allow logfiles to be cycled.
|
||||
|
||||
* Extend allow/deny directive syntax in configuration file to so
|
||||
directive can apply to all hosts on the Internet.
|
||||
|
||||
* Tidy up printout of timestamps to make it clear they are in UTC
|
||||
|
||||
* Make 'configure' check the processor type as well as the operating
|
||||
system.
|
||||
243
README
Normal file
243
README
Normal file
@@ -0,0 +1,243 @@
|
||||
This is the README for chrony.
|
||||
|
||||
What is chrony?
|
||||
===============
|
||||
Chrony is a pair of programs for maintaining the accuracy of computer
|
||||
clocks.
|
||||
|
||||
chronyd is a (background) daemon program that can be started at boot
|
||||
time. This does most of the work.
|
||||
|
||||
chronyc is a command-line interface program which can be used to
|
||||
monitor chronyd's performance and to change various operating
|
||||
parateters whilst it is running.
|
||||
|
||||
chronyd's main function is to obtain measurements of the true (UTC)
|
||||
time from one of several sources, and correct the system clock
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
between measurements from the reference.
|
||||
|
||||
The reference time can be derived from either Network Time Protocol
|
||||
(NTP) servers (preferred), or wristwatch-and-keyboard (via chronyc).
|
||||
The main source of information about the Network Time Protocol is
|
||||
http://www.eecis.udel.edu/~ntp.
|
||||
|
||||
It is designed so that it can work on computers which only have
|
||||
intermittent access to reference sources, for example computers which
|
||||
use a dial-up account to access the Internet. Of course, it will work
|
||||
on computers with permanent connections too.
|
||||
|
||||
In addition, the Linux 2.0.x (for x >= 32), 2.2.x and 2.3.x versions
|
||||
can monitor the system's real time clock performance, so the system
|
||||
can maintain accurate time even across reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
chronyd can also operate as an RFC1305-compatible NTP server and peer.
|
||||
|
||||
|
||||
What will chrony run on?
|
||||
========================
|
||||
|
||||
Chrony can be successfully built and run on
|
||||
|
||||
1. Linux v1.2.13, v2.0.x, 2.1.x (partially), 2.2.x, 2.3.x, 2.4.x (i386).
|
||||
Real time clock support is limited to 2.0.32 onwards and to 2.2, 2.3 and
|
||||
2.4 series only. PowerPC is also known to be supported.
|
||||
|
||||
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
|
||||
|
||||
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
|
||||
|
||||
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
|
||||
|
||||
5. NetBSD.
|
||||
|
||||
Any other system will require a porting exercise. You would need to
|
||||
start from one of the existing system-specific drivers and look into
|
||||
the quirks of certain system calls and the kernel on your target
|
||||
system. (This is described in the manual).
|
||||
|
||||
How do I set it up?
|
||||
===================
|
||||
|
||||
The file INSTALL gives instructions. On supported systems the
|
||||
compilation process should be automatic.
|
||||
|
||||
You will need an ANSI C compiler -- gcc is recommended. Versions
|
||||
2.7.2/2.7.2.2 are known to work.
|
||||
|
||||
The manual (in texinfo and text formats) describes how to set the
|
||||
software up for the less straightforward cases.
|
||||
|
||||
What documentation is there?
|
||||
============================
|
||||
|
||||
A manual is supplied in Texinfo format (chrony.texi) and
|
||||
ready-formatted plain text (chrony.txt) in the distribution.
|
||||
|
||||
There is also information available on the chrony web pages, accessible
|
||||
through the URL
|
||||
|
||||
http://chrony.sunsite.dk/
|
||||
|
||||
What can chrony not do?
|
||||
=======================
|
||||
|
||||
Compared to the `reference' RFC1305 implementation xntpd, chronyd does
|
||||
not support hardware reference clocks, leap seconds or broadcast
|
||||
modes.
|
||||
|
||||
Where are new versions announced?
|
||||
=================================
|
||||
|
||||
There is a low volume mailing list where new versions and other
|
||||
important news relating to chrony is announced. You can join this list
|
||||
by sending mail to
|
||||
|
||||
chrony-announce-subscribe@sunsite.dk
|
||||
|
||||
These messages will be copied to chrony-users (see below). I also try
|
||||
to announce new versions on Freshmeat (http://freshmeat.net/).
|
||||
|
||||
I don't reliably announce via news any more - I don't tend to keep up
|
||||
with news as I haven't enough time.
|
||||
|
||||
How can I get support for chrony?
|
||||
and where can I discuss new features, possible bugs etc?
|
||||
========================================================
|
||||
|
||||
There are 3 mailing lists relating to chrony. chrony-announce was
|
||||
mentioned above. chrony-users is a users' discussion list, e.g. for
|
||||
general questions and answers about using chrony. chrony-dev is a more
|
||||
technical list, e.g. for discussing how new features should be
|
||||
implemented, exchange of information between developers etc. To
|
||||
subscribe to either of these lists, send an empty message to
|
||||
|
||||
chrony-users-subscribe@sunsite.dk
|
||||
or
|
||||
chrony-dev-subscribe@sunsite.dk
|
||||
|
||||
as applicable.
|
||||
|
||||
Note that due to family commitments (a 3 year-old and a 1 year-old), I
|
||||
no longer have the time to give to supporting chrony that I once had.
|
||||
Therefore, the chrony-users list should be your main route for support,
|
||||
rather than mailing me directly. Even if it's me that responds to your
|
||||
question on the list, at least *ALL* subscribers then benefit from
|
||||
seeing the discussion, rather than me taking up lots of time on
|
||||
supporting people on a one-to-one basis. If you do mail me directly,
|
||||
don't be surprised if I cc: the response to the mailing list.
|
||||
|
||||
But how can I contact the author if I need to?
|
||||
==============================================
|
||||
|
||||
You can email me at <rc@rc0.org.uk>. If that fails, you could try to
|
||||
find me through one of the mailing lists. It would be nice if:
|
||||
|
||||
- you include the word 'chrony' in the subject line (so my mail reader
|
||||
can sort my mail by topic)
|
||||
|
||||
- you don't send complete log files, encoded binaries etc, without
|
||||
editing such material down to just the relevant bits - a few tens of
|
||||
lines at most. (My dial-up connection handles large messages rather
|
||||
slowly ...).
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
The following people have provided patches and other major contributions
|
||||
to the program :
|
||||
|
||||
Andrew Bishop <amb@gedanken.demon.co.uk>
|
||||
Fixes for bugs in logging when in daemon mode
|
||||
Fixes for compiler warnings
|
||||
Robustness improvements for drift file
|
||||
Improve installation (directory checking etc)
|
||||
Entries in contrib directory
|
||||
Improvements to 'sources' and 'sourcestats' output from chronyc
|
||||
Improvements to documentation
|
||||
Investigation of required dosynctodr behaviour for various Solaris
|
||||
versions.
|
||||
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Entries in contrib directory
|
||||
|
||||
Erik Bryer <ebryer@spots.ab.ca>
|
||||
Entries in contrib directory
|
||||
|
||||
Paul Elliott <pelliott@io.com>
|
||||
DNSchrony (in contrib directory), a tool for handling NTP servers
|
||||
with variable IP addresses.
|
||||
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Alexander Gretencord <arutha@gmx.de>
|
||||
Changes to installation directory system to make it easier for
|
||||
package builders.
|
||||
|
||||
Walter Haidinger <walter.haidinger@gmx.at>
|
||||
Providing me with login access to a Linux installation where v1.12
|
||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
||||
providing the disc space so I can keep an independent backup of the
|
||||
sources.
|
||||
|
||||
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
||||
Port to NetBSD
|
||||
|
||||
John Hasler <john@dhh.gt.org>
|
||||
Changes to support 64 bit machines (i.e. those where
|
||||
sizeof(unsigned long) > 4)
|
||||
|
||||
Liam Hatton <me@liamhatton.com>
|
||||
Advice on configuring for Linux on PPC
|
||||
|
||||
Jachym Holecek <jakym@volny.cz>
|
||||
Patch to make Linux real time clock work with devfs
|
||||
|
||||
Jim Knoble <jmknoble@pobox.com>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Antti Jrvinen <costello@iki.fi>
|
||||
Advice on configuring for BSD/386
|
||||
|
||||
Victor Moroz <vim@prv.adlum.ru>
|
||||
Patch to support Linux with HZ!=100
|
||||
|
||||
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
acquisitionport support
|
||||
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Patch to make chronyc use the readline library if available
|
||||
|
||||
Wolfgang Weisselberg <weissel@netcologne.de>
|
||||
Entries in contrib directory
|
||||
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Many robustness and security improvements
|
||||
|
||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
||||
Providing me with information about the Linux 2.2 kernel
|
||||
functionality compared to 2.0.
|
||||
|
||||
Doug Woodward <dougw@whistler.com>
|
||||
Advice on configuring for Solaris 2.8 on x86
|
||||
|
||||
Many other people have contributed bug reports and suggestions. I'm
|
||||
sorry I can't identify all of you individually.
|
||||
|
||||
Version control information
|
||||
===========================
|
||||
|
||||
$Header: /cvs/src/chrony/README,v 1.27 2003/07/01 20:56:23 richard Exp $
|
||||
|
||||
vim:tw=72
|
||||
688
acquire.c
Normal file
688
acquire.c
Normal file
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/acquire.c,v 1.23 2003/03/27 23:45:47 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Processing to perform the equivalent of what ntpdate does. That is,
|
||||
make a rapid-fire set of measurements to a designated set of
|
||||
sources, and step or slew the local clock to bring it into line with
|
||||
the result.
|
||||
|
||||
This is kept completely separate of the main chronyd processing, by
|
||||
using a separate socket for sending/receiving the measurement
|
||||
packets. That way, ntp_core.c can be kept completely independent of
|
||||
this functionality.
|
||||
|
||||
A few of the finer points of how to construct valid RFC1305 packets
|
||||
and validate responses for this case have been cribbed from the
|
||||
ntpdate source.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "acquire.h"
|
||||
#include "memory.h"
|
||||
#include "sched.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "ntp.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "conf.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Interval between firing off the first sample to successive sources */
|
||||
#define INTER_SOURCE_START (0.2)
|
||||
|
||||
#define MAX_SAMPLES 8
|
||||
|
||||
#define MAX_DEAD_PROBES 4
|
||||
#define N_GOOD_SAMPLES 4
|
||||
|
||||
#define RETRANSMISSION_TIMEOUT (1.0)
|
||||
|
||||
typedef struct { unsigned long ip_addr;
|
||||
int sanity; /* Flag indicating whether source
|
||||
looks sane or not */
|
||||
int n_dead_probes; /* Number of probes sent to the server
|
||||
since a good one */
|
||||
int n_samples; /* Number of samples accumulated */
|
||||
int n_total_samples; /* Total number of samples received
|
||||
including useless ones */
|
||||
double offsets[MAX_SAMPLES]; /* In seconds, positive means local
|
||||
clock is fast of reference */
|
||||
double root_distances[MAX_SAMPLES]; /* in seconds */
|
||||
double inter_lo; /* Low end of estimated range of offset */
|
||||
double inter_hi; /* High end of estimated range of offset */
|
||||
|
||||
NTP_int64 last_tx; /* Transmit timestamp in last packet
|
||||
transmitted to source. */
|
||||
|
||||
int timer_running;
|
||||
SCH_TimeoutID timeout_id;
|
||||
} SourceRecord;
|
||||
|
||||
static SourceRecord *sources;
|
||||
static int n_sources;
|
||||
static int n_started_sources;
|
||||
static int n_completed_sources;
|
||||
|
||||
static int init_slew_threshold = -1;
|
||||
|
||||
static int sock_fd = -1;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void (*saved_after_hook)(void *) = NULL;
|
||||
static void *saved_after_hook_anything = NULL;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
typedef struct {
|
||||
double offset;
|
||||
enum {LO, HIGH} type;
|
||||
int index;
|
||||
} Endpoint;
|
||||
|
||||
typedef struct {
|
||||
double lo;
|
||||
double hi;
|
||||
} Interval;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void read_from_socket(void *anything);
|
||||
static void transmit_timeout(void *x);
|
||||
static void wind_up_acquisition(void);
|
||||
static void start_source_timeout_handler(void *not_used);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static SCH_TimeoutID source_start_timeout_id;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
ACQ_Initialise(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
ACQ_Finalise(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
initialise_io(void)
|
||||
{
|
||||
unsigned short port_number = CNF_GetAcquisitionPort();
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (sock_fd < 0) {
|
||||
LOG_FATAL(LOGF_Acquire, "Could not open socket : %s", strerror(errno));
|
||||
}
|
||||
|
||||
if (port_number == 0) {
|
||||
/* Don't bother binding this socket - we're not fussed what port
|
||||
number it gets */
|
||||
} else {
|
||||
struct sockaddr_in my_addr;
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(port_number);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if (bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s\n", strerror(errno));
|
||||
/* but keep running */
|
||||
}
|
||||
}
|
||||
|
||||
SCH_AddInputFileHandler(sock_fd, read_from_socket, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
finalise_io(void)
|
||||
{
|
||||
if (sock_fd >= 0) {
|
||||
SCH_RemoveInputFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
probe_source(SourceRecord *src)
|
||||
{
|
||||
NTP_Packet pkt;
|
||||
int version = 3;
|
||||
NTP_Mode my_mode = MODE_CLIENT;
|
||||
struct timeval cooked;
|
||||
double local_time_err;
|
||||
struct sockaddr_in his_addr;
|
||||
|
||||
#if 0
|
||||
printf("Sending probe to %08lx sent=%d samples=%d\n", src->ip_addr, src->n_probes_sent, src->n_samples);
|
||||
#endif
|
||||
|
||||
pkt.lvm = (((LEAP_Unsynchronised << 6) & 0xc0) |
|
||||
((version << 3) & 0x38) |
|
||||
((my_mode) & 0x7));
|
||||
|
||||
pkt.stratum = 0;
|
||||
pkt.poll = 4;
|
||||
pkt.precision = -6; /* as ntpdate */
|
||||
pkt.root_delay = double_to_int32(1.0); /* 1 second */
|
||||
pkt.root_dispersion = double_to_int32(1.0); /* likewise */
|
||||
pkt.reference_id = 0UL;
|
||||
pkt.reference_ts.hi = 0; /* Set to 0 */
|
||||
pkt.reference_ts.lo = 0; /* Set to 0 */
|
||||
pkt.originate_ts.hi = 0; /* Set to 0 */
|
||||
pkt.originate_ts.lo = 0; /* Set to 0 */
|
||||
pkt.receive_ts.hi = 0; /* Set to 0 */
|
||||
pkt.receive_ts.lo = 0; /* Set to 0 */
|
||||
|
||||
/* And do transmission */
|
||||
his_addr.sin_addr.s_addr = htonl(src->ip_addr);
|
||||
his_addr.sin_port = htons(123); /* Fixed for now */
|
||||
his_addr.sin_family = AF_INET;
|
||||
|
||||
LCL_ReadCookedTime(&cooked, &local_time_err);
|
||||
UTI_TimevalToInt64(&cooked, &pkt.transmit_ts);
|
||||
|
||||
if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE,
|
||||
0,
|
||||
(struct sockaddr *) &his_addr, sizeof(his_addr)) < 0) {
|
||||
LOG(LOGS_WARN, LOGF_Acquire, "Could not send to %s : %s",
|
||||
UTI_IPToDottedQuad(src->ip_addr),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
src->last_tx = pkt.transmit_ts;
|
||||
|
||||
++(src->n_dead_probes);
|
||||
src->timer_running = 1;
|
||||
src->timeout_id = SCH_AddTimeoutByDelay(RETRANSMISSION_TIMEOUT, transmit_timeout, (void *) src);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
transmit_timeout(void *x)
|
||||
{
|
||||
SourceRecord *src = (SourceRecord *) x;
|
||||
|
||||
src->timer_running = 0;
|
||||
|
||||
#if 0
|
||||
printf("Timeout expired for server %08lx\n", src->ip_addr);
|
||||
#endif
|
||||
|
||||
if (src->n_dead_probes < MAX_DEAD_PROBES) {
|
||||
probe_source(src);
|
||||
} else {
|
||||
/* Source has croaked or is taking too long to respond */
|
||||
++n_completed_sources;
|
||||
if (n_completed_sources == n_sources) {
|
||||
wind_up_acquisition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_STRATUM 15
|
||||
|
||||
static void
|
||||
process_receive(NTP_Packet *msg, SourceRecord *src, struct timeval *now)
|
||||
{
|
||||
|
||||
unsigned long lvm;
|
||||
int leap, version, mode;
|
||||
double root_delay, root_dispersion;
|
||||
double total_root_delay, total_root_dispersion, total_root_distance;
|
||||
|
||||
struct timeval local_orig, local_average, remote_rx, remote_tx, remote_average;
|
||||
double remote_interval, local_interval;
|
||||
double delta, theta, epsilon;
|
||||
int n;
|
||||
|
||||
/* Most of the checks are from ntpdate */
|
||||
|
||||
/* Need to do something about authentication */
|
||||
|
||||
lvm = msg->lvm;
|
||||
leap = (lvm >> 6) & 0x3;
|
||||
version = (lvm >> 3) & 0x7;
|
||||
mode = lvm & 0x7;
|
||||
|
||||
if ((leap == LEAP_Unsynchronised) ||
|
||||
(version != 3) ||
|
||||
(mode != MODE_SERVER && mode != MODE_PASSIVE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->stratum > MAX_STRATUM) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether server is responding to our last request */
|
||||
if ((msg->originate_ts.hi != src->last_tx.hi) ||
|
||||
(msg->originate_ts.lo != src->last_tx.lo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check that the server is sane */
|
||||
if (((msg->originate_ts.hi == 0) && (msg->originate_ts.lo == 0)) ||
|
||||
((msg->receive_ts.hi == 0) && (msg->receive_ts.lo) == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
root_delay = int32_to_double(msg->root_delay);
|
||||
root_dispersion = int32_to_double(msg->root_dispersion);
|
||||
|
||||
UTI_Int64ToTimeval(&src->last_tx, &local_orig);
|
||||
UTI_Int64ToTimeval(&msg->receive_ts, &remote_rx);
|
||||
UTI_Int64ToTimeval(&msg->transmit_ts, &remote_tx);
|
||||
UTI_AverageDiffTimevals(&remote_rx, &remote_tx, &remote_average, &remote_interval);
|
||||
UTI_AverageDiffTimevals(&local_orig, now, &local_average, &local_interval);
|
||||
|
||||
delta = local_interval - remote_interval;
|
||||
|
||||
/* Defined as positive if we are fast. Note this sign convention is
|
||||
opposite to that used in ntp_core.c */
|
||||
|
||||
UTI_DiffTimevalsToDouble(&theta, &local_average, &remote_average);
|
||||
|
||||
/* Could work out epsilon - leave till later */
|
||||
epsilon = 0.0;
|
||||
|
||||
total_root_delay = fabs(delta) + root_delay;
|
||||
total_root_dispersion = epsilon + root_dispersion;
|
||||
total_root_distance = 0.5 * fabs(total_root_delay) + total_root_dispersion;
|
||||
|
||||
n = src->n_samples;
|
||||
#if 0
|
||||
printf("Sample %d theta=%.6f delta=%.6f root_del=%.6f root_disp=%.6f root_dist=%.6f\n",
|
||||
n, theta, delta, total_root_delay, total_root_dispersion, total_root_distance);
|
||||
#endif
|
||||
src->offsets[n] = theta;
|
||||
src->root_distances[n] = total_root_distance;
|
||||
++(src->n_samples);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
read_from_socket(void *anything)
|
||||
{
|
||||
int status;
|
||||
ReceiveBuffer msg;
|
||||
struct sockaddr_in his_addr;
|
||||
int his_addr_len;
|
||||
int flags;
|
||||
int message_length;
|
||||
unsigned long remote_ip;
|
||||
int i, ok;
|
||||
struct timeval now;
|
||||
double local_time_err;
|
||||
SourceRecord *src;
|
||||
|
||||
flags = 0;
|
||||
message_length = sizeof(msg);
|
||||
his_addr_len = sizeof(his_addr);
|
||||
|
||||
/* Get timestamp */
|
||||
LCL_ReadCookedTime(&now, &local_time_err);
|
||||
|
||||
status = recvfrom (sock_fd, (char *)&msg, message_length, flags,
|
||||
(struct sockaddr *) &his_addr, &his_addr_len);
|
||||
|
||||
if (status < 0) {
|
||||
LOG(LOGS_WARN, LOGF_Acquire, "Error reading from socket, %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
remote_ip = ntohl(his_addr.sin_addr.s_addr);
|
||||
|
||||
#if 0
|
||||
printf("Got message from %08lx\n", remote_ip);
|
||||
#endif
|
||||
|
||||
/* Find matching host */
|
||||
ok = 0;
|
||||
for (i=0; i<n_sources; i++) {
|
||||
if (remote_ip == sources[i].ip_addr) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
|
||||
src = sources + i;
|
||||
++src->n_total_samples;
|
||||
|
||||
src->n_dead_probes = 0; /* reset this when we actually receive something */
|
||||
|
||||
/* If we got into this function, we know the retransmission timeout has not
|
||||
expired for the source */
|
||||
if (src->timer_running) {
|
||||
SCH_RemoveTimeout(src->timeout_id);
|
||||
src->timer_running = 0;
|
||||
}
|
||||
|
||||
process_receive(&msg.ntp_pkt, src, &now);
|
||||
|
||||
/* Check if server done and requeue timeout */
|
||||
if ((src->n_samples >= N_GOOD_SAMPLES) ||
|
||||
(src->n_total_samples >= MAX_SAMPLES)) {
|
||||
++n_completed_sources;
|
||||
#if 0
|
||||
printf("Source %08lx completed\n", src->ip_addr);
|
||||
#endif
|
||||
if (n_completed_sources == n_sources) {
|
||||
wind_up_acquisition();
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Send the next probe */
|
||||
probe_source(src);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_next_source(void)
|
||||
{
|
||||
probe_source(sources + n_started_sources);
|
||||
#if 0
|
||||
printf("Trying to start source %08lx\n", sources[n_started_sources].ip_addr);
|
||||
#endif
|
||||
n_started_sources++;
|
||||
|
||||
if (n_started_sources < n_sources) {
|
||||
source_start_timeout_id = SCH_AddTimeoutByDelay(INTER_SOURCE_START, start_source_timeout_handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
endpoint_compare(const void *a, const void *b)
|
||||
{
|
||||
const Endpoint *aa = (const Endpoint *) a;
|
||||
const Endpoint *bb = (const Endpoint *) b;
|
||||
|
||||
if (aa->offset < bb->offset) {
|
||||
return -1;
|
||||
} else if (aa->offset > bb->offset) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_measurements(void)
|
||||
{
|
||||
|
||||
SourceRecord *s;
|
||||
Endpoint *eps;
|
||||
int i, j;
|
||||
int n_sane_sources;
|
||||
double lo, hi;
|
||||
double inter_lo, inter_hi;
|
||||
|
||||
int depth;
|
||||
int best_depth;
|
||||
int n_at_best_depth;
|
||||
Interval *intervals;
|
||||
double estimated_offset;
|
||||
int index1, index2;
|
||||
|
||||
n_sane_sources = 0;
|
||||
|
||||
/* First, get a consistent interval for each source. Those for
|
||||
which this is not possible are considered to be insane. */
|
||||
|
||||
for (i=0; i<n_sources; i++) {
|
||||
s = sources + i;
|
||||
/* If we got no measurements, the source is insane */
|
||||
if (s->n_samples == 0) {
|
||||
s->sanity = 0;
|
||||
} else {
|
||||
s->sanity = 1; /* so far ... */
|
||||
lo = s->offsets[0] - s->root_distances[0];
|
||||
hi = s->offsets[0] + s->root_distances[0];
|
||||
inter_lo = lo;
|
||||
inter_hi = hi;
|
||||
for (j=1; j<s->n_samples; j++) {
|
||||
lo = s->offsets[j] - s->root_distances[j];
|
||||
hi = s->offsets[j] + s->root_distances[j];
|
||||
if ((inter_hi <= lo) || (inter_lo >= hi)) {
|
||||
/* Oh dear, we won't get an interval for this source */
|
||||
s->sanity = 0;
|
||||
break;
|
||||
} else {
|
||||
inter_lo = (lo < inter_lo) ? inter_lo : lo;
|
||||
inter_hi = (hi > inter_hi) ? inter_hi : hi;
|
||||
}
|
||||
}
|
||||
if (s->sanity) {
|
||||
s->inter_lo = inter_lo;
|
||||
s->inter_hi = inter_hi;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->sanity) {
|
||||
++n_sane_sources;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Now build the endpoint list, similar to the RFC1305 clock
|
||||
selection algorithm. */
|
||||
eps = MallocArray(Endpoint, 2*n_sane_sources);
|
||||
intervals = MallocArray(Interval, n_sane_sources);
|
||||
|
||||
j = 0;
|
||||
for (i=0; i<n_sources; i++) {
|
||||
s = sources + i;
|
||||
if (s->sanity) {
|
||||
eps[j].offset = s->inter_lo;
|
||||
eps[j].type = LO;
|
||||
eps[j].index = i;
|
||||
eps[j+1].offset = s->inter_hi;
|
||||
eps[j+1].type = HIGH;
|
||||
eps[j+1].index = i;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(eps, 2*n_sane_sources, sizeof(Endpoint), endpoint_compare);
|
||||
|
||||
/* Now do depth searching algorithm */
|
||||
n_at_best_depth = best_depth = depth = 0;
|
||||
for (i=0; i<2*n_sane_sources; i++) {
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "Endpoint type %s source index %d [ip=%08lx] offset=%.6f\n",
|
||||
(eps[i].type == LO) ? "LO" : "HIGH",
|
||||
eps[i].index,
|
||||
sources[eps[i].index].ip_addr,
|
||||
eps[i].offset);
|
||||
#endif
|
||||
|
||||
switch (eps[i].type) {
|
||||
case LO:
|
||||
depth++;
|
||||
if (depth > best_depth) {
|
||||
best_depth = depth;
|
||||
n_at_best_depth = 0;
|
||||
intervals[0].lo = eps[i].offset;
|
||||
} else if (depth == best_depth) {
|
||||
intervals[n_at_best_depth].lo = eps[i].offset;
|
||||
} else {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HIGH:
|
||||
if (depth == best_depth) {
|
||||
intervals[n_at_best_depth].hi = eps[i].offset;
|
||||
n_at_best_depth++;
|
||||
}
|
||||
|
||||
depth--;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (best_depth > 0) {
|
||||
if ((n_at_best_depth % 2) == 1) {
|
||||
index1 = (n_at_best_depth - 1) / 2;
|
||||
estimated_offset = 0.5 * (intervals[index1].lo + intervals[index1].hi);
|
||||
} else {
|
||||
index2 = (n_at_best_depth / 2);
|
||||
index1 = index2 - 1;
|
||||
estimated_offset = 0.5 * (intervals[index1].lo + intervals[index2].hi);
|
||||
}
|
||||
|
||||
|
||||
/* Apply a step change to the system clock. As per sign
|
||||
convention in local.c and its children, a positive offset means
|
||||
the system clock is fast of the reference, i.e. it needs to be
|
||||
stepped backwards. */
|
||||
|
||||
if (fabs(estimated_offset) > (double) init_slew_threshold) {
|
||||
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (step)",
|
||||
fabs(estimated_offset),
|
||||
(estimated_offset >= 0) ? "fast" : "slow");
|
||||
LCL_ApplyStepOffset(estimated_offset);
|
||||
} else {
|
||||
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
|
||||
fabs(estimated_offset),
|
||||
(estimated_offset >= 0) ? "fast" : "slow");
|
||||
LCL_AccumulateOffset(estimated_offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Acquire, "No intersecting endpoints found");
|
||||
}
|
||||
|
||||
Free(intervals);
|
||||
Free(eps);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
wind_up_acquisition(void)
|
||||
{
|
||||
|
||||
/* Now process measurements */
|
||||
process_measurements();
|
||||
|
||||
Free(sources);
|
||||
|
||||
finalise_io();
|
||||
|
||||
if (saved_after_hook) {
|
||||
(saved_after_hook)(saved_after_hook_anything);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_source_timeout_handler(void *not_used)
|
||||
{
|
||||
|
||||
start_next_source();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
ACQ_StartAcquisition(int n, unsigned long *ip_addrs, int threshold, void (*after_hook)(void *), void *anything)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
saved_after_hook = after_hook;
|
||||
saved_after_hook_anything = anything;
|
||||
|
||||
init_slew_threshold = threshold;
|
||||
|
||||
n_started_sources = 0;
|
||||
n_completed_sources = 0;
|
||||
n_sources = n;
|
||||
sources = MallocArray(SourceRecord, n);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
sources[i].ip_addr = ip_addrs[i];
|
||||
sources[i].n_samples = 0;
|
||||
sources[i].n_total_samples = 0;
|
||||
sources[i].n_dead_probes = 0;
|
||||
}
|
||||
|
||||
initialise_io();
|
||||
|
||||
/* Start sampling first source */
|
||||
start_next_source();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
47
acquire.h
Normal file
47
acquire.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/acquire.h,v 1.9 2002/02/28 23:27:07 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for acquisition module
|
||||
*/
|
||||
|
||||
#ifndef GOT_ACQUIRE_H
|
||||
#define GOT_ACQUIRE_H
|
||||
|
||||
typedef struct ACQ_SourceRecord *ACQ_Source;
|
||||
|
||||
extern void ACQ_Initialise(void);
|
||||
|
||||
extern void ACQ_Finalise(void);
|
||||
|
||||
extern void ACQ_StartAcquisition(int n, unsigned long *ip_addrs, int init_slew_threshold,
|
||||
void (*after_hook)(void *), void *anything);
|
||||
|
||||
extern void ACQ_AccumulateSample(ACQ_Source acq_source, double offset, double root_distance);
|
||||
|
||||
extern void ACQ_MissedSample(ACQ_Source acq_source);
|
||||
|
||||
#endif /* GOT_ACQUIRE_H */
|
||||
46
addressing.h
Normal file
46
addressing.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/addressing.h,v 1.7 2002/02/28 23:27:08 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Types used for addressing sources etc
|
||||
*/
|
||||
|
||||
#ifndef GOT_ADDRESSING_H
|
||||
#define GOT_ADDRESSING_H
|
||||
|
||||
/* This type is used to represent an IPv4 address and port
|
||||
number. Both parts are in HOST order, NOT network order. */
|
||||
typedef struct {
|
||||
unsigned long ip_addr;
|
||||
unsigned short port;
|
||||
} NTP_Remote_Address;
|
||||
|
||||
#if 0
|
||||
unsigned long NTP_IP_Address;
|
||||
#endif
|
||||
|
||||
#endif /* GOT_ADDRESSING_H */
|
||||
|
||||
385
addrfilt.c
Normal file
385
addrfilt.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/addrfilt.c,v 1.8 2002/02/28 23:27:08 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module provides a set of routines for checking IP addresses
|
||||
against a set of rules and deciding whether they are allowed or
|
||||
disallowed.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "addrfilt.h"
|
||||
#include "memory.h"
|
||||
|
||||
/* Define the number of bits which are stripped off per level of
|
||||
indirection in the tables */
|
||||
#define NBITS 4
|
||||
|
||||
/* Define the table size */
|
||||
#define TABLE_SIZE (1UL<<NBITS)
|
||||
|
||||
struct _TableNode;
|
||||
|
||||
typedef struct _TableNode ExtendedTable[TABLE_SIZE];
|
||||
|
||||
typedef enum {DENY, ALLOW, AS_PARENT} State;
|
||||
|
||||
typedef struct _TableNode {
|
||||
State state;
|
||||
ExtendedTable *extended;
|
||||
} TableNode;
|
||||
|
||||
struct ADF_AuthTableInst {
|
||||
TableNode base;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
inline static unsigned long
|
||||
get_subnet(unsigned long addr)
|
||||
{
|
||||
return (addr >> (32-NBITS)) & ((1UL<<NBITS) - 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
inline static unsigned long
|
||||
get_residual(unsigned long addr)
|
||||
{
|
||||
return (addr << NBITS);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ADF_AuthTable
|
||||
ADF_CreateTable(void)
|
||||
{
|
||||
ADF_AuthTable result;
|
||||
result = MallocNew(struct ADF_AuthTableInst);
|
||||
|
||||
/* Default is that nothing is allowed */
|
||||
result->base.state = DENY;
|
||||
result->base.extended = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function deletes all definitions of child nodes, in effect
|
||||
pruning a whole subnet definition back to a single parent
|
||||
record. */
|
||||
static void
|
||||
close_node(TableNode *node)
|
||||
{
|
||||
int i;
|
||||
TableNode *child_node;
|
||||
|
||||
if (node->extended != NULL) {
|
||||
for (i=0; i<TABLE_SIZE; i++) {
|
||||
child_node = &((*(node->extended))[i]);
|
||||
close_node(child_node);
|
||||
}
|
||||
Free(node->extended);
|
||||
node->extended = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
/* Allocate the extension field in a node, and set all the children's
|
||||
states to default to that of the node being extended */
|
||||
|
||||
static void
|
||||
open_node(TableNode *node)
|
||||
{
|
||||
int i;
|
||||
TableNode *child_node;
|
||||
|
||||
if (node->extended == NULL) {
|
||||
|
||||
node->extended = MallocNew(ExtendedTable);
|
||||
|
||||
for (i=0; i<TABLE_SIZE; i++) {
|
||||
child_node = &((*(node->extended))[i]);
|
||||
child_node->state = AS_PARENT;
|
||||
child_node->extended = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static ADF_Status
|
||||
set_subnet(TableNode *start_node,
|
||||
unsigned long ip,
|
||||
int subnet_bits,
|
||||
State new_state,
|
||||
int delete_children)
|
||||
{
|
||||
int bits_to_go;
|
||||
unsigned long residual;
|
||||
unsigned long subnet;
|
||||
TableNode *node;
|
||||
|
||||
bits_to_go = subnet_bits;
|
||||
residual = ip;
|
||||
node = start_node;
|
||||
|
||||
if ((subnet_bits < 0) ||
|
||||
(subnet_bits > 32)) {
|
||||
|
||||
return ADF_BADSUBNET;
|
||||
|
||||
} else {
|
||||
|
||||
if ((bits_to_go & (NBITS-1)) == 0) {
|
||||
|
||||
while (bits_to_go > 0) {
|
||||
subnet = get_subnet(residual);
|
||||
residual = get_residual(residual);
|
||||
if (!(node->extended)) {
|
||||
open_node(node);
|
||||
}
|
||||
node = &((*(node->extended))[subnet]);
|
||||
bits_to_go -= NBITS;
|
||||
}
|
||||
|
||||
if (delete_children) {
|
||||
close_node(node);
|
||||
}
|
||||
node->state = new_state;
|
||||
|
||||
} else { /* Have to set multiple entries */
|
||||
int N, i, j;
|
||||
TableNode *this_node;
|
||||
|
||||
while (bits_to_go >= NBITS) {
|
||||
subnet = get_subnet(residual);
|
||||
residual = get_residual(residual);
|
||||
if (!(node->extended)) {
|
||||
open_node(node);
|
||||
}
|
||||
node = &((*(node->extended))[subnet]);
|
||||
bits_to_go -= NBITS;
|
||||
}
|
||||
|
||||
/* How many subnet entries to set : 1->8, 2->4, 3->2 */
|
||||
N = 1 << (NBITS-bits_to_go);
|
||||
subnet = get_subnet(residual);
|
||||
if (!(node->extended)) {
|
||||
open_node(node);
|
||||
}
|
||||
|
||||
for (i=subnet, j=0; j<N; i++, j++) {
|
||||
this_node = &((*(node->extended))[i]);
|
||||
if (delete_children) {
|
||||
close_node(this_node);
|
||||
}
|
||||
this_node->state = new_state;
|
||||
}
|
||||
}
|
||||
|
||||
return ADF_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ADF_Status
|
||||
ADF_Allow(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits)
|
||||
{
|
||||
return set_subnet(&(table->base), ip, subnet_bits, ALLOW, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
ADF_Status
|
||||
ADF_AllowAll(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits)
|
||||
{
|
||||
return set_subnet(&(table->base), ip, subnet_bits, ALLOW, 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ADF_Status
|
||||
ADF_Deny(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits)
|
||||
{
|
||||
return set_subnet(&(table->base), ip, subnet_bits, DENY, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ADF_Status
|
||||
ADF_DenyAll(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits)
|
||||
{
|
||||
return set_subnet(&(table->base), ip, subnet_bits, DENY, 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
ADF_DestroyTable(ADF_AuthTable table)
|
||||
{
|
||||
close_node(&(table->base));
|
||||
Free(table);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_ip_in_node(TableNode *start_node, unsigned long ip)
|
||||
{
|
||||
unsigned long residual, subnet;
|
||||
int result = 0;
|
||||
int finished = 0;
|
||||
TableNode *node;
|
||||
State state=DENY;
|
||||
|
||||
node = start_node;
|
||||
residual = ip;
|
||||
|
||||
do {
|
||||
if (node->state != AS_PARENT) {
|
||||
state = node->state;
|
||||
}
|
||||
if (node->extended) {
|
||||
subnet = get_subnet(residual);
|
||||
residual = get_residual(residual);
|
||||
node = &((*(node->extended))[subnet]);
|
||||
} else {
|
||||
/* Make decision on this node */
|
||||
finished = 1;
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
switch (state) {
|
||||
case ALLOW:
|
||||
result = 1;
|
||||
break;
|
||||
case DENY:
|
||||
result = 0;
|
||||
break;
|
||||
case AS_PARENT:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
ADF_IsAllowed(ADF_AuthTable table,
|
||||
unsigned long ip)
|
||||
{
|
||||
|
||||
return check_ip_in_node(&(table->base), ip);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined TEST
|
||||
|
||||
static void print_node(TableNode *node, unsigned long addr, int shift, int subnet_bits)
|
||||
{
|
||||
unsigned long new_addr;
|
||||
int i;
|
||||
TableNode *sub_node;
|
||||
|
||||
for (i=0; i<subnet_bits; i++) putchar(' ');
|
||||
|
||||
printf("%d.%d.%d.%d/%d : %s\n",
|
||||
((addr >> 24) & 255),
|
||||
((addr >> 16) & 255),
|
||||
((addr >> 8) & 255),
|
||||
((addr ) & 255),
|
||||
subnet_bits,
|
||||
(node->state == ALLOW) ? "allow" :
|
||||
(node->state == DENY) ? "deny" : "as parent");
|
||||
if (node->extended) {
|
||||
for (i=0; i<16; i++) {
|
||||
sub_node = &((*(node->extended))[i]);
|
||||
new_addr = addr | ((unsigned long) i << shift);
|
||||
print_node(sub_node, new_addr, shift - 4, subnet_bits + 4);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void print_table(ADF_AuthTable table)
|
||||
{
|
||||
unsigned long addr = 0;
|
||||
int shift = 28;
|
||||
int subnet_bits = 0;
|
||||
|
||||
print_node(&table->base, addr, shift, subnet_bits);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
ADF_AuthTable table;
|
||||
table = ADF_CreateTable();
|
||||
|
||||
ADF_Allow(table, 0x7e800000, 9);
|
||||
ADF_Deny(table, 0x7ecc0000, 14);
|
||||
/* ADF_Deny(table, 0x7f000001, 32); */
|
||||
/* ADF_Allow(table, 0x7f000000, 8); */
|
||||
|
||||
print_table(table);
|
||||
|
||||
ADF_DestroyTable(table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* defined TEST */
|
||||
|
||||
|
||||
|
||||
|
||||
77
addrfilt.h
Normal file
77
addrfilt.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/addrfilt.h,v 1.6 2002/02/28 23:27:08 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Module for providing an authorisation filter on IP addresses
|
||||
*/
|
||||
|
||||
#ifndef GOT_ADDRFILT_H
|
||||
#define GOT_ADDRFILT_H
|
||||
|
||||
typedef struct ADF_AuthTableInst *ADF_AuthTable;
|
||||
|
||||
typedef enum {
|
||||
ADF_SUCCESS,
|
||||
ADF_BADSUBNET
|
||||
} ADF_Status;
|
||||
|
||||
|
||||
/* Create a new table. The default rule is deny for everything */
|
||||
extern ADF_AuthTable ADF_CreateTable(void);
|
||||
|
||||
/* Allow anything in the supplied subnet, EXCEPT for any more specific
|
||||
subnets that are already defined */
|
||||
extern ADF_Status ADF_Allow(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits);
|
||||
|
||||
/* Allow anything in the supplied subnet, overwriting existing
|
||||
definitions for any more specific subnets */
|
||||
extern ADF_Status ADF_AllowAll(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits);
|
||||
|
||||
/* Deny anything in the supplied subnet, EXCEPT for any more specific
|
||||
subnets that are already defined */
|
||||
extern ADF_Status ADF_Deny(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits);
|
||||
|
||||
/* Deny anything in the supplied subnet, overwriting existing
|
||||
definitions for any more specific subnets */
|
||||
extern ADF_Status ADF_DenyAll(ADF_AuthTable table,
|
||||
unsigned long ip,
|
||||
int subnet_bits);
|
||||
|
||||
/* Clear up the table */
|
||||
extern void ADF_DestroyTable(ADF_AuthTable table);
|
||||
|
||||
/* Check whether a given IP address is allowed by the rules in
|
||||
the table */
|
||||
extern int ADF_IsAllowed(ADF_AuthTable table,
|
||||
unsigned long ip);
|
||||
|
||||
#endif /* GOT_ADDRFILT_H */
|
||||
159
broadcast.c
Normal file
159
broadcast.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/broadcast.c,v 1.3 2002/02/28 23:27:08 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Deal with broadcast server functions.
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "addressing.h"
|
||||
#include "broadcast.h"
|
||||
#include "sched.h"
|
||||
#include "ntp.h"
|
||||
#include "local.h"
|
||||
#include "reference.h"
|
||||
#include "util.h"
|
||||
#include "ntp_io.h"
|
||||
|
||||
typedef struct {
|
||||
NTP_Remote_Address addr;
|
||||
int interval;
|
||||
} Destination;
|
||||
static Destination *destinations = 0;
|
||||
static int n_destinations = 0;
|
||||
static int max_destinations = 0;
|
||||
|
||||
void
|
||||
BRD_Initialise(void)
|
||||
{
|
||||
return; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
BRD_Finalise(void)
|
||||
{
|
||||
return; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This is a cut-down version of what transmit_packet in ntp_core.c does */
|
||||
|
||||
static void
|
||||
timeout_handler(void *arbitrary)
|
||||
{
|
||||
Destination *d = (Destination *) arbitrary;
|
||||
NTP_Packet message;
|
||||
/* Parameters read from reference module */
|
||||
int version;
|
||||
int leap;
|
||||
int are_we_synchronised, our_stratum;
|
||||
NTP_Leap leap_status;
|
||||
unsigned long our_ref_id;
|
||||
struct timeval our_ref_time;
|
||||
double our_root_delay, our_root_dispersion;
|
||||
double local_time_err;
|
||||
struct timeval local_transmit;
|
||||
|
||||
version = 3;
|
||||
|
||||
LCL_ReadCookedTime(&local_transmit, &local_time_err);
|
||||
REF_GetReferenceParams(&local_transmit,
|
||||
&are_we_synchronised, &leap_status,
|
||||
&our_stratum,
|
||||
&our_ref_id, &our_ref_time,
|
||||
&our_root_delay, &our_root_dispersion);
|
||||
|
||||
|
||||
if (are_we_synchronised) {
|
||||
leap = (int) leap_status;
|
||||
} else {
|
||||
leap = 3;
|
||||
}
|
||||
|
||||
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
|
||||
message.stratum = our_stratum;
|
||||
message.poll = 6; /* FIXME: what should this be? */
|
||||
message.precision = LCL_GetSysPrecisionAsLog();
|
||||
|
||||
/* If we're sending a client mode packet and we aren't synchronized yet,
|
||||
we might have to set up artificial values for some of these parameters */
|
||||
message.root_delay = double_to_int32(our_root_delay);
|
||||
message.root_dispersion = double_to_int32(our_root_dispersion);
|
||||
|
||||
message.reference_id = htonl((NTP_int32) our_ref_id);
|
||||
|
||||
/* Now fill in timestamps */
|
||||
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts);
|
||||
message.originate_ts.hi = 0UL;
|
||||
message.originate_ts.lo = 0UL;
|
||||
message.receive_ts.hi = 0UL;
|
||||
message.receive_ts.lo = 0UL;
|
||||
|
||||
LCL_ReadCookedTime(&local_transmit, &local_time_err);
|
||||
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
|
||||
NIO_SendNormalPacket(&message, &d->addr);
|
||||
|
||||
/* Requeue timeout. Don't care if interval drifts gradually, so just do it
|
||||
* at the end. */
|
||||
SCH_AddTimeoutInClass((double) d->interval, 1.0,
|
||||
SCH_NtpBroadcastClass,
|
||||
timeout_handler, (void *) d);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
BRD_AddDestination(unsigned long addr, unsigned short port, int interval)
|
||||
{
|
||||
if (max_destinations == n_destinations) {
|
||||
/* Expand array */
|
||||
max_destinations += 8;
|
||||
if (destinations) {
|
||||
destinations = ReallocArray(Destination, max_destinations, destinations);
|
||||
} else {
|
||||
destinations = MallocArray(Destination, max_destinations);
|
||||
}
|
||||
}
|
||||
|
||||
destinations[n_destinations].addr.ip_addr = addr;
|
||||
destinations[n_destinations].addr.port = port;
|
||||
destinations[n_destinations].interval = interval;
|
||||
|
||||
SCH_AddTimeoutInClass((double) interval, 1.0,
|
||||
SCH_NtpBroadcastClass,
|
||||
timeout_handler, (void *)(destinations + n_destinations));
|
||||
|
||||
++n_destinations;
|
||||
|
||||
}
|
||||
|
||||
|
||||
39
broadcast.h
Normal file
39
broadcast.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/broadcast.h,v 1.2 2002/02/28 23:27:08 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Deal with broadcast server functions.
|
||||
*/
|
||||
|
||||
#ifndef GOT_BROADCAST_H
|
||||
#define GOT_BROADCAST_H
|
||||
|
||||
extern void BRD_Initialise(void);
|
||||
extern void BRD_Finalise(void);
|
||||
extern void BRD_AddDestination(unsigned long addr, unsigned short port, int interval);
|
||||
|
||||
#endif /* GOT_BROADCAST_H */
|
||||
|
||||
24
build_kit
Executable file
24
build_kit
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env perl
|
||||
# $Header: /cvs/src/chrony/build_kit,v 1.13 2003/01/12 23:50:54 richard Exp $
|
||||
# Perl script for building a release
|
||||
|
||||
chmod 0755, "configure";
|
||||
|
||||
# Construct chrony.spec file
|
||||
$version = $ARGV[0] || die "No version on command line";
|
||||
open (IN, "<chrony.spec.sample");
|
||||
open (OUT, ">chrony.spec");
|
||||
while (<IN>) {
|
||||
s/\@\@VERSION\@\@/$version/;
|
||||
print OUT;
|
||||
}
|
||||
close (IN);
|
||||
close (OUT);
|
||||
|
||||
unlink "chrony.spec.sample";
|
||||
|
||||
# Requires the makeinfo from texinfo v4
|
||||
system("makeinfo --no-headers --number-sections -o chrony.txt chrony.texi");
|
||||
unlink("build_kit");
|
||||
unlink("LICINS");
|
||||
|
||||
594
candm.h
Normal file
594
candm.h
Normal file
@@ -0,0 +1,594 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/candm.h,v 1.39 2003/04/01 20:54:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Definitions for the network protocol used for command and monitoring
|
||||
of the timeserver.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_CANDM_H
|
||||
#define GOT_CANDM_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
/* This is the default port to use for CANDM, if no alternative is
|
||||
defined */
|
||||
#define DEFAULT_CANDM_PORT 323
|
||||
|
||||
/* Request codes */
|
||||
#define REQ_NULL 0
|
||||
#define REQ_ONLINE 1
|
||||
#define REQ_OFFLINE 2
|
||||
#define REQ_BURST 3
|
||||
#define REQ_MODIFY_MINPOLL 4
|
||||
#define REQ_MODIFY_MAXPOLL 5
|
||||
#define REQ_DUMP 6
|
||||
#define REQ_MODIFY_MAXDELAY 7
|
||||
#define REQ_MODIFY_MAXDELAYRATIO 8
|
||||
#define REQ_MODIFY_MAXUPDATESKEW 9
|
||||
#define REQ_LOGON 10
|
||||
#define REQ_SETTIME 11
|
||||
#define REQ_LOCAL 12
|
||||
#define REQ_MANUAL 13
|
||||
#define REQ_N_SOURCES 14
|
||||
#define REQ_SOURCE_DATA 15
|
||||
#define REQ_REKEY 16
|
||||
#define REQ_ALLOW 17
|
||||
#define REQ_ALLOWALL 18
|
||||
#define REQ_DENY 19
|
||||
#define REQ_DENYALL 20
|
||||
#define REQ_CMDALLOW 21
|
||||
#define REQ_CMDALLOWALL 22
|
||||
#define REQ_CMDDENY 23
|
||||
#define REQ_CMDDENYALL 24
|
||||
#define REQ_ACCHECK 25
|
||||
#define REQ_CMDACCHECK 26
|
||||
#define REQ_ADD_SERVER 27
|
||||
#define REQ_ADD_PEER 28
|
||||
#define REQ_DEL_SOURCE 29
|
||||
#define REQ_WRITERTC 30
|
||||
#define REQ_DFREQ 31
|
||||
#define REQ_DOFFSET 32
|
||||
#define REQ_TRACKING 33
|
||||
#define REQ_SOURCESTATS 34
|
||||
#define REQ_RTCREPORT 35
|
||||
#define REQ_TRIMRTC 36
|
||||
#define REQ_CYCLELOGS 37
|
||||
#define REQ_SUBNETS_ACCESSED 38
|
||||
#define REQ_CLIENT_ACCESSES 39
|
||||
#define REQ_CLIENT_ACCESSES_BY_INDEX 40
|
||||
#define REQ_MANUAL_LIST 41
|
||||
#define REQ_MANUAL_DELETE 42
|
||||
#define REQ_MAKESTEP 43
|
||||
#define REQ_ACTIVITY 44
|
||||
#define N_REQUEST_TYPES 45
|
||||
|
||||
/* Special utoken value used to log on with first exchange being the
|
||||
password. (This time value has long since gone by) */
|
||||
#define SPECIAL_UTOKEN 0x10101010
|
||||
|
||||
/* The EOR (end of record) fields are used by the offsetof operator in
|
||||
pktlength.c, to get the number of bytes that ought to be
|
||||
transmitted for each packet type. */
|
||||
|
||||
typedef struct {
|
||||
uint32_t mask;
|
||||
uint32_t address;
|
||||
int32_t EOR;
|
||||
} REQ_Online;
|
||||
|
||||
typedef struct {
|
||||
uint32_t mask;
|
||||
uint32_t address;
|
||||
int32_t EOR;
|
||||
} REQ_Offline;
|
||||
|
||||
typedef struct {
|
||||
uint32_t mask;
|
||||
uint32_t address;
|
||||
int32_t n_good_samples;
|
||||
int32_t n_total_samples;
|
||||
int32_t EOR;
|
||||
} REQ_Burst;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
int32_t new_minpoll;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Minpoll;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
int32_t new_maxpoll;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Maxpoll;
|
||||
|
||||
typedef struct {
|
||||
int32_t pad;
|
||||
int32_t EOR;
|
||||
} REQ_Dump;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
int32_t new_max_delay;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Maxdelay;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
int32_t new_max_delay_ratio;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Maxdelayratio;
|
||||
|
||||
typedef struct {
|
||||
int32_t new_max_update_skew;
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Maxupdateskew;
|
||||
|
||||
typedef struct {
|
||||
struct timeval ts;
|
||||
int32_t EOR;
|
||||
} REQ_Logon;
|
||||
|
||||
typedef struct {
|
||||
struct timeval ts;
|
||||
int32_t EOR;
|
||||
} REQ_Settime;
|
||||
|
||||
typedef struct {
|
||||
int32_t on_off;
|
||||
int32_t stratum;
|
||||
int32_t EOR;
|
||||
} REQ_Local;
|
||||
|
||||
typedef struct {
|
||||
int32_t option;
|
||||
int32_t EOR;
|
||||
} REQ_Manual;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_N_Sources;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Source_Data;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Rekey;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip;
|
||||
int32_t subnet_bits;
|
||||
int32_t EOR;
|
||||
} REQ_Allow_Deny;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip;
|
||||
int32_t EOR;
|
||||
} REQ_Ac_Check;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip_addr;
|
||||
uint32_t port;
|
||||
int32_t minpoll;
|
||||
int32_t maxpoll;
|
||||
int32_t presend_minpoll;
|
||||
int32_t online;
|
||||
int32_t auto_offline;
|
||||
uint32_t authkey;
|
||||
int32_t max_delay;
|
||||
int32_t max_delay_ratio;
|
||||
int32_t EOR;
|
||||
} REQ_NTP_Source;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip_addr;
|
||||
int32_t EOR;
|
||||
} REQ_Del_Source;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_WriteRtc;
|
||||
|
||||
typedef struct {
|
||||
int32_t dfreq;
|
||||
int32_t EOR;
|
||||
} REQ_Dfreq;
|
||||
|
||||
typedef struct {
|
||||
int32_t sec;
|
||||
int32_t usec;
|
||||
int32_t EOR;
|
||||
} REQ_Doffset;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_RTCReport;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_TrimRTC;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip;
|
||||
uint32_t bits_specd;
|
||||
} REQ_SubnetsAccessed_Subnet;
|
||||
|
||||
#define MAX_SUBNETS_ACCESSED 8
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_subnets;
|
||||
REQ_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
|
||||
} REQ_SubnetsAccessed;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 16
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_clients;
|
||||
uint32_t client_ips[MAX_CLIENT_ACCESSES];
|
||||
} REQ_ClientAccesses;
|
||||
|
||||
typedef struct {
|
||||
uint32_t first_index;
|
||||
uint32_t n_indices;
|
||||
int32_t EOR;
|
||||
} REQ_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ManualList;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_ManualDelete;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_MakeStep;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Activity;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
#define PKT_TYPE_CMD_REPLY 2
|
||||
|
||||
/* This version number needs to be incremented whenever the packet
|
||||
size and/or the format of any of the existing messages is changed.
|
||||
Other changes, e.g. new command types, should be handled cleanly by
|
||||
client.c and cmdmon.c anyway, so the version can stay the same.
|
||||
|
||||
Version 1 : original version with fixed size packets
|
||||
|
||||
Version 2 : both command and reply packet sizes made capable of
|
||||
being variable length.
|
||||
|
||||
Version 3 : NTP_Source message lengthened (auto_offline)
|
||||
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 3
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
typedef struct {
|
||||
uint8_t version; /* Protocol version */
|
||||
uint8_t pkt_type; /* What sort of packet this is */
|
||||
uint8_t res1;
|
||||
uint8_t res2;
|
||||
uint16_t command; /* Which command is being issued */
|
||||
uint16_t attempt; /* How many resends the client has done
|
||||
(count up from zero for same sequence
|
||||
number) */
|
||||
uint32_t sequence; /* Client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* Command token (to prevent replay attack) */
|
||||
uint32_t auth[4]; /* MD5 authentication of the packet */
|
||||
|
||||
union {
|
||||
REQ_Online online;
|
||||
REQ_Offline offline;
|
||||
REQ_Burst burst;
|
||||
REQ_Modify_Minpoll modify_minpoll;
|
||||
REQ_Modify_Maxpoll modify_maxpoll;
|
||||
REQ_Dump dump;
|
||||
REQ_Modify_Maxdelay modify_maxdelay;
|
||||
REQ_Modify_Maxdelayratio modify_maxdelayratio;
|
||||
REQ_Modify_Maxupdateskew modify_maxupdateskew;
|
||||
REQ_Logon logon;
|
||||
REQ_Settime settime;
|
||||
REQ_Local local;
|
||||
REQ_Manual manual;
|
||||
REQ_N_Sources n_sources;
|
||||
REQ_Source_Data source_data;
|
||||
REQ_Rekey rekey;
|
||||
REQ_Allow_Deny allow_deny;
|
||||
REQ_Ac_Check ac_check;
|
||||
REQ_NTP_Source ntp_source;
|
||||
REQ_Del_Source del_source;
|
||||
REQ_WriteRtc writertc;
|
||||
REQ_Dfreq dfreq;
|
||||
REQ_Doffset doffset;
|
||||
REQ_Tracking tracking;
|
||||
REQ_Sourcestats sourcestats;
|
||||
REQ_RTCReport rtcreport;
|
||||
REQ_TrimRTC trimrtc;
|
||||
REQ_CycleLogs cyclelogs;
|
||||
REQ_SubnetsAccessed subnets_accessed;
|
||||
REQ_ClientAccesses client_accesses;
|
||||
REQ_ClientAccessesByIndex client_accesses_by_index;
|
||||
REQ_ManualList manual_list;
|
||||
REQ_ManualDelete manual_delete;
|
||||
REQ_MakeStep make_step;
|
||||
REQ_Activity activity;
|
||||
} data; /* Command specific parameters */
|
||||
|
||||
} CMD_Request;
|
||||
|
||||
/* ================================================== */
|
||||
/* Authority codes for command types */
|
||||
|
||||
#define PERMIT_OPEN 0
|
||||
#define PERMIT_LOCAL 1
|
||||
#define PERMIT_AUTH 2
|
||||
|
||||
/* ================================================== */
|
||||
/* These conversion utilities are used to convert between the internal
|
||||
and the 'wire' representation of real quantities */
|
||||
|
||||
#define WIRE2REAL(x) ((double) ((int32_t) ntohl(x)) / 65536.0)
|
||||
#define REAL2WIRE(x) (htonl((int32_t)(0.5 + 65536.0 * (x))))
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Reply codes */
|
||||
#define RPY_NULL 1
|
||||
#define RPY_N_SOURCES 2
|
||||
#define RPY_SOURCE_DATA 3
|
||||
#define RPY_MANUAL_TIMESTAMP 4
|
||||
#define RPY_TRACKING 5
|
||||
#define RPY_SOURCESTATS 6
|
||||
#define RPY_RTC 7
|
||||
#define RPY_SUBNETS_ACCESSED 8
|
||||
#define RPY_CLIENT_ACCESSES 9
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
|
||||
#define RPY_MANUAL_LIST 11
|
||||
#define RPY_ACTIVITY 12
|
||||
#define N_REPLY_TYPES 13
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
#define STT_FAILED 1
|
||||
#define STT_UNAUTH 2
|
||||
#define STT_INVALID 3
|
||||
#define STT_NOSUCHSOURCE 4
|
||||
#define STT_INVALIDTS 5
|
||||
#define STT_NOTENABLED 6
|
||||
#define STT_BADSUBNET 7
|
||||
#define STT_ACCESSALLOWED 8
|
||||
#define STT_ACCESSDENIED 9
|
||||
#define STT_NOHOSTACCESS 10
|
||||
#define STT_SOURCEALREADYKNOWN 11
|
||||
#define STT_TOOMANYSOURCES 12
|
||||
#define STT_NORTC 13
|
||||
#define STT_BADRTCFILE 14
|
||||
#define STT_INACTIVE 15
|
||||
#define STT_BADSAMPLE 16
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_Null;
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_sources;
|
||||
int32_t EOR;
|
||||
} RPY_N_Sources;
|
||||
|
||||
#define RPY_SD_MD_CLIENT 0
|
||||
#define RPY_SD_MD_PEER 1
|
||||
#define RPY_SD_MD_REF 2
|
||||
|
||||
#define RPY_SD_ST_SYNC 0
|
||||
#define RPY_SD_ST_UNREACH 1
|
||||
#define RPY_SD_ST_FALSETICKER 2
|
||||
#define RPY_SD_ST_JITTERY 3
|
||||
#define RPY_SD_ST_OTHER 4
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip_addr;
|
||||
uint16_t poll;
|
||||
uint16_t stratum;
|
||||
uint16_t state;
|
||||
uint16_t mode;
|
||||
uint32_t since_sample;
|
||||
int32_t orig_latest_meas;
|
||||
int32_t latest_meas;
|
||||
uint32_t latest_meas_err;
|
||||
int32_t est_offset;
|
||||
uint32_t est_offset_err;
|
||||
int32_t resid_freq;
|
||||
uint32_t resid_skew;
|
||||
int32_t EOR;
|
||||
} RPY_Source_Data;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ref_id;
|
||||
uint32_t stratum;
|
||||
uint32_t ref_time_s;
|
||||
uint32_t ref_time_us;
|
||||
uint32_t current_correction_s;
|
||||
uint32_t current_correction_us;
|
||||
int32_t freq_ppm;
|
||||
int32_t resid_freq_ppm;
|
||||
int32_t skew_ppm;
|
||||
int32_t root_delay;
|
||||
int32_t root_dispersion;
|
||||
int32_t EOR;
|
||||
} RPY_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip_addr;
|
||||
uint32_t n_samples;
|
||||
uint32_t n_runs;
|
||||
uint32_t span_seconds;
|
||||
uint32_t sd_us;
|
||||
int32_t resid_freq_ppm;
|
||||
int32_t skew_ppm;
|
||||
int32_t EOR;
|
||||
} RPY_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ref_time;
|
||||
uint16_t n_samples;
|
||||
uint16_t n_runs;
|
||||
uint32_t span_seconds;
|
||||
int32_t rtc_seconds_fast;
|
||||
int32_t rtc_gain_rate_ppm;
|
||||
int32_t EOR;
|
||||
} RPY_Rtc;
|
||||
|
||||
typedef struct {
|
||||
uint32_t centiseconds;
|
||||
int32_t dfreq_ppm;
|
||||
int32_t new_afreq_ppm;
|
||||
int32_t EOR;
|
||||
} RPY_ManualTimestamp;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip;
|
||||
uint32_t bits_specd;
|
||||
uint32_t bitmap[8];
|
||||
} RPY_SubnetsAccessed_Subnet;
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_subnets;
|
||||
RPY_SubnetsAccessed_Subnet subnets[MAX_SUBNETS_ACCESSED];
|
||||
} RPY_SubnetsAccessed;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ip;
|
||||
uint32_t client_hits;
|
||||
uint32_t peer_hits;
|
||||
uint32_t cmd_hits_auth;
|
||||
uint32_t cmd_hits_normal;
|
||||
uint32_t cmd_hits_bad;
|
||||
uint32_t last_ntp_hit_ago;
|
||||
uint32_t last_cmd_hit_ago;
|
||||
} RPY_ClientAccesses_Client;
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_clients;
|
||||
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
|
||||
} RPY_ClientAccesses;
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_indices; /* how many indices there are in the server's table */
|
||||
uint32_t next_index; /* the index 1 beyond those processed on this call */
|
||||
uint32_t n_clients; /* the number of valid entries in the following array */
|
||||
RPY_ClientAccesses_Client clients[MAX_CLIENT_ACCESSES];
|
||||
} RPY_ClientAccessesByIndex;
|
||||
|
||||
#define MAX_MANUAL_LIST_SAMPLES 32
|
||||
|
||||
typedef struct {
|
||||
uint32_t when;
|
||||
int32_t slewed_offset;
|
||||
int32_t orig_offset;
|
||||
int32_t residual;
|
||||
} RPY_ManualListSample;
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_samples;
|
||||
RPY_ManualListSample samples[MAX_MANUAL_LIST_SAMPLES];
|
||||
} RPY_ManualList;
|
||||
|
||||
typedef struct {
|
||||
int32_t online;
|
||||
int32_t offline;
|
||||
int32_t burst_online;
|
||||
int32_t burst_offline;
|
||||
int32_t EOR;
|
||||
} RPY_Activity;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t pkt_type;
|
||||
uint8_t res1;
|
||||
uint8_t res2;
|
||||
uint16_t command; /* Which command is being replied to */
|
||||
uint16_t reply; /* Which format of reply this is */
|
||||
uint16_t status; /* Status of command processing */
|
||||
uint16_t number; /* Which packet this is in reply sequence */
|
||||
uint16_t total; /* Number of replies to expect in this sequence */
|
||||
uint16_t pad1; /* Get up to 4 byte alignment */
|
||||
uint32_t sequence; /* Echo of client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* New command token (only if command was successfully
|
||||
authenticated) */
|
||||
uint32_t auth[4]; /* MD5 authentication of the packet */
|
||||
|
||||
union {
|
||||
RPY_Null null;
|
||||
RPY_N_Sources n_sources;
|
||||
RPY_Source_Data source_data;
|
||||
RPY_ManualTimestamp manual_timestamp;
|
||||
RPY_Tracking tracking;
|
||||
RPY_Sourcestats sourcestats;
|
||||
RPY_Rtc rtc;
|
||||
RPY_SubnetsAccessed subnets_accessed;
|
||||
RPY_ClientAccesses client_accesses;
|
||||
RPY_ClientAccessesByIndex client_accesses_by_index;
|
||||
RPY_ManualList manual_list;
|
||||
RPY_Activity activity;
|
||||
} data; /* Reply specific parameters */
|
||||
|
||||
} CMD_Reply;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#endif /* GOT_CANDM_H */
|
||||
65
chrony.1
Normal file
65
chrony.1
Normal file
@@ -0,0 +1,65 @@
|
||||
.TH CHRONY 1 "August 10, 2001" chrony "User's Manual"
|
||||
.SH NAME
|
||||
chrony \- programs for keeping computer clocks accurate
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBchronyc\fR [\fIOPTIONS\fR]
|
||||
|
||||
\fBchronyd\fR [\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
|
||||
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
|
||||
command-line interface to it. Time reference sources for chronyd can be
|
||||
RFC1305 NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
|
||||
real-time clock at boot time (Linux only). chronyd can determine the rate at
|
||||
which the computer gains or loses time and compensate for it while no external
|
||||
reference is present. Its use of NTP servers can be switched on and off
|
||||
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
|
||||
to the Internet, and it can also act as an RFC1305-compatible NTP server.
|
||||
|
||||
.SH USAGE
|
||||
\fIchronyc\fR is a command-line interface program which can be used to
|
||||
monitor \fIchronyd\fR's performance and to change various operating
|
||||
parateters whilst it is running.
|
||||
|
||||
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
|
||||
time from one of several sources, and correct the system clock
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
between measurements from the reference.
|
||||
|
||||
The reference time can be derived from either Network Time Protocol
|
||||
(NTP) servers (preferred), or wristwatch-and-keyboard (via \fIchronyc\fR).
|
||||
The main source of information about the Network Time Protocol is
|
||||
\fIhttp://www.eecis.udel.edu/~ntp\fR.
|
||||
|
||||
It is designed so that it can work on computers which only have
|
||||
intermittent access to reference sources, for example computers which
|
||||
use a dial-up account to access the Internet. Of course, it will work
|
||||
on computers with permanent connections too.
|
||||
|
||||
In addition, for Linux 2.0.x (for x >= 32) or 2.2 onwards, chronyd can monitor
|
||||
the system's real time clock performance, so the system can maintain accurate
|
||||
time even across reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
\fIchronyd\fR can also operate as an RFC1305-compatible NTP server and peer.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyc(1),
|
||||
.BR chrony(1)
|
||||
|
||||
.I http://chrony.sunsite.dk/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
49
chrony.conf.5
Normal file
49
chrony.conf.5
Normal file
@@ -0,0 +1,49 @@
|
||||
.TH chrony.conf 5 "August 10, 2001" chrony "Configuration Files"
|
||||
.SH NAME
|
||||
chrony.conf \- chronyd configuration file
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B /etc/chrony.conf
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks. \fIchronyd\fR is a background daemon program that can be started at
|
||||
boot time.
|
||||
|
||||
Assuming that you have found some servers, you need to set up a
|
||||
configuration file to run \fIchrony\fR. The (compiled-in) default location
|
||||
for this file is \fB/etc/chrony.conf\fR. Assuming that your ntp servers
|
||||
are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
|
||||
as a minimum
|
||||
|
||||
server a.b.c
|
||||
server d.e.f
|
||||
server g.h.i
|
||||
|
||||
However, you will probably want to include some of the other directives
|
||||
described in detail in the documentation supplied with the distribution
|
||||
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives will be
|
||||
particularly useful : `driftfile', `commandkey', `keyfile'. The smallest
|
||||
useful configuration file would look something like
|
||||
|
||||
server a.b.c
|
||||
server d.e.f
|
||||
server g.h.i
|
||||
keyfile /etc/chrony.keys
|
||||
commandkey 1
|
||||
driftfile /etc/chrony.drift
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chronyd(1)
|
||||
|
||||
.I http://chrony.sunsite.dk/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
|
||||
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
|
||||
for details.
|
||||
29
chrony.lsm
Normal file
29
chrony.lsm
Normal file
@@ -0,0 +1,29 @@
|
||||
Begin3
|
||||
Title: chrony
|
||||
Version: 1.18
|
||||
Entered-date: 01APR02
|
||||
Description: A pair of programs for keeping computer clocks accurate.
|
||||
chronyd is a background (daemon) program and chronyc is a
|
||||
command-line interface to it. Time reference sources for
|
||||
chronyd can be RFC1305 NTP servers, human (via keyboard and
|
||||
chronyc), and the computer's real-time clock at boot time
|
||||
(Linux only). chronyd can determine the rate at which the
|
||||
computer gains or loses time and compensate for it whilst no
|
||||
external reference is present. chronyd's use of NTP servers
|
||||
can be switched on and off (through chronyc) to support
|
||||
computers with dial-up/intermittent access to the
|
||||
Internet. chronyd can also act as an RFC1305-compatible NTP
|
||||
server.
|
||||
Keywords: time NTP RFC1305 RTC adjtime
|
||||
Author: rc@rc0.org.uk (Richard Curnow)
|
||||
Maintained-by: rc@rc0.org.uk (Richard Curnow)
|
||||
Primary-site: sunsite.unc.edu /pub/Linux/system/admin/time
|
||||
295k chrony-1.18.tar.gz
|
||||
2k chrony.lsm
|
||||
Platforms: Linux 2.0/2.1/2.2/2.3/2.4 (x86, powerpc)
|
||||
Solaris 2.5/6/7/8, SunOS 4.1.4. (Sparc)
|
||||
BSDI/386.
|
||||
NetBSD
|
||||
Solaris 2.8 (x86)
|
||||
Copying-policy: GPL
|
||||
End
|
||||
52
chrony.spec.sample
Normal file
52
chrony.spec.sample
Normal file
@@ -0,0 +1,52 @@
|
||||
Summary: An NTP client/server
|
||||
Name: chrony
|
||||
Version: @@VERSION@@
|
||||
Release: 1
|
||||
Source: chrony-%{version}.tar.gz
|
||||
Copyright: GPL
|
||||
Group: Applications/Utilities
|
||||
Packager: Richard P. Curnow <rc@rc0.org.uk>
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
|
||||
Requires: info
|
||||
|
||||
%description
|
||||
A pair of programs for keeping computer clocks accurate. chronyd is a
|
||||
background (daemon) program and chronyc is a command-line interface to it.
|
||||
Time reference sources for chronyd can be RFC1305 NTP servers, human (via
|
||||
keyboard and chronyc), and the computer's real-time clock at boot time (Linux
|
||||
only). chronyd can determine the rate at which the computer gains or loses
|
||||
time and compensate for it whilst no external reference is present. chronyd's
|
||||
use of NTP servers can be switched on and off (through chronyc) to support
|
||||
computers with dial-up/intermittent access to the Internet. chronyd can also
|
||||
act as an RFC1305-compatible NTP server.
|
||||
|
||||
%prep
|
||||
%setup
|
||||
|
||||
%build
|
||||
./configure --prefix=%{_prefix}
|
||||
make CC=gcc CFLAGS=-O2 prefix=%{_prefix}
|
||||
make chrony.txt prefix=%{_prefix}
|
||||
make chrony.info prefix=%{_prefix}
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
cd $RPM_BUILD_DIR/chrony-%{version}
|
||||
make install DESTDIR=$RPM_BUILD_ROOT prefix=%{_prefix}
|
||||
mkdir -p $RPM_BUILD_ROOT%{_infodir}
|
||||
cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
|
||||
|
||||
%files
|
||||
%{_sbindir}/chronyd
|
||||
%{_bindir}/chronyc
|
||||
%{_infodir}/chrony.info*
|
||||
%{_mandir}/man1/chrony.1.gz
|
||||
%{_mandir}/man1/chronyc.1.gz
|
||||
%{_mandir}/man5/chrony.conf.5.gz
|
||||
%{_mandir}/man8/chronyd.8.gz
|
||||
%doc README
|
||||
%doc chrony.txt
|
||||
%doc COPYING
|
||||
%doc examples/chrony.conf.example
|
||||
%doc examples/chrony.keys.example
|
||||
|
||||
3979
chrony.texi
Normal file
3979
chrony.texi
Normal file
File diff suppressed because it is too large
Load Diff
56
chronyc.1
Normal file
56
chronyc.1
Normal file
@@ -0,0 +1,56 @@
|
||||
.TH CHRONYC 1 "August 10, 2001" chrony "User's Manual"
|
||||
.SH NAME
|
||||
chronyc \- command-line interface for chronyd
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B chronyc
|
||||
[\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks.
|
||||
|
||||
\fBchronyc\fR is a command-line interface program which can be used to
|
||||
monitor \fIchronyd\fR's performance and to change various operating
|
||||
parateters whilst it is running.
|
||||
|
||||
.SH USAGE
|
||||
A detailed description of all commands supported by \fBchronyc\fR is available
|
||||
via the documentation supplied with the distribution (\fIchrony.txt\fR and
|
||||
\fIchrony.texi\fR).
|
||||
|
||||
.SH OPTIONS
|
||||
A summary of the options supported by \fBchronyc\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-h\fR \fIhostname\fR
|
||||
specify hostname
|
||||
.TP
|
||||
\fB\-p\fR \fIport-number\fR
|
||||
specify port-number
|
||||
.TP
|
||||
\fB\-n\fR
|
||||
display raw IP addresses (don't attempt to look up hostnames)
|
||||
.TP \fIcommand\fR
|
||||
specify command. If no command is given, chronyc will read commands
|
||||
interactively.
|
||||
|
||||
|
||||
.SH VERSION
|
||||
1.17
|
||||
|
||||
.SH BUGS
|
||||
To report bugs, please contact the author and/or visit \fIhttp://go.to/chrony\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyd(1),
|
||||
.BR chrony(1)
|
||||
|
||||
.I http://chrony.sunsite.dk/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part of "The Missing
|
||||
Man Pages Project". Please see \fIhttp://www.netmeister.org/misc/m2p2/index.html\fR
|
||||
for details.
|
||||
111
chronyd.8
Normal file
111
chronyd.8
Normal file
@@ -0,0 +1,111 @@
|
||||
.TH CHRONYD 8 "August 10, 2001" chrony "System Administration"
|
||||
.SH NAME
|
||||
chronyd \- chrony background daemon
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B chronyd
|
||||
[\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchrony\fR is a pair of programs for maintaining the accuracy of computer
|
||||
clocks. \fBchronyd\fR is a background daemon program that can be started at boot
|
||||
time.
|
||||
|
||||
\fBchronyd\fR is a daemon which runs in background on the
|
||||
system. It obtains measurements (e.g. via the network) of the
|
||||
system's offset relative to other systems, and adjusts the system
|
||||
time accordingly. For isolated systems, the user can periodically
|
||||
enter the correct time by hand (using \fIchronyc\fR). In either case,
|
||||
\fBchronyd\fR determines the rate at which the computer
|
||||
gains or loses time, and compensates for this.
|
||||
|
||||
.SH USAGE
|
||||
\fBchronyd\fR is usually started at boot-time and requires superuser
|
||||
priviliges.
|
||||
|
||||
If \fBchronyd\fR has been installed to its default location
|
||||
\fI/usr/local/sbin/chronyd\fR, starting it is simply a matter of entering the
|
||||
command:
|
||||
|
||||
\fI/usr/local/sbin/chronyd\fR
|
||||
|
||||
Information messages and warnings will be logged to syslog.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
A summary of the options supported by \fBchronyd\fR is included below.
|
||||
|
||||
.TP
|
||||
.B \-d
|
||||
When run in this mode, the program will not detach itself from the
|
||||
terminal, and all messages will be sent to the terminal instead of
|
||||
to syslog.
|
||||
.TP
|
||||
\fB\-f\fR \fIconf-file\fR
|
||||
This option can be used to specify an alternate location for the
|
||||
configuration file (default \fI/etc/chrony.conf\fR).
|
||||
.TP
|
||||
.B \-r
|
||||
This option will reload sample histories for each of the servers being used.
|
||||
These histories are created by using the \fIdump\fR command in \fIchronyc\fR,
|
||||
or by setting the \fIdumponexit\fR directive in the configuration file. This
|
||||
option is useful if you want to stop and restart \fBchronyd\fR briefly for any
|
||||
reason, e.g. to install a new version. However, it only makes sense on
|
||||
systems where the kernel can maintain clock compensation whilst not under
|
||||
\fBchronyd\fR's control. The only version where this happens so far is Linux.
|
||||
On systems where this is not the case, e.g. Solaris and SunOS the option
|
||||
should not be used.
|
||||
.TP
|
||||
.B \-s
|
||||
This option will set the system clock from the computer's real-time
|
||||
clock. This is analogous to supplying the \fI-s\fR flag to the
|
||||
\fI/sbin/clock\fR program during the Linux boot sequence.
|
||||
|
||||
Support for real-time clocks is limited at present - the criteria
|
||||
are described in the section on the \fIrtcfile\fR directive in the
|
||||
documentation supplied with the distribution.
|
||||
|
||||
If \fBchronyd\fR cannot support the real time clock on your computer,
|
||||
this option cannot be used and a warning message will be logged to
|
||||
the syslog.
|
||||
|
||||
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
|
||||
to preserve the old samples after setting the system clock from
|
||||
the real time clock. This can be used to allow \fBchronyd\fR to
|
||||
perform long term averaging of the gain or loss rate across system
|
||||
reboots, and is useful for dial-up systems that are shut down when
|
||||
not in use. For this to work well, it relies on \fBchronyd\fR having
|
||||
been able to determine accurate statistics for the difference
|
||||
between the real time clock and system clock last time the
|
||||
computer was on.
|
||||
.TP
|
||||
.B \-v
|
||||
This option displays \fBchronyd\fR's version number to the terminal and exits
|
||||
|
||||
.SH FILES
|
||||
\fI/etc/chrony.conf\fR
|
||||
|
||||
.SH VERSION
|
||||
Version 1.17
|
||||
|
||||
.SH BUGS
|
||||
To report bugs, please contact the author and/or visit \fIhttp://chrony.sunsite.dk/\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
\fBchronyd\fR is documented in detail in the documentation supplied with the
|
||||
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR) and is also available
|
||||
from \fIhttp://go.to/chrony\fR
|
||||
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR clock(8),
|
||||
.BR xntpd(8),
|
||||
.BR ntpd(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
392
clientlog.c
Normal file
392
clientlog.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/clientlog.c,v 1.10 2003/01/20 22:24:20 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module keeps a count of the number of successful accesses by
|
||||
clients, and the times of the last accesses.
|
||||
|
||||
This can be used for status reporting, and (in the case of a
|
||||
server), if it needs to know which clients have made use of its data
|
||||
recently.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "clientlog.h"
|
||||
#include "conf.h"
|
||||
#include "memory.h"
|
||||
#include "reports.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Number of bits of address per layer of the table. This value has
|
||||
been chosen on the basis that a server will predominantly be serving
|
||||
a lot of hosts in a few subnets, rather than a few hosts scattered
|
||||
across many subnets. */
|
||||
|
||||
#define NBITS 8
|
||||
|
||||
/* Number of entries in each subtable */
|
||||
#define TABLE_SIZE (1UL<<NBITS)
|
||||
|
||||
typedef struct _Node {
|
||||
unsigned long ip_addr;
|
||||
unsigned long client_hits;
|
||||
unsigned long peer_hits;
|
||||
unsigned long cmd_hits_bad;
|
||||
unsigned long cmd_hits_normal;
|
||||
unsigned long cmd_hits_auth;
|
||||
time_t last_ntp_hit;
|
||||
time_t last_cmd_hit;
|
||||
} Node;
|
||||
|
||||
typedef struct _Subnet {
|
||||
void *entry[TABLE_SIZE];
|
||||
} Subnet;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Table for the class A subnet */
|
||||
static Subnet top_subnet;
|
||||
|
||||
/* Table containing pointers directly to all nodes that have been
|
||||
allocated. */
|
||||
static Node **nodes = NULL;
|
||||
|
||||
/* Number of nodes actually in the table. */
|
||||
static int n_nodes = 0;
|
||||
|
||||
/* Number of entries for which the table has been sized. */
|
||||
static int max_nodes = 0;
|
||||
|
||||
#define NODE_TABLE_INCREMENT 4
|
||||
|
||||
/* Flag indicating whether facility is turned on or not */
|
||||
static int active = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clear_subnet(Subnet *subnet)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<TABLE_SIZE; i++) {
|
||||
subnet->entry[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clear_node(Node *node)
|
||||
{
|
||||
node->client_hits = 0;
|
||||
node->peer_hits = 0;
|
||||
node->cmd_hits_auth = 0;
|
||||
node->cmd_hits_normal = 0;
|
||||
node->cmd_hits_bad = 0;
|
||||
node->last_ntp_hit = (time_t) 0;
|
||||
node->last_cmd_hit = (time_t) 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_Initialise(void)
|
||||
{
|
||||
clear_subnet(&top_subnet);
|
||||
if (CNF_GetNoClientLog()) {
|
||||
active = 0;
|
||||
} else {
|
||||
active = 1;
|
||||
}
|
||||
|
||||
nodes = NULL;
|
||||
max_nodes = 0;
|
||||
n_nodes = 0;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_Finalise(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
create_subnet(Subnet *parent_subnet, int the_entry)
|
||||
{
|
||||
parent_subnet->entry[the_entry] = (void *) MallocNew(Subnet);
|
||||
clear_subnet((Subnet *) parent_subnet->entry[the_entry]);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
create_node(Subnet *parent_subnet, int the_entry)
|
||||
{
|
||||
Node *new_node;
|
||||
new_node = MallocNew(Node);
|
||||
parent_subnet->entry[the_entry] = (void *) new_node;
|
||||
clear_node(new_node);
|
||||
|
||||
if (n_nodes == max_nodes) {
|
||||
if (nodes) {
|
||||
max_nodes += NODE_TABLE_INCREMENT;
|
||||
nodes = ReallocArray(Node *, max_nodes, nodes);
|
||||
} else {
|
||||
if (max_nodes != 0) {
|
||||
CROAK("max_nodes should be 0");
|
||||
}
|
||||
max_nodes = NODE_TABLE_INCREMENT;
|
||||
nodes = MallocArray(Node *, max_nodes);
|
||||
}
|
||||
}
|
||||
nodes[n_nodes++] = (Node *) new_node;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Recursively seek out the Node entry for a particular address,
|
||||
expanding subnet tables and node entries as we go if necessary. */
|
||||
|
||||
static void *
|
||||
find_subnet(Subnet *subnet, CLG_IP_Addr addr, int bits_left)
|
||||
{
|
||||
unsigned long this_subnet, new_subnet, mask, shift;
|
||||
unsigned long new_bits_left;
|
||||
|
||||
shift = 32 - NBITS;
|
||||
mask = (1UL<<shift) - 1;
|
||||
this_subnet = addr >> shift;
|
||||
new_subnet = (addr & mask) << NBITS;
|
||||
new_bits_left = bits_left - NBITS;
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "fs addr=%08lx bl=%d ma=%08lx this=%08lx newsn=%08lx nbl=%d\n",
|
||||
addr, bits_left, mask, this_subnet, new_subnet, new_bits_left);
|
||||
#endif
|
||||
|
||||
if (new_bits_left > 0) {
|
||||
if (!subnet->entry[this_subnet]) {
|
||||
create_subnet(subnet, this_subnet);
|
||||
}
|
||||
return find_subnet((Subnet *) subnet->entry[this_subnet], new_subnet, new_bits_left);
|
||||
} else {
|
||||
if (!subnet->entry[this_subnet]) {
|
||||
create_node(subnet, this_subnet);
|
||||
}
|
||||
return subnet->entry[this_subnet];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
/* Search for the record for a particular subnet, but return NULL if
|
||||
one of the parents does not exist - never open a node out */
|
||||
|
||||
static void *
|
||||
find_subnet_dont_open(Subnet *subnet, CLG_IP_Addr addr, int bits_left)
|
||||
{
|
||||
unsigned long this_subnet, new_subnet, mask, shift;
|
||||
unsigned long new_bits_left;
|
||||
|
||||
if (bits_left == 0) {
|
||||
return subnet;
|
||||
} else {
|
||||
|
||||
shift = 32 - NBITS;
|
||||
mask = (1UL<<shift) - 1;
|
||||
this_subnet = addr >> shift;
|
||||
new_subnet = (addr & mask) << NBITS;
|
||||
new_bits_left = bits_left - NBITS;
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "fsdo addr=%08lx bl=%d this=%08lx newsn=%08lx nbl=%d\n",
|
||||
addr, bits_left, this_subnet, new_subnet, new_bits_left);
|
||||
#endif
|
||||
|
||||
if (!subnet->entry[this_subnet]) {
|
||||
return NULL;
|
||||
} else {
|
||||
return find_subnet_dont_open((Subnet *) subnet->entry[this_subnet], new_subnet, new_bits_left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_LogNTPClientAccess (CLG_IP_Addr client, time_t now)
|
||||
{
|
||||
Node *node;
|
||||
if (active) {
|
||||
node = (Node *) find_subnet(&top_subnet, client, 32);
|
||||
node->ip_addr = client;
|
||||
++node->client_hits;
|
||||
node->last_ntp_hit = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_LogNTPPeerAccess(CLG_IP_Addr client, time_t now)
|
||||
{
|
||||
Node *node;
|
||||
if (active) {
|
||||
node = (Node *) find_subnet(&top_subnet, client, 32);
|
||||
node->ip_addr = client;
|
||||
++node->peer_hits;
|
||||
node->last_ntp_hit = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_LogCommandAccess(CLG_IP_Addr client, CLG_Command_Type type, time_t now)
|
||||
{
|
||||
Node *node;
|
||||
if (active) {
|
||||
node = (Node *) find_subnet(&top_subnet, client, 32);
|
||||
node->ip_addr = client;
|
||||
node->last_cmd_hit = now;
|
||||
switch (type) {
|
||||
case CLG_CMD_AUTH:
|
||||
++node->cmd_hits_auth;
|
||||
break;
|
||||
case CLG_CMD_NORMAL:
|
||||
++node->cmd_hits_normal;
|
||||
break;
|
||||
case CLG_CMD_BAD_PKT:
|
||||
++node->cmd_hits_bad;
|
||||
break;
|
||||
default:
|
||||
CROAK("Impossible");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CLG_Status
|
||||
CLG_GetSubnetBitmap(CLG_IP_Addr subnet, int bits, CLG_Bitmap result)
|
||||
{
|
||||
Subnet *s;
|
||||
unsigned long i;
|
||||
unsigned long word, bit, mask;
|
||||
|
||||
if ((bits == 0) || (bits == 8) || (bits == 16) || (bits == 24)) {
|
||||
memset (result, 0, TABLE_SIZE/8);
|
||||
if (active) {
|
||||
s = find_subnet_dont_open(&top_subnet, subnet, bits);
|
||||
if (s) {
|
||||
for (i=0; i<256; i++) {
|
||||
if (s->entry[i]) {
|
||||
word = i / 32;
|
||||
bit = i % 32;
|
||||
mask = 1UL << bit;
|
||||
result[word] |= mask;
|
||||
}
|
||||
}
|
||||
return CLG_SUCCESS;
|
||||
} else {
|
||||
return CLG_EMPTYSUBNET;
|
||||
}
|
||||
} else {
|
||||
return CLG_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
return CLG_BADSUBNET;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CLG_Status
|
||||
CLG_GetClientAccessReportByIP(unsigned long ip, RPT_ClientAccess_Report *report, time_t now)
|
||||
{
|
||||
Node *node;
|
||||
|
||||
if (!active) {
|
||||
return CLG_INACTIVE;
|
||||
} else {
|
||||
node = (Node *) find_subnet_dont_open(&top_subnet, ip, 32);
|
||||
|
||||
if (!node) {
|
||||
return CLG_EMPTYSUBNET;
|
||||
} else {
|
||||
report->client_hits = node->client_hits;
|
||||
report->peer_hits = node->peer_hits;
|
||||
report->cmd_hits_auth = node->cmd_hits_auth;
|
||||
report->cmd_hits_normal = node->cmd_hits_normal;
|
||||
report->cmd_hits_bad = node->cmd_hits_bad;
|
||||
report->last_ntp_hit_ago = now - node->last_ntp_hit;
|
||||
report->last_cmd_hit_ago = now - node->last_cmd_hit;
|
||||
|
||||
return CLG_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CLG_Status
|
||||
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
|
||||
time_t now, unsigned long *n_indices)
|
||||
{
|
||||
Node *node;
|
||||
|
||||
*n_indices = n_nodes;
|
||||
|
||||
if (!active) {
|
||||
return CLG_INACTIVE;
|
||||
} else {
|
||||
|
||||
if ((index < 0) || (index >= n_nodes)) {
|
||||
return CLG_INDEXTOOLARGE;
|
||||
}
|
||||
|
||||
node = nodes[index];
|
||||
|
||||
report->ip_addr = node->ip_addr;
|
||||
report->client_hits = node->client_hits;
|
||||
report->peer_hits = node->peer_hits;
|
||||
report->cmd_hits_auth = node->cmd_hits_auth;
|
||||
report->cmd_hits_normal = node->cmd_hits_normal;
|
||||
report->cmd_hits_bad = node->cmd_hits_bad;
|
||||
report->last_ntp_hit_ago = now - node->last_ntp_hit;
|
||||
report->last_cmd_hit_ago = now - node->last_cmd_hit;
|
||||
|
||||
return CLG_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
91
clientlog.h
Normal file
91
clientlog.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/clientlog.h,v 1.8 2003/04/01 20:54:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module contains facilities for logging access by clients.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_CLIENTLOG_H
|
||||
#define GOT_CLIENTLOG_H
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "reports.h"
|
||||
|
||||
typedef unsigned long CLG_IP_Addr;
|
||||
|
||||
/* Enough to hold flags for 256 hosts in a class C */
|
||||
typedef uint32_t CLG_Bitmap[8];
|
||||
|
||||
extern void CLG_Initialise(void);
|
||||
extern void CLG_Finalise(void);
|
||||
extern void CLG_LogNTPClientAccess(CLG_IP_Addr client, time_t now);
|
||||
extern void CLG_LogNTPPeerAccess(CLG_IP_Addr client, time_t now);
|
||||
|
||||
/* When logging command packets, there are several subtypes */
|
||||
|
||||
typedef enum {
|
||||
CLG_CMD_AUTH, /* authenticated */
|
||||
CLG_CMD_NORMAL, /* normal */
|
||||
CLG_CMD_BAD_PKT /* bad version or packet length */
|
||||
} CLG_Command_Type;
|
||||
|
||||
extern void CLG_LogCommandAccess(CLG_IP_Addr client, CLG_Command_Type type, time_t now);
|
||||
|
||||
/* And some reporting functions, for use by chronyc. */
|
||||
/* TBD */
|
||||
|
||||
typedef enum {
|
||||
CLG_SUCCESS, /* All is well */
|
||||
CLG_EMPTYSUBNET, /* No hosts logged in requested subnet */
|
||||
CLG_BADSUBNET, /* Subnet requested is not 0, 8, 16 or 24 bits */
|
||||
CLG_INACTIVE, /* Facility not active */
|
||||
CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */
|
||||
} CLG_Status;
|
||||
|
||||
/* For bits=0, 8, 16, flag which immediate subnets of that subnet are
|
||||
known. For bits=24, flag which hosts in that subnet are known.
|
||||
Other values, return 0 (failed) */
|
||||
|
||||
extern CLG_Status CLG_GetSubnetBitmap(CLG_IP_Addr subnet, int bits, CLG_Bitmap result);
|
||||
|
||||
extern CLG_Status
|
||||
CLG_GetClientAccessReportByIP(unsigned long ip, RPT_ClientAccess_Report *report, time_t now);
|
||||
|
||||
CLG_Status
|
||||
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
|
||||
time_t now, unsigned long *n_indices);
|
||||
|
||||
/* And an iterating function, to call 'fn' for each client or peer
|
||||
that has accessed us since 'since'. */
|
||||
|
||||
extern void CLG_IterateNTPClients
|
||||
(void (*fn)(CLG_IP_Addr client, void *arb),
|
||||
void *arb,
|
||||
time_t since);
|
||||
|
||||
|
||||
#endif /* GOT_CLIENTLOG_H */
|
||||
41
cmdmon.h
Normal file
41
cmdmon.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/cmdmon.h,v 1.8 2002/02/28 23:27:09 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the control and monitoring module in the software
|
||||
*/
|
||||
|
||||
#ifndef GOT_CMDMON_H
|
||||
#define GOT_CMDMON_H
|
||||
|
||||
extern void CAM_Initialise(void);
|
||||
|
||||
extern void CAM_Finalise(void);
|
||||
|
||||
extern int CAM_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all);
|
||||
extern int CAM_CheckAccessRestriction(unsigned long ip_addr);
|
||||
|
||||
#endif /* GOT_CMDMON_H */
|
||||
163
cmdparse.c
Normal file
163
cmdparse.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/cmdparse.c,v 1.11 2003/01/20 22:52:07 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Module for parsing various forms of directive and command lines that
|
||||
are common to the configuration file and to the command client.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "cmdparse.h"
|
||||
#include "nameserv.h"
|
||||
|
||||
#define MAXLEN 2047
|
||||
#define SMAXLEN "2047"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CPS_Status
|
||||
CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
|
||||
{
|
||||
int ok, n, done;
|
||||
char cmd[MAXLEN+1], hostname[MAXLEN+1];
|
||||
CPS_Status result;
|
||||
|
||||
src->port = 123;
|
||||
src->params.minpoll = 6;
|
||||
src->params.maxpoll = 10;
|
||||
src->params.presend_minpoll = 0;
|
||||
src->params.authkey = INACTIVE_AUTHKEY;
|
||||
src->params.max_delay = 16.0;
|
||||
src->params.max_delay_ratio = 16384.0;
|
||||
src->params.online = 1;
|
||||
src->params.auto_offline = 0;
|
||||
|
||||
result = CPS_Success;
|
||||
|
||||
ok = 0;
|
||||
if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) {
|
||||
src->ip_addr = DNS_Name2IPAddress(hostname);
|
||||
if (src->ip_addr != DNS_Failed_Address) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
result = CPS_BadHost;
|
||||
} else {
|
||||
|
||||
line += n;
|
||||
|
||||
/* Parse subfields */
|
||||
ok = 1;
|
||||
done = 0;
|
||||
do {
|
||||
if (sscanf(line, "%" SMAXLEN "s%n", cmd, &n) == 1) {
|
||||
|
||||
line += n;
|
||||
|
||||
if (!strncasecmp(cmd, "port", 4)) {
|
||||
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
|
||||
result = CPS_BadPort;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "minpoll", 7)) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
|
||||
result = CPS_BadMinpoll;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "maxpoll", 7)) {
|
||||
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
|
||||
result = CPS_BadMaxpoll;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "presend", 7)) {
|
||||
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
|
||||
result = CPS_BadPresend;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
/* This MUST come before the following one ! */
|
||||
} else if (!strncasecmp(cmd, "maxdelayratio", 13)) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
|
||||
result = CPS_BadMaxdelayratio;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "maxdelay", 8)) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
|
||||
result = CPS_BadMaxdelay;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "key", 3)) {
|
||||
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1) {
|
||||
result = CPS_BadKey;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
} else {
|
||||
line += n;
|
||||
}
|
||||
} else if (!strncasecmp(cmd, "offline", 7)) {
|
||||
src->params.online = 0;
|
||||
|
||||
} else if (!strncasecmp(cmd, "auto_offline", 12)) {
|
||||
src->params.auto_offline = 1;
|
||||
|
||||
} else {
|
||||
result = CPS_BadOption;
|
||||
ok = 0;
|
||||
done = 1;
|
||||
}
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
60
cmdparse.h
Normal file
60
cmdparse.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/cmdparse.h,v 1.7 2002/02/28 23:27:09 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the command parser
|
||||
*/
|
||||
|
||||
#ifndef GOT_CMDPARSE_H
|
||||
#define GOT_CMDPARSE_H
|
||||
|
||||
#include "srcparams.h"
|
||||
|
||||
typedef enum {
|
||||
CPS_Success,
|
||||
CPS_BadOption,
|
||||
CPS_BadHost,
|
||||
CPS_BadPort,
|
||||
CPS_BadMinpoll,
|
||||
CPS_BadMaxpoll,
|
||||
CPS_BadPresend,
|
||||
CPS_BadMaxdelayratio,
|
||||
CPS_BadMaxdelay,
|
||||
CPS_BadKey
|
||||
} CPS_Status;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ip_addr;
|
||||
unsigned short port;
|
||||
SourceParameters params;
|
||||
} CPS_NTP_Source;
|
||||
|
||||
/* Parse a command to add an NTP server or peer */
|
||||
extern CPS_Status CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src);
|
||||
|
||||
|
||||
|
||||
#endif /* GOT_CMDPARSE_H */
|
||||
74
conf.h
Normal file
74
conf.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/conf.h,v 1.24 2003/03/27 23:45:47 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for configuration module
|
||||
*/
|
||||
|
||||
#ifndef GOT_CONF_H
|
||||
#define GOT_CONF_H
|
||||
|
||||
extern char *CNF_GetRtcDevice(void);
|
||||
|
||||
extern void CNF_ReadFile(const char *filename);
|
||||
|
||||
extern void CNF_AddSources(void);
|
||||
extern void CNF_AddBroadcasts(void);
|
||||
|
||||
extern void CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything);
|
||||
|
||||
extern unsigned short CNF_GetAcquisitionPort(void);
|
||||
extern unsigned short CNF_GetNTPPort(void);
|
||||
extern char *CNF_GetDriftFile(void);
|
||||
extern char *CNF_GetLogDir(void);
|
||||
extern char *CNF_GetDumpDir(void);
|
||||
extern int CNF_GetLogMeasurements(void);
|
||||
extern int CNF_GetLogStatistics(void);
|
||||
extern int CNF_GetLogTracking(void);
|
||||
extern int CNF_GetLogRtc(void);
|
||||
extern char *CNF_GetKeysFile(void);
|
||||
extern char *CNF_GetRtcFile(void);
|
||||
extern unsigned long CNF_GetCommandKey(void);
|
||||
extern int CNF_GetDumpOnExit(void);
|
||||
extern int CNF_GetManualEnabled(void);
|
||||
extern int CNF_GetCommandPort(void);
|
||||
extern int CNF_GetRTCOnUTC(void);
|
||||
extern void CNF_GetLogChange(int *enabled, double *threshold);
|
||||
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
|
||||
extern int CNF_GetNoClientLog(void);
|
||||
extern void CNF_GetBindAddress(unsigned long *addr);
|
||||
extern void CNF_GetBindCommandAddress(unsigned long *addr);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern void CNF_GetLinuxHz(int *set, int *hz);
|
||||
extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale);
|
||||
|
||||
/* Value returned in ppm, as read from file */
|
||||
extern double CNF_GetMaxUpdateSkew(void);
|
||||
extern int CNF_AllowLocalReference(int *stratum);
|
||||
|
||||
extern void CNF_SetupAccessRestrictions(void);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
313
configure
vendored
Executable file
313
configure
vendored
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $Header: /cvs/src/chrony/configure,v 1.28 2003/07/01 20:53:00 richard Exp $
|
||||
#
|
||||
# =======================================================================
|
||||
#
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# #COPYRIGHT#
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
# This configure script determines the operating system type and version
|
||||
|
||||
if [ "x${CC}" = "x" ]; then
|
||||
MYCC="gcc"
|
||||
else
|
||||
MYCC="${CC}"
|
||||
fi
|
||||
|
||||
if [ "x${CFLAGS}" = "x" ]; then
|
||||
MYCFLAGS="-O2 -g"
|
||||
else
|
||||
MYCFLAGS="${CFLAGS}"
|
||||
fi
|
||||
|
||||
# ======================================================================
|
||||
# FUNCTIONS
|
||||
|
||||
#{{{ test_for_sqrt
|
||||
test_for_sqrt () {
|
||||
# 0 : doesn't need -lm
|
||||
# 1 : needs -lm
|
||||
# 2 : doesn't even link with -lm
|
||||
|
||||
cat >docheck.c <<EOF;
|
||||
#include <math.h>
|
||||
int main(int argc, char **argv) {
|
||||
return (int) sqrt((double)argc);
|
||||
}
|
||||
EOF
|
||||
|
||||
${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
${MYCC} ${MYCFLAGS} -o docheck docheck.o >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
result=0
|
||||
else
|
||||
${MYCC} ${MYCFLAGS} -o docheck docheck.o -lm >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
result=1
|
||||
else
|
||||
result=2
|
||||
fi
|
||||
fi
|
||||
else
|
||||
result=2
|
||||
fi
|
||||
|
||||
rm -f docheck.c docheck.o docheck
|
||||
echo $result
|
||||
}
|
||||
#}}}
|
||||
#{{{ test_for_stdint_h
|
||||
test_for_stdint_h () {
|
||||
cat >docheck.c <<EOF;
|
||||
#include <stdint.h>
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
result=0
|
||||
else
|
||||
result=1
|
||||
fi
|
||||
|
||||
rm -f docheck.c docheck.o
|
||||
echo $result
|
||||
}
|
||||
#}}}
|
||||
#{{{ test_for_inttypes_h
|
||||
test_for_inttypes_h () {
|
||||
cat >docheck.c <<EOF;
|
||||
#include <inttypes.h>
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
result=0
|
||||
else
|
||||
result=1
|
||||
fi
|
||||
|
||||
rm -f docheck.c docheck.o
|
||||
echo $result
|
||||
}
|
||||
#}}}
|
||||
|
||||
# ======================================================================
|
||||
|
||||
|
||||
|
||||
OPERATINGSYSTEM=`uname -s`
|
||||
VERSION=`uname -r`
|
||||
MACHINE=`uname -m`
|
||||
|
||||
SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
|
||||
|
||||
EXTRA_LIBS=""
|
||||
EXTRA_CLI_LIBS=""
|
||||
EXTRA_OBJECTS=""
|
||||
EXTRA_DEFS=""
|
||||
INSTALL_PREFIX=/usr/local
|
||||
SYSDEFS=""
|
||||
|
||||
# Support for readline (on by default)
|
||||
feat_readline=1
|
||||
readline_lib=""
|
||||
readline_inc=""
|
||||
ncurses_lib=""
|
||||
|
||||
SETINFODIR=""
|
||||
SETMANDIR=""
|
||||
|
||||
for option
|
||||
do
|
||||
case "$option" in
|
||||
--prefix=* | --install_prefix=* )
|
||||
INSTALL_PREFIX=`echo $option | sed -e 's/[^=]*=//;'`
|
||||
;;
|
||||
--trace )
|
||||
EXTRA_DEFS="-DTRACEON"
|
||||
;;
|
||||
--disable-readline )
|
||||
feat_readline=0
|
||||
;;
|
||||
--with-readline-library=* )
|
||||
readline_lib=-L`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--with-readline-includes=* )
|
||||
readline_inc=-I`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--with-ncurses-library=* )
|
||||
ncurses_lib=-L`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--infodir=* )
|
||||
SETINFODIR=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--mandir=* )
|
||||
SETMANDIR=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
* )
|
||||
echo "Unrecognized option : " $option
|
||||
esac
|
||||
done
|
||||
|
||||
case $SYSTEM in
|
||||
SunOS-sun4* )
|
||||
case $VERSION in
|
||||
4.* )
|
||||
EXTRA_OBJECTS="sys_sunos.o strerror.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
SYSDEFS="-DSUNOS"
|
||||
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
|
||||
;;
|
||||
5.* )
|
||||
EXTRA_OBJECTS="sys_solaris.o"
|
||||
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
|
||||
EXTRA_CLI_LIBS="-lsocket -lnsl"
|
||||
SYSDEFS="-DSOLARIS"
|
||||
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
|
||||
if [ $VERSION = "5.3" ]; then
|
||||
SYSDEFS="$SYSDEFS -DHAS_NO_BZERO"
|
||||
echo "Using memset() instead of bzero()"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
Linux* )
|
||||
EXTRA_OBJECTS="sys_linux.o wrap_adjtimex.o rtc_linux.o"
|
||||
SYSDEFS="-DLINUX"
|
||||
echo "Configuring for " $SYSTEM
|
||||
if [ -r /usr/include/linux/spinlock.h ]; then
|
||||
SYSDEFS="$SYSDEFS -DHAS_SPINLOCK_H"
|
||||
echo "The system has <spinlock.h>, using that"
|
||||
else
|
||||
echo "The system does not have <spinlock.h>, using private definition for spinlock_t"
|
||||
fi
|
||||
if [ "${MACHINE}" = "alpha" ]; then
|
||||
echo "Enabling -mieee"
|
||||
# FIXME: Should really test for GCC
|
||||
SYSDEFS="$SYSDEFS -mieee -DALPHA"
|
||||
fi
|
||||
;;
|
||||
|
||||
BSD/386-i[3456]86 )
|
||||
# Antti Jrvinen <costello@iki.fi> reported that this system can
|
||||
# be supported with the SunOS 4.x driver files.
|
||||
EXTRA_OBJECTS="sys_sunos.o strerror.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
SYSDEFS="-DSUNOS"
|
||||
echo "Configuring for BSD/386 (using SunOS driver)"
|
||||
;;
|
||||
NetBSD-* )
|
||||
EXTRA_OBJECTS="sys_netbsd.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
SYSDEFS=""
|
||||
echo "Configuring for $SYSTEM"
|
||||
;;
|
||||
SunOS-i86pc* )
|
||||
# Doug Woodward <dougw@whistler.com> reported that this configuration
|
||||
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms
|
||||
EXTRA_OBJECTS="sys_solaris.o"
|
||||
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
|
||||
EXTRA_CLI_LIBS="-lsocket -lnsl"
|
||||
SYSDEFS="-DSOLARIS"
|
||||
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
|
||||
;;
|
||||
CYGWIN32_NT-i[3456]86 )
|
||||
EXTRA_OBJECTS="sys_winnt.o"
|
||||
EXTRA_LIBS=""
|
||||
SYSDEFS="-DWINNT"
|
||||
echo "Configuring for Windows NT (Cygwin32)"
|
||||
;;
|
||||
* )
|
||||
echo "Sorry, I don't know how to build this software on your system."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
printf "Checking if sqrt() needs -lm : "
|
||||
case `test_for_sqrt`
|
||||
in
|
||||
0)
|
||||
printf "No\n"
|
||||
LIBS=""
|
||||
;;
|
||||
1)
|
||||
printf "Yes\n"
|
||||
LIBS="-lm"
|
||||
;;
|
||||
*)
|
||||
printf "\nCan't compile/link a program which uses sqrt(), bailing out\n"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
printf "Checking for <stdint.h> : "
|
||||
if [ `test_for_stdint_h` -eq 0 ]; then
|
||||
printf "Yes\n"
|
||||
SYSDEFS="${SYSDEFS} -DHAS_STDINT_H"
|
||||
else
|
||||
printf "No\n"
|
||||
fi
|
||||
|
||||
printf "Checking for <inttypes.h> : "
|
||||
if [ `test_for_inttypes_h` -eq 0 ]; then
|
||||
printf "Yes\n"
|
||||
SYSDEFS="${SYSDEFS} -DHAS_INTTYPES_H"
|
||||
else
|
||||
printf "No\n"
|
||||
fi
|
||||
|
||||
if [ "x${MYCC}" = "xgcc" ]; then
|
||||
CCWARNFLAGS="-Wmissing-prototypes -Wall"
|
||||
else
|
||||
CCWARNFLAGS=""
|
||||
fi
|
||||
|
||||
if [ $feat_readline = "1" ]; then
|
||||
READLINE_COMPILE="-DFEAT_READLINE=1 $readline_inc"
|
||||
READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
|
||||
else
|
||||
READLINE_COMPILE=""
|
||||
READLINE_LINK=""
|
||||
fi
|
||||
|
||||
MANDIR=${INSTALL_PREFIX}/man
|
||||
INFODIR=${INSTALL_PREFIX}/info
|
||||
if [ "x$SETINFODIR" != "x" ]; then
|
||||
INFODIR=$SETINFODIR
|
||||
fi
|
||||
if [ "x$SETMANDIR" != "x" ]; then
|
||||
MANDIR=$SETMANDIR
|
||||
fi
|
||||
|
||||
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
|
||||
s%@CC@%${MYCC}%;\
|
||||
s%@CFLAGS@%${MYCFLAGS}%;\
|
||||
s%@CCWARNFLAGS@%${CCWARNFLAGS}%;\
|
||||
s%@LIBS@%${LIBS}%;\
|
||||
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
|
||||
s%@SYSDEFS@%${SYSDEFS}%;\
|
||||
s%@EXTRA_DEFS@%${EXTRA_DEFS}%;\
|
||||
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
|
||||
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
|
||||
s%@READLINE_LINK@%${READLINE_LINK}%;\
|
||||
s%@INSTALL_PREFIX@%${INSTALL_PREFIX}%;\
|
||||
s%@MANDIR@%${MANDIR}%;\
|
||||
s%@INFODIR@%${INFODIR}%;"\
|
||||
< Makefile.in > Makefile
|
||||
|
||||
339
contrib/DNSchrony/COPYING
Normal file
339
contrib/DNSchrony/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
583
contrib/DNSchrony/DNSchrony.pl
Executable file
583
contrib/DNSchrony/DNSchrony.pl
Executable file
@@ -0,0 +1,583 @@
|
||||
#!/usr/bin/perl
|
||||
# Copyright (C) Paul Elliott 2002
|
||||
my($copyrighttext) = <<'EOF';
|
||||
# Copyright (C) Paul Elliott 2002
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# SEE COPYING FOR DETAILS
|
||||
EOF
|
||||
|
||||
#modules we use.
|
||||
|
||||
use Socket;
|
||||
use Getopt::Std;
|
||||
use Net::DNS;
|
||||
use Tie::Syslog;
|
||||
use File::Temp qw/ :mktemp /;
|
||||
use File::Copy;
|
||||
|
||||
local($res) = new Net::DNS::Resolver;
|
||||
|
||||
#dns lookup of IP address.
|
||||
#returns ip or errorstring.
|
||||
sub gethostaddr($) #get ip address from host
|
||||
{
|
||||
my($host) = shift;
|
||||
$query = $res->search($host);
|
||||
if ($query) {
|
||||
foreach $rr ($query->answer) {
|
||||
next unless $rr->type eq "A";
|
||||
print $rr->address, "\n" if $pedebug;
|
||||
return $rr->address;
|
||||
}
|
||||
} else {
|
||||
print "query failed: ", $res->errorstring, "\n" if $pedebug;
|
||||
return $res->errorstring;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#send messages to syslog
|
||||
|
||||
sub Log($$)
|
||||
{
|
||||
if ($log) {
|
||||
my($level) = shift;
|
||||
my($mess) =shift;
|
||||
|
||||
tie *MYLOG, 'Tie::Syslog',$level,$0,'pid','unix';
|
||||
print MYLOG $mess;
|
||||
|
||||
untie *MYLOG;
|
||||
}
|
||||
}
|
||||
|
||||
#send message to output or syslog
|
||||
#and die.
|
||||
|
||||
sub BadDie($)
|
||||
{
|
||||
my($myerr) =$!;
|
||||
my($mess)=shift;
|
||||
|
||||
if($log){
|
||||
tie *MYLOG, 'Tie::Syslog','local0.err',$0,'pid','unix';
|
||||
print MYLOG $mess;
|
||||
print MYLOG $myerr;
|
||||
|
||||
untie *MYLOG;
|
||||
|
||||
} else {
|
||||
print "$mess\n$myerr\n";
|
||||
}
|
||||
die $mess;
|
||||
}
|
||||
|
||||
sub isIpAddr($) #return true if looks like ip address
|
||||
{
|
||||
my($ip) = shift;
|
||||
return 1 if ( $ip =~ m/$ipOnlyPAT/ );
|
||||
return 0;
|
||||
}
|
||||
sub isHostname($) #return true if looks like ip address
|
||||
{
|
||||
my($ip) = shift;
|
||||
return 1 if ( $ip =~ m/$hostnameOnlyPAT/ );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#send commands to chronyc by piping.
|
||||
sub chronyc($) #send commands to chronyc
|
||||
{
|
||||
my($command) = shift;
|
||||
my($err) = "/var/tmp/chronyc.log";
|
||||
my($chronyP) = "/usr/local/bin/chronyc";
|
||||
open(CHRONY, "| $chronyP 1>$err 2>&1");
|
||||
|
||||
print CHRONY "$passwd$command\n";
|
||||
|
||||
close(CHRONY);
|
||||
|
||||
Log('local0.info',"chronyc command issued=$command");
|
||||
#look at status lines till return bad.
|
||||
open( IN, "<$err");
|
||||
my($status);
|
||||
while (<IN>) {
|
||||
$status = $_;
|
||||
|
||||
unless ( m/\A200 OK/ ) {
|
||||
last;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$status ="" if ( $status =~ m/\A200 OK/ );
|
||||
close(IN);
|
||||
unlink $err;
|
||||
Log('local0.info',"chronyc results=$status");
|
||||
return $status;
|
||||
|
||||
}
|
||||
|
||||
#common patterns
|
||||
|
||||
# an ip address patern
|
||||
local($ipPAT) = qr/\d{1,3}(?:\.\d{1,3}){3}/;
|
||||
# an hostname pattern
|
||||
local($hostnamePAT) = qr/\w+(?:\.\w+)*/;
|
||||
#line with hostname only
|
||||
local($hostnameOnlyPAT) = qr/\A$hostnamePAT\Z/;
|
||||
#line with ip address only
|
||||
local($ipOnlyPAT) =qr/\A$ipPAT\Z/;
|
||||
|
||||
#options hash
|
||||
my(%opts);
|
||||
|
||||
|
||||
getopts('nuadslPSC', \%opts);
|
||||
|
||||
local($log) = ( $opts{'l'} ) ? 1 : 0;
|
||||
|
||||
my($offline) = !( $opts{'n'} ) ;
|
||||
my($offlineS) = ( $opts{'n'} ) ? " " : " offline" ;
|
||||
|
||||
# paul elliotts secret debug var. no one will ever find out about it.
|
||||
local($pedebug)=( ($ENV{"PAULELLIOTTDEBUG"}) or ($opts{P}) );
|
||||
|
||||
if ($opts{C}) {
|
||||
|
||||
print $copyrighttext;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
print <<"EOF" unless $opts{'S'};
|
||||
$0, Copyright (C) 2002 Paul Elliott
|
||||
$0 comes with ABSOLUTELY NO WARRANTY; for details
|
||||
invoke $0 -C. This is free software, and you are welcome
|
||||
to redistribute it under certain conditions; invoke $0 -C
|
||||
for details.
|
||||
EOF
|
||||
|
||||
|
||||
|
||||
local($passwd);
|
||||
|
||||
# password to send to chronyc
|
||||
my($pl) = $ENV{"CHRONYPASSWORD"};
|
||||
|
||||
#password comand to send to chronyc
|
||||
if ( $pl ) {
|
||||
$passwd = "password $pl\n";
|
||||
} else {
|
||||
$passwd = "";
|
||||
}
|
||||
print "passwd=$passwd\n" if ($pedebug);
|
||||
|
||||
my(%host2ip);
|
||||
|
||||
# hash of arrays. host2ip{$host}[0] is ip address for this host
|
||||
# host2ip{$host}[1] is rest of paramenters for this host exc offline.
|
||||
|
||||
#if debuging do chrony.conf in current directory.
|
||||
my($listfile) =( ($pedebug) ? "./chrony.conf" : "/etc/chrony.conf") ;
|
||||
|
||||
# This section reads in the old data about
|
||||
# hostnames IP addresses and server parameters
|
||||
# data is stored as it would be in chrony.conf
|
||||
# file i.e.:
|
||||
#># HOSTNAME
|
||||
#>server IPADDR minpoll 5 maxpoll 10 maxdelay 0.4 offline
|
||||
#
|
||||
# the parameter offline is omitted if the -n switch is specified.
|
||||
# first parameter is the filename of the file usually
|
||||
# is /etc/DNSchrony.conf
|
||||
# this is where we store the list of DNS hosts.
|
||||
# hosts with static IP address shold be kept in chrony.conf
|
||||
|
||||
# this is header that marks dnyamic host section
|
||||
my($noedithead)=<<'EOF';
|
||||
## DNSchrony dynamic dns server section. DO NOT EDIT
|
||||
## per entry FORMAT:
|
||||
## |--------------------------------------------|
|
||||
## |#HOSTNAME |
|
||||
## |server IP-ADDRESS extra-params [ offline ] |
|
||||
## |--------------------------------------------|
|
||||
EOF
|
||||
#patern that recognizes above.
|
||||
my($noeditheadPAT) =
|
||||
qr/\#\#\s+DNSchrony\s+dynamic\s+dns\s+server\s+section\.\s+DO\s+NOT\s+EDIT\s*/;
|
||||
|
||||
#end of header marker.
|
||||
my($noeditheadend)=<<'EOF';
|
||||
## END OF DNSchrony dynamic dns server section.
|
||||
EOF
|
||||
|
||||
#pattern that matches above.
|
||||
my($noeditheadendPAT)=
|
||||
qr/\#\#\s+END\s+OF\s+DNSchrony\s+dynamic\s+dns\s+server\s+section.\s*/;
|
||||
|
||||
#array to hold non dns portion of chrony.conf
|
||||
my(@chronyDconf);
|
||||
|
||||
|
||||
my($ip);
|
||||
my($rest);
|
||||
my($host);
|
||||
|
||||
# for each entry in the list of hosts....
|
||||
open(READIN, "<$listfile") or BadDie("Can not open $listfile");
|
||||
|
||||
# read till dynamic patern read save in @chronyDconf
|
||||
|
||||
while ( <READIN> ) {
|
||||
|
||||
my($line) = $_;
|
||||
|
||||
last if ( m/\A$noeditheadPAT\Z/ );
|
||||
|
||||
push(@chronyDconf,$line);
|
||||
|
||||
}
|
||||
|
||||
while ( <READIN> ) {
|
||||
|
||||
#end loop when end of header encountered
|
||||
last if ( m/\A$noeditheadendPAT/ );
|
||||
|
||||
# parse the line giving ip address, extra pamamters, and host
|
||||
#do host comment line first
|
||||
($host) = m{
|
||||
\A\#\s*
|
||||
($hostnamePAT)
|
||||
\s*\z
|
||||
}xio;
|
||||
|
||||
#no match skip this line.
|
||||
next unless ( $host );
|
||||
|
||||
# read next line
|
||||
$_ = <READIN>;
|
||||
|
||||
# parse out ip address extra parameters.
|
||||
($ip,$rest) =
|
||||
m{
|
||||
\A
|
||||
\s*
|
||||
server #server comand
|
||||
\s+
|
||||
($ipPAT) #ip address
|
||||
(?ixo: \s )
|
||||
\s*
|
||||
(
|
||||
(?(?!
|
||||
(?iox: offline )? #skip to offline #
|
||||
\s* #or #
|
||||
\Z
|
||||
).)*
|
||||
)
|
||||
(?ixo:
|
||||
\s*
|
||||
(?ixo: offline )? #consume to #
|
||||
\s*
|
||||
\Z
|
||||
)
|
||||
}xio ;
|
||||
|
||||
#if failure again.
|
||||
next unless ( $ip );
|
||||
|
||||
$rest =~ s/\s*\z//; #remove trail blanks
|
||||
#from parameters
|
||||
# store the data in the list
|
||||
# key is host name value is
|
||||
# array [0] is ip address
|
||||
# [1] is other parameters
|
||||
$host2ip{$host} = [$ip,$rest] ;
|
||||
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
|
||||
|
||||
}
|
||||
#read trailing line into @chronyDconf
|
||||
while ( <READIN> ) {
|
||||
|
||||
push(@chronyDconf,$_);
|
||||
|
||||
}
|
||||
|
||||
close(READIN) or BadDie("can not close $listfile");
|
||||
|
||||
#if the add command:
|
||||
# command can be HOST=IPADDRESS OTHER_PARAMETERS
|
||||
# means add the server trust the ip address geven with out a dns lookup
|
||||
# good for when dns is down but we know the ip addres
|
||||
# or
|
||||
# HOST OTHER_PARAMETERS
|
||||
#we lookup the ip address with dns.
|
||||
|
||||
if ($opts{'a'}) {
|
||||
my($param)= shift;
|
||||
|
||||
|
||||
# parse the param is it hostname
|
||||
if ( ($host,$ip) = $param =~ m/\A($hostnamePAT)=($ipPAT)\Z/ ) {
|
||||
printf "ip=$ip host=$host\n" if ($pedebug);
|
||||
} else {
|
||||
|
||||
$host = $param;
|
||||
|
||||
# get the ip address
|
||||
$ip = gethostaddr($host);
|
||||
|
||||
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
|
||||
print "query failed: ", $ip, "host=$host\n" if $pedebug;
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
printf "ip=$ip host=$host\n" if ($pedebug);
|
||||
|
||||
# add the server using chronyc
|
||||
my($status) = chronyc("add server $ip $rest");
|
||||
if ($status) { #chronyc error
|
||||
print "chronyc failed, status=$status\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# get rest of arguements
|
||||
$rest = join( ' ', @ARGV);
|
||||
print "rest=$rest\n" if ($pedebug);
|
||||
|
||||
#save node in hash
|
||||
$host2ip{$host} = [$ip,$rest] ;
|
||||
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
|
||||
|
||||
}
|
||||
|
||||
#delete command if arguement is ip address
|
||||
#just delete it
|
||||
#if a hostname look it up
|
||||
#then delete it.
|
||||
|
||||
if ($opts{'d'}) {
|
||||
$host = shift;
|
||||
|
||||
#get host name is it ap address
|
||||
if ( isIpAddr($host) ) { # if ip address
|
||||
my($hostIT);
|
||||
my($found) =0;
|
||||
foreach $hostIT (keys(%host2ip) ) { #search for match
|
||||
if ( $host2ip{$hostIT}[0] eq $host) {
|
||||
$found=1; #record match
|
||||
}
|
||||
} #end of search
|
||||
if ($found) { #if match found
|
||||
my($status) = chronyc("delete $host"); #chronyc
|
||||
if ($status) { #chronyc error
|
||||
print "chronyc failed, status=$status\n";
|
||||
exit 1;
|
||||
} else { #reiterate
|
||||
foreach $hostIT (keys(%host2ip) ) {
|
||||
if ( $host2ip{$hostIT}[0] eq $host) {
|
||||
delete $host2ip{$hostIT}; #deleting match hosts
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else { #else not ip address
|
||||
#must be hostname
|
||||
if ( ! $host2ip{$host} ) {
|
||||
print "No such host as $host listed\n";
|
||||
exit 1;
|
||||
}
|
||||
#get ip address
|
||||
$ip=gethostaddr($host);
|
||||
if ( ! isIpAddr($ip) ) { #no ip address
|
||||
print "query failed: ", $ip, "\n" if $pedebug;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
printf "ip=$ip host=$host\n" if ($pedebug);
|
||||
|
||||
my($listed_host_ip) = $host2ip{$host}[0]; # get the ip address saved
|
||||
|
||||
if ( $ip ne $listed_host_ip) {
|
||||
print
|
||||
"Info: listed host ip=>$listed_host_ip".
|
||||
"< is different from DNS ip=>$ip<\n";
|
||||
$ip = $listed_host_ip;
|
||||
}
|
||||
|
||||
# delete the server
|
||||
my($status) = chronyc("delete $listed_host_ip\n");
|
||||
|
||||
if ($status) {
|
||||
print "chronyc failed, status=$status\n";
|
||||
exit 1;
|
||||
}
|
||||
#delete table entry
|
||||
delete$host2ip{$host};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#update for each host who's dns ip address has changed
|
||||
#delete the old server and add the new. update the record.
|
||||
if ($opts{'u'}) {
|
||||
my($command);
|
||||
|
||||
my(%prospective); # store new IP address we
|
||||
#are thinking of changing.
|
||||
|
||||
Log('local0.info',
|
||||
"Now searching for modified DNS entries.");
|
||||
|
||||
foreach $host (keys(%host2ip)) { #for each listed host
|
||||
my($old_ip) = $host2ip{$host}[0]; #get old ip
|
||||
$rest = $host2ip{$host}[1]; #extra params
|
||||
|
||||
$ip = gethostaddr($host); #get new ip from dns
|
||||
#if error
|
||||
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
|
||||
print "query failed: ", $ip, "host=$host\n";
|
||||
|
||||
Log('local0.err',"query failed: ". $ip . "host=$host");
|
||||
|
||||
exit 1;
|
||||
}
|
||||
|
||||
next if($ip eq $old_ip); #if ip not changed, skip
|
||||
|
||||
Log('local0.info',"Ip address for $host has changed. Old IP address=".
|
||||
"$old_ip, new IP address=$ip");
|
||||
# add command to delete old host, add the new.
|
||||
$command = $command . "delete $old_ip\n" .
|
||||
"add server $ip $rest\n";
|
||||
|
||||
# we are now thinking about changing this host ip
|
||||
$prospective{$host} = [$ip,$rest];
|
||||
}
|
||||
# submit all the accumulated chronyc commands if any.
|
||||
if ($command) {
|
||||
$status = chronyc($command);
|
||||
if ($status) {
|
||||
print "chronyc failed, status=$status\n";
|
||||
Log('local0.err',"query failed: ". $ip . "host=$host");
|
||||
exit 1;
|
||||
}
|
||||
} else { #if no commands exit
|
||||
exit 0; #because no rewrite of file needed
|
||||
}
|
||||
|
||||
#copy prospective modifications back into main table.
|
||||
#we now know that all these mods were done with chronyc
|
||||
foreach $host (keys(%prospective)) {
|
||||
my($ip) = $prospective{$host}[0];
|
||||
$rest = $prospective{$host}[1];
|
||||
$host2ip{$host} = [$ip,$rest];
|
||||
}
|
||||
}
|
||||
|
||||
#starting for each entry we have read in from the old list
|
||||
# add the server in chronyc
|
||||
# this option is seldom used.
|
||||
|
||||
if ($opts{'s'}) {
|
||||
my($command)="";
|
||||
|
||||
foreach $host (keys(%host2ip)) {
|
||||
$command = $command . "add server $host2ip{$host}[0] ".
|
||||
"$host2ip{$host}[1]\n";
|
||||
}
|
||||
my($status) = chronyc($command);
|
||||
if ($status) {
|
||||
print "chronyc failed, status=$status\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
}
|
||||
# write out the data file in format
|
||||
#># HOSTNAME
|
||||
#>server IPADDRESS extra parameters [offline]
|
||||
# offline is omitted if -n switch is specified.
|
||||
|
||||
my(@value);
|
||||
my($such);
|
||||
{
|
||||
# to start out we write to temporary file.
|
||||
(my($writeout) , my($outname)) = mkstemp( "${listfile}.outXXXXXXX");
|
||||
|
||||
$outname or BadDie("can not open for $listfile");
|
||||
|
||||
|
||||
# save the chrony.conf part!
|
||||
# and write the DYNAMIC header
|
||||
print $writeout @chronyDconf, $noedithead;
|
||||
|
||||
|
||||
# for each entry
|
||||
foreach $host (keys(%host2ip) ){
|
||||
|
||||
#write the record
|
||||
|
||||
# write the comment that indicates the hostname
|
||||
# and the server command.
|
||||
print $writeout
|
||||
"\# $host\nserver $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\n" ;
|
||||
|
||||
print
|
||||
"server $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\# $host\n"
|
||||
if $pedebug;
|
||||
|
||||
}
|
||||
|
||||
#WRITE THE end of dnyamic marker comment
|
||||
print $writeout $noeditheadend;
|
||||
|
||||
# close the output file which was a temporary file.
|
||||
close($writeout) or BadDie("can not close $outname");
|
||||
|
||||
# we now begin a intracate dance to make the the temporary
|
||||
# the main chrony.conf
|
||||
#
|
||||
# if there is a chrony.conf.BAK save it to a temporary.
|
||||
# rename chrony.conf to chrony.conf.BAK
|
||||
# rename the temporary to chrony.conf
|
||||
# if there already was a chrony.conf.BAK, unlink the copy of this.
|
||||
|
||||
my($backname) = "$listfile\.BAK";
|
||||
my($backplain) = ( -f $backname );
|
||||
my($saveback);
|
||||
#if chrony.conf.BAK exists rename to a temporary.
|
||||
if ($backplain ) {
|
||||
|
||||
$saveback = mktemp("${backname}.bakXXXXXXX");
|
||||
move($backname,$saveback) or
|
||||
BadDie "unable to move $backname to $savename";
|
||||
|
||||
}
|
||||
|
||||
# rename old chrony.conf to chrony.conf.BAK
|
||||
move($listfile,$backname) or
|
||||
BadDie "unable to move $listfile to $backname";
|
||||
|
||||
# rename our output to chrony.conf
|
||||
move($outname,$listfile) or
|
||||
BadDie "unable to move $outname to $listfile";
|
||||
|
||||
#if there was a temporary chrony.conf.BAK that we saved to temp
|
||||
#unlink it
|
||||
unlink($saveback) or BadDie "unable to unlink $saveback" if($backplain);
|
||||
|
||||
}
|
||||
21
contrib/DNSchrony/DNSchronyADD
Executable file
21
contrib/DNSchrony/DNSchronyADD
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# $1 is chrony password.
|
||||
# $2 is hostname to add or hostname=ipaddres
|
||||
# $3-$9 is rest of extra server parameters
|
||||
|
||||
FIRST="$1"
|
||||
HOST="$2"
|
||||
shift 2
|
||||
|
||||
#remaining parameters a the other paramaters to server command
|
||||
#excluding "offline"
|
||||
ARGS="$*"
|
||||
|
||||
#if none use default taken from chrony documentation.
|
||||
DEF="minpoll 5 maxpoll 10 maxdelay 0.4"
|
||||
|
||||
DARGS=${ARGS:-$DEF}
|
||||
|
||||
CHRONYPASSWORD=$FIRST \
|
||||
/usr/local/bin/DNSchrony.pl -a "$HOST" "$DARGS"
|
||||
7
contrib/DNSchrony/DNSchronyDELETE
Executable file
7
contrib/DNSchrony/DNSchronyDELETE
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# $1 is chrony password.
|
||||
# $2 host to be deleted if ip nn.n.n.n then no DNS used
|
||||
|
||||
CHRONYPASSWORD=$1 \
|
||||
/usr/local/bin/DNSchrony.pl -d $2
|
||||
7
contrib/DNSchrony/DNSchronyUPDATE
Executable file
7
contrib/DNSchrony/DNSchronyUPDATE
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# $1 is chrony password.
|
||||
|
||||
|
||||
CHRONYPASSWORD=$1 \
|
||||
/usr/local/bin/DNSchrony.pl -ulS
|
||||
166
contrib/DNSchrony/README
Normal file
166
contrib/DNSchrony/README
Normal file
@@ -0,0 +1,166 @@
|
||||
Copyright (C) Paul Elliott 2002
|
||||
|
||||
|
||||
DNSchrony.pl version -2.0
|
||||
|
||||
Problem: If you look at the list of secondary NTP servers:
|
||||
http://www.eecis.udel.edu/~mills/ntp/clock2.htm
|
||||
|
||||
you will find statements like this:
|
||||
|
||||
"Note: IP addresses are subject to change; please use DNS"
|
||||
|
||||
These servers represent a problem for chrony. Chrony is a program
|
||||
designed to work on hosts with an intermittent connection to the
|
||||
internet. Often no DNS is available when chrony starts. As chrony
|
||||
is currently designed, chronyd never sees a DNS host name. If a
|
||||
user specifies one when using chronyc's "add server" command, the
|
||||
DNS lookup is done by chronyc and an IP address is passed to chronyd.
|
||||
|
||||
One can imagine I suppose, a redesign to chrony in which chronyd
|
||||
keeps track of DNS changes. But this has problems, all the time
|
||||
chronyd is fooling around with DNS, it would not be keeping track
|
||||
of its prime function, what the clocks and NTP servers are saying.
|
||||
This could result in poorer performance. Or perhaps you say that
|
||||
chronyd should be multi threaded. One thread to fool with DNS
|
||||
and another to keep track of time. But this introduces a great
|
||||
deal of complexity, and complexity is the enemy of elegant robust
|
||||
code. Besides, Richard probably has better things to do.
|
||||
|
||||
I have attempted to address this problem with a humble perl script,
|
||||
which I now release under the GPL: DNSchrony.pl
|
||||
|
||||
PLEA FOR HELP FROM EXPERIENCED PERL HACKERS.
|
||||
|
||||
Please go thru the code and find errors and improvements.
|
||||
I am not quite an polished perl hacker. Please fix bugs and
|
||||
make improvements. It needs better documentation. Someone
|
||||
who knows how, put in some POD.
|
||||
|
||||
END OF PLEA
|
||||
|
||||
Philosophy of DNSchrony.pl: keep a list of servers that use
|
||||
DNS. From time to time, hopefully when DNS is up, go thru
|
||||
the list lookup all the hostnames and see if any ip addresses have
|
||||
changed. If any have changed, update our list and do chronyc
|
||||
"delete" and "add server" commands so that chronyd now talks to
|
||||
the right NTP server.
|
||||
|
||||
Additional nuance: keep the list in /etc/chrony.conf in the
|
||||
form of comments starting with "#" and "server" commands
|
||||
legal in a chrony.conf file. Format of a list entry:
|
||||
|
||||
# hostname
|
||||
server IP-ADDRESS extra server parameters
|
||||
|
||||
These entries are delimited by special comments that allow
|
||||
DNSchrony.pl to find them and also tell humans not to mess with them.
|
||||
|
||||
Example of such a section of a chrony.conf file:
|
||||
|
||||
dumpdir /var/log/chrony
|
||||
rtcfile /etc/chrony.rtc
|
||||
|
||||
## DNSchrony dynamic dns server section. DO NOT EDIT
|
||||
## per entry FORMAT:
|
||||
## |--------------------------------------------|
|
||||
## |#HOSTNAME |
|
||||
## |server IP-ADDRESS extra-params [ offline ] |
|
||||
## |--------------------------------------------|
|
||||
# tock.greyware.com
|
||||
server 208.14.208.44 minpoll 5 maxpoll 10 maxdelay 0.4 offline
|
||||
# tick.greyware.com
|
||||
server 208.14.208.19 minpoll 5 maxpoll 10 maxdelay 0.4 offline
|
||||
# ntppub.tamu.edu
|
||||
server 128.194.254.9 minpoll 5 maxpoll 10 maxdelay 0.4 offline
|
||||
## END OF DNSchrony dynamic dns server section.
|
||||
|
||||
This allows the list of dynamic DNS servers to be preserved
|
||||
when chronyd is stoped/started.
|
||||
|
||||
All servers that do not have ip addresses subject to change
|
||||
should be put in the regular part of chrony.conf as described
|
||||
in the chrony documentation.
|
||||
|
||||
Security philosophy: DNSchrony does no security checking but
|
||||
relies on other security factors.
|
||||
|
||||
Users without the privilege to modify /etc/chrony.conf and the
|
||||
directory /etc will be unable to use DNSchrony to do so, because
|
||||
of file protections. DNSchrony passes thru passwords to chronyc.
|
||||
Users that do not know the correct chronyc password will be
|
||||
unable to get chronyd do do anything. Thus, DNSchrony passes
|
||||
the buck to these other security features.
|
||||
|
||||
INSTALLATION:
|
||||
|
||||
copy the files: DNSchronyADD DNSchronyUPDATE DNSchronyDELETE DNSchrony.pl
|
||||
to /usr/local/bin. Backup the file /etc/chrony.conf leave hosts
|
||||
with static ip addresses in this file.
|
||||
|
||||
DNSchrony uses the following perl modules. See that they are installed.
|
||||
Get them from CPAN if needed.
|
||||
|
||||
Net::DNS, Tie::Syslog, Getopt::Std, Socket, File.
|
||||
|
||||
Cause DNSchronyUPDATE bash script to run from time to time when DNS
|
||||
is working. If you have a dialup, one way to do this would be to
|
||||
modify your /etc/ppp/ip-up.local file as follows:
|
||||
|
||||
cat <<EOF | /usr/local/bin/chronyc
|
||||
password mysecret
|
||||
online
|
||||
EOF
|
||||
# update all of the dynamic servers and save the result.
|
||||
# do not wait for response
|
||||
|
||||
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
|
||||
|
||||
Since this file contains the chronyc password you will want to set the
|
||||
file permissions so that just everybody will not be able to read
|
||||
it. But you already did that when you put in the chronyc command. Any
|
||||
other way to make DNSchronyUPDATE run perodicly when DNS is up will
|
||||
also work.
|
||||
|
||||
To add a server with a varying IP address one could run:
|
||||
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com
|
||||
|
||||
or if you want to specify different server parameters you
|
||||
could say:
|
||||
|
||||
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com "minpoll 10 maxpoll 20 maxdelay 0.8"
|
||||
|
||||
The DNSchronyADD's default for these parameters is:
|
||||
"minpoll 5 maxpoll 10 maxdelay 0.4" values that are often shown
|
||||
as examples in the chrony documentation.
|
||||
|
||||
If DNS is not running now but you know the IP address, you can say:
|
||||
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com=208.14.208.44
|
||||
|
||||
Of course, the IP address will be checked next time DNSchronyUPDATE
|
||||
runs.
|
||||
|
||||
To delete dynamic DNS a server:
|
||||
/usr/local/bin/DNSchronyDELETE mysecret tock.greyware.com
|
||||
|
||||
To change parameters delete and re-add.
|
||||
|
||||
Of course, in all of the above "mysecret" is your chronyc password
|
||||
which SHOULD NOT BE "mysecret".
|
||||
----------------------------------------------
|
||||
DNSchrony.pl is covered by the GPL
|
||||
# Copyright (C) Paul Elliott 2002
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# SEE COPYING FOR DETAILS
|
||||
22
contrib/DNSchrony/ip-up.local
Normal file
22
contrib/DNSchrony/ip-up.local
Normal file
@@ -0,0 +1,22 @@
|
||||
#example file /etc/ppp/ip-up.local
|
||||
#originally from SuSE distribution
|
||||
#modified for chrony
|
||||
cat <<EOF | /usr/local/bin/chronyc
|
||||
password mysecret
|
||||
online
|
||||
EOF
|
||||
# update all of the dynamic servers and save the result.
|
||||
# do not wait for response
|
||||
|
||||
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
|
||||
#other stuff who knows?
|
||||
|
||||
# The following lines added for Linux-HA support # Heartbeat
|
||||
DEVFILE=`echo $DEVICE | sed -e 's!^/dev/!!' -e 's!/!.!g'` # Heartbeat
|
||||
OUTFILE=/var/run/ppp.d/$DEVFILE # Heartbeat
|
||||
( # Heartbeat
|
||||
echo "$IPREMOTE" # Heartbeat
|
||||
echo "$IFNAME" # Heartbeat
|
||||
echo "$PPPD_PID" # Heartbeat
|
||||
echo "$IPLOCAL" # Heartbeat
|
||||
) > $OUTFILE # Heartbeat
|
||||
114
contrib/andrew_bishop_1
Normal file
114
contrib/andrew_bishop_1
Normal file
@@ -0,0 +1,114 @@
|
||||
From amb@gedanken.demon.co.uk Tue Aug 17 22:14:00 1999
|
||||
Date: Fri, 6 Aug 1999 19:00:24 +0100
|
||||
From: Andrew M. Bishop <amb@gedanken.demon.co.uk>
|
||||
To: richard@rrbcurnow.freeserve.co.uk
|
||||
Subject: Re: Chrony and laptop configuration
|
||||
|
||||
Hi,
|
||||
|
||||
Attached is the apmd_proxy script from the apmd-3.0beta9 distribution.
|
||||
|
||||
The changes that I would make are the following:
|
||||
|
||||
Replace the update_clock function (line 122) with
|
||||
|
||||
update_clock () {
|
||||
|
||||
chronyd -f /etc/chrony.conf
|
||||
|
||||
}
|
||||
|
||||
Around line 171 (in the suspend actions section) I would kill chronyd.
|
||||
|
||||
begin 644 apmd_proxy.gz
|
||||
M'XL("+L@JS<``V%P;61?<')O>'D`I5K[;]M&$OY9^BLV2JZQ6TF.`Q2XUDA1
|
||||
MQU8<]>('_&A[.!R,-;D2MR&Y+)?TXZ[WO]\W,\N'%-E)[X08CJ2=V7G/-T,_
|
||||
M?[9S8_,=GPR?*_S3119?%Z6[?U`3A=_+4F<JMK[059284BU<J?;/CE6L3>9R
|
||||
M$!R4VB[5L2X_WNDRKM161!]D/Z:)T9FVZ73I%]$TUUY/E^YV6[W>Q>$'M?O=
|
||||
M=]^!^E#?VEB]+=U=;M)4;<4W/Q;.5]-$E[=@-S5QO:V^4S_5N0DD(+I,K%<^
|
||||
M(0(?E;:H%-Y'.DU-K&X>5)68GHAJBU3:5G>)R?DK7^G*@(M;*)T_J,+=0:U,
|
||||
MYWII,I-7:E'G465!F&AP372^-/%4X5*CS+V.*F5N<<R#EZ[`IBKM<@D.Q)ID
|
||||
ML/F267=VC$UA\E@11W?'7Z@[8NWRA5W6I8G)[!7>9X5-C:IL9J:LYR^V2BP)
|
||||
M3>J*HJS`@Z],IG2<V=SZJM05?.(35Z>Q*NJ*M0(SJ!1[TK-4FA7RL(&-DN;H
|
||||
MC5&%*>'/#&:K"XC'EH%".O>6"42,GBJ=G>\@F_*%B>S"1DJ7RSIKK0*-25Q<
|
||||
M0.*RN<A0]`W9U$51799LU#F[KJ?@2Z]*XR&,MS<VM16\Z=3OM2G9K>""P(@1
|
||||
M:(;4:ASM37EK(Z.V;JU6.Y`TVH',VQRKF<-9FY.:FG0:DT+P!MA6^J-(J`O0
|
||||
M%*4E[<54HO@[T,/E69&:<?";1<R1!=2H9Q5?>_:P.&:D?JM]!?/B3L-ZMRYC
|
||||
M-1/$-%D0$BP=1,/OAD'F8A-";<6[X)(A9^ZL3X@LN$W!2V;2^2`X.;50J\Y3
|
||||
MIV.*Q;BTMZ:$U8D+$EG?<(B25+FI[ESYD60`1QW1W;^T:=**#(?4%",I[%..
|
||||
M0T`\8@HYJW(R=SH:4UQ+T%%4@Z_SC8DI-+M(+`T)B9A@P\\7+,)'4Z(J2"ZS
|
||||
M%B0-G:/LW)WNOJ(@2.R2ZM)6[<69),T(/$(&D+T6EM*OKK;'_5B.=(YKJ[K,
|
||||
M$1#*E"6817``AXT$6^,7XH/DR&-4%\G^,8P6VP@A!5NBM%1)*`%TGCXC5ZYI
|
||||
M^)N)*H[Z3^(J2$0^CN%-R&`78W6C81`E1?;LBG1M'$86O*7DP&?0&W;)$2FU
|
||||
MV!4L6\$10A6%-=7%$(IDS;?STXM-HK'Q\7KV3)V<7L[HMY)JBW^YJT*VM`+7
|
||||
M(B"41<`?FAL+0TK<^&>!U_GL\NK\1/V\_^%J]KUP5Z_06G*'^-9I\,#>$Z96
|
||||
ME.TZBDQ1<:FDURXXB-0]9:D*!LJMXZN+2_5^_^<9ZWMX/O]Y=BXA<WJNWL^/
|
||||
MWL_.MUG"]X:XEV:E?GN#DI-'QG,L=`I_OUX/<5]9J977I-][J-SQ&2GR?4)7
|
||||
MJ"<(N<'5%8=7C.:X1KU2<'K4X0.ZMB0=/+F^7UTV\T'IK1#,Z3J?$..P0WNB
|
||||
M(=GZ>OL34[#IOU"F<)ID4IN%XL!N3'-%;[Y8K<#\LQQZ0JQR"&6LN4(X7/05
|
||||
MD9*X*%WVA"`-FW#/9]A\3IJ>EYY@L^ZI55:"9U!:JHIZZB=>*DWA*%I5"J@2
|
||||
M3FWD(+!)/<%A_V"GN49H-O+AOO`DG]R0:E23Z6A=Q-2F/PF_P"[2A0[`X1%V
|
||||
M`KNF#<'6-U('P'`U`ZD8HS;"&^BNTJZYVZ%.H-.T%8)(OV'26X!=-%>JW1LZ
|
||||
MEZ\+$@"5%!`Y?(:?Z5H?$V$NYL=G'^;OYK-#=7!Z\FY^='6^?SD_/5$JX%_`
|
||||
M'X``!C0$-OL(D=H:Y(::5>D8JAG+W8ERTTA%D>ZVP-?NCMX#:EL2W?>A4/HP
|
||||
M)KFH#L>V(6L!=^5-NI"&<6$J=75YP)"JK%G_!U>CF:8N^DB5K&ED<HK@;>@J
|
||||
M)`]Q!A.\<[!':>,8``27$HH-\L)HN=HQ5;0#9XK_=ICY=`B.;Q8Z]::5Y.+J
|
||||
MXFQV<GA]>G*]SS+QUT&H%D+I6V?C34T'7$+;X8&!%<ET!!QN&/VZ/.=>24S`
|
||||
MG],`ZKRESKW0=5IUL,&S+QCMDO*-&T).T!S5T`]7A'Y#5F1]S@Z.#^;[8%,&
|
||||
M9AR0`G[A+;@+H)MCCE3*)=Z#3JS%5,`4:9[H6S0ZYB50'/RHI=^T90Y*D?--
|
||||
MF:*!^AJ@#;5%JXN#BSGA*1`"0%5D%<1PAQY&`3V,`N15AN`DM]$^K`UQ*[I0
|
||||
MPZ7+B^3!4['"C8'+GD)8PTYC05-<96A$`$C@'NH6"PZT!#E-<)\A'S&-JE1X
|
||||
MC!KH-V:_,H!EP,0XB`<=\)&:.1V*B:]G/\T.+LG\P1-=4-&0.GM[=70T/SGB
|
||||
M=U<Y\:=)L1FR@+9CB!D<?#R[?']Z"(CBVO^_YOH5FYMZN91PS^`]#)P^Z-)4
|
||||
MJ=2A,JD36*8T<DL<BM_2Y$CXE'K:&,`?I8>2IN(RU6@GT0J,_U&B!&[.N7RV
|
||||
M`ZP'5W((\*H3"`\NN%1196O5(;,)'F[%1*US-?E51NRN\$H):'6>J`]NZ5OP
|
||||
MG5+:=,/AZESL\O1!KJ?YN??%BZ^I&W1L7S=LP<1"K[+.UUC!BCM55NSTY`);
|
||||
MRN4H<>KEUVNOE^J''YXB&+UX!2%&?73V*`&WHPVOIV]X.5E[/272O8DV7/#Z
|
||||
M40*4336Y9\?L4\5");#4K*@0)ZK$)!2J&<(HK6,I9IZ6$_33#MQ->2*.E:[J
|
||||
ML`Y8-^;_\!H.A\SY&L+1\&ZVMM6_AP,IX//#&4_Y$LB^``@%``X#I".\GZ"1
|
||||
M\GLB.>215L(RE&#(.=CQM-5*XD)C4)[\KB87:O>O:B<VM_A0#P:@Q/LW;]!_
|
||||
MOU4816J@W.&`*N_>\#^->&'0UK!=(V&X[A$I_YQ`KUIY>C<_Y]'K>]4-:LT$
|
||||
MCR88<,7KZ6M.4I[(I;(CU6/>*J"O#@4D74L#;B0/R"FP@"4S6NEU"Q4^/1R@
|
||||
M4?Y#318;^ZWZYQXW@.&``G"Z\8Q\AT*=4D]]2(U\P&Q'+PX^G![\[?CT<#92
|
||||
M;]31\67'<4"MG#L?GU_8X8!^F.X%`8<WH9.OR/#NP_[1F]%H.#!4KGL?3>J1
|
||||
M,(`R]TJ,'W107WT5L,G$JQ=T7/WQATKN5C\C7Q"DX`D/U2;3L#_MEDQ<EX1@
|
||||
MYDWRD/'".,\ESCM$:F9I&Q?2I[==!(>%I2%S')8QJX&",HVX+B<"F:0K]!%%
|
||||
M#ZFTB*`9W\G&=S+,HL=UX.+Y<!B!':R_.T(0#8?DGO7Z$UX-?.*++B[W3P[?
|
||||
M_OV1L\SF/8>=BFH,M)G]%REC$(_6=9OB9JYAT?O@Q#,'M$RRYJ%I-B<NH"Y1
|
||||
M?LS@I;_]"HB'K>P6S*-*6@^T:S#&.`)QIZ3R*-P]^F,4)!IM#RDO]ION*2C:
|
||||
M+-E/:W@Q^"HLMMK9:O`)6OS$_"W4%;[4]!0M<9#/"Z)G7;NE#'MYM+Y1;#8A
|
||||
M"\IW>-W&*1<_%"CKJ+GOI]X%4\GRD9ID3N;4Z@.JVWUO)"'";@+9N$RC#LN+
|
||||
MM)7UV12434:NPNPF-R=:O7B-=P'.=,D-(I=?Z^A:$-T/7/CR.DW;$P-S#SBS
|
||||
M2^X\E\W.%N^@@MQA?FK5DRB(MT$92D4CV2[='V*N$X"YOY*2P%G=WS!5#T5`
|
||||
MH;%C7+ITJM"^DI`HG,VKL;JI&3,3>0B.!@?"-K(9N\$(PY@'K?)/AU8`^V&9
|
||||
M[:5DTU9^)6<"D`N'@QO#,HTBBR#=H+>YY"4M0>X`S@D+)S+,K:EFR@HECHC;
|
||||
M>>.)^0!?06J,B#0>"`7'!TGG&YC?.`LW1V91DX#>+2IJ-Y-N'2H#"NO;0FN6
|
||||
MCK:Q8>)@*4H!``CUE9.<"9$KY<%!+`L\,;4`\_/9Q=7Q##<=A/U>,S#T+#7B
|
||||
M%2=C9:Y<88V)O*:5=3`W!IF:I^22[]3MR$\&)&,ANR::U.M=1B"]1>..8)AE
|
||||
MY])Y--\,=NDE5M>LPDP30EA)$B&^'YE8$/4\?7<A/UAEQ`:G3.!.N?YM6]&Z
|
||||
M=.J/.AL"&#-)J8O$1EZ&RM@961++:,5YDG=G>-/7Q8\UM$)7OR)B"3DA>$*A
|
||||
ME/K-+N4-C6_6#H8>3#@,?655:YI6<N^H(M?9#7R\.PX/&L2XM:\Y'S`@FONJ
|
||||
M.8P[KBBE1,)Q2$.D".^8*M?="J@,+(#K6-%?V]O0R9FQ>.RY:GU6^Y*?HT;)
|
||||
M;=7YX+D:K'ZSNZ=\:DRA=NG+8&;'<R.9&K*%_@4`*,]PX%57TVZ&^EV`@D0T
|
||||
M^W7_^.P#@.+I!=H&AK.8NR0Y(/AR)^P-&Z,3E:Q"`^.D9<A=6)Z+4:R5A@_4
|
||||
MG:T"K5)GF,[YHEM=/M#BHTO,T)A'+(S+:1_`S7?P7(P`>*53>=C,)Q;H?WM[
|
||||
M3\*1%I9("C]U;"B=@S6>3J>K.U6**^#JLS%@`CU(D&T_XSV!Q5-""*(J8`&5
|
||||
ML;8ET%%IH:&K"1V%#(_OC,`P<D'1/N[^?`/H%B<K>Q[N(DTI;8!A;]]G^=9&
|
||||
MV"[L>;%M2ZE?7-D^4\+6*E:ON7,+#QT$+?VQFO1_ER1+T]_C-:D)O7Y)>B17
|
||||
M0L1^+E?"L2YEPJ'I>F`_&K3YE\<LX//YY9.GF,U!>*!.B<=/5A>V1-ODQT9^
|
||||
MRD?F?6#?+!`9287V2!]E%-8(C&:F'C7XG[`O,4-@*_4%2.R3V;>9K@:K0[N`
|
||||
MJ2^WQNG9TX<V6X/"W92$;_@))9TY##F1,3Y8.8JB,@X9<D//_=6HI\<H;"+9
|
||||
M(*Z@1-^@Z]Z>>EHC=?!^_^1H1MSAXLNKBT=/TDW23^@N'L*06S;,KB.^G+ZA
|
||||
M9+VS]`<VU(5VN'0U`\18Z1B@!,4\0UV(&_>CDE71EP'K#3JV";?N478I^50D
|
||||
MI"5+$%`FGU0ZC/P1"#Y?J7@]PB!EH&U"ELIPI4;H"B.5`L^F:DLV'&9!H!EV
|
||||
M5&:ZG-+>^=M7?Q%:P-"7%>'RC#;2\D<[%2/8VA.F[-_:/?T)%PLWLA_J]5VW
|
||||
>Z]AB9"M2/=L.+(S7D<0S_V\81H;_`M>*^#$A)0``
|
||||
`
|
||||
end
|
||||
|
||||
--
|
||||
Andrew.
|
||||
----------------------------------------------------------------------
|
||||
Andrew M. Bishop amb@gedanken.demon.co.uk
|
||||
http://www.gedanken.demon.co.uk/
|
||||
|
||||
95
contrib/andrew_bishop_2
Normal file
95
contrib/andrew_bishop_2
Normal file
@@ -0,0 +1,95 @@
|
||||
From amb@gedanken.demon.co.uk Wed Sep 1 22:26:59 1999
|
||||
Date: Thu, 19 Aug 1999 17:30:14 +0100
|
||||
From: Andrew M. Bishop <amb@gedanken.demon.co.uk>
|
||||
To: richard@rrbcurnow.freeserve.co.uk
|
||||
Subject: [amb@gedanken.demon.co.uk: Chrony and laptop configuration]
|
||||
|
||||
Hi,
|
||||
|
||||
What you need to do is replace 10.0.0.0 with the network of the
|
||||
freeserve nameservers in the two scripts below.
|
||||
|
||||
Other than that you can use it as is.
|
||||
|
||||
------- Start of forwarded message -------
|
||||
From: "Andrew M. Bishop" <amb@gedanken.demon.co.uk>
|
||||
To: richard@rrbcurnow.freeserve.co.uk
|
||||
Subject: Chrony and laptop configuration
|
||||
Date: Sat, 31 Jul 1999 11:02:04 +0100
|
||||
|
||||
Attached are the ip-up and ip-down files that I use for chrony.
|
||||
(Actually because of the way that debian works they are separate file
|
||||
in the /etc/ppp/ip-up.d directory that are run in a SysV init style).
|
||||
|
||||
They rely on the presence of an 'ipparam demon' or 'ipparam freeserve'
|
||||
line in the PPP options file.
|
||||
|
||||
-------------------- /etc/ppp/ip-up --------------------
|
||||
#!/bin/sh -f
|
||||
#
|
||||
# A script to start chrony
|
||||
#
|
||||
|
||||
PPP_IPPARAM="$6"
|
||||
|
||||
if [ $PPP_IPPARAM = "demon" ]; then
|
||||
|
||||
/usr/local/bin/chronyc << EOF
|
||||
password xxxxxxx
|
||||
online 255.255.255.0/158.152.1.0
|
||||
online 255.255.255.0/194.159.253.0
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
if [ $PPP_IPPARAM = "freeserve" ]; then
|
||||
|
||||
/usr/local/bin/chronyc << EOF
|
||||
password xxxxxxx
|
||||
online 255.255.255.0/10.0.0.0
|
||||
EOF
|
||||
|
||||
fi
|
||||
-------------------- /etc/ppp/ip-up --------------------
|
||||
|
||||
-------------------- /etc/ppp/ip-down --------------------
|
||||
#!/bin/sh -f
|
||||
#
|
||||
# A script to stop chrony
|
||||
#
|
||||
|
||||
PPP_IPPARAM="$6"
|
||||
|
||||
if [ $PPP_IPPARAM = "demon" ]; then
|
||||
|
||||
/usr/local/bin/chronyc << EOF
|
||||
password xxxxxxx
|
||||
offline 255.255.255.0/158.152.1.0
|
||||
offline 255.255.255.0/194.159.253.0
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
if [ $PPP_IPPARAM = "freeserve" ]; then
|
||||
|
||||
/usr/local/bin/chronyc << EOF
|
||||
password xxxxxxx
|
||||
offline 255.255.255.0/10.0.0.0
|
||||
EOF
|
||||
|
||||
fi
|
||||
-------------------- /etc/ppp/ip-down --------------------
|
||||
|
||||
--
|
||||
Andrew.
|
||||
----------------------------------------------------------------------
|
||||
Andrew M. Bishop amb@gedanken.demon.co.uk
|
||||
http://www.gedanken.demon.co.uk/
|
||||
------- End of forwarded message -------
|
||||
|
||||
--
|
||||
Andrew.
|
||||
----------------------------------------------------------------------
|
||||
Andrew M. Bishop amb@gedanken.demon.co.uk
|
||||
http://www.gedanken.demon.co.uk/
|
||||
|
||||
65
contrib/erik_bryer_1
Normal file
65
contrib/erik_bryer_1
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# chrony Start time synchronization. This script
|
||||
# starts chronyd.
|
||||
#
|
||||
# Hacked by: Erik Bryer <ebryer@spots.ab.ca> using inet as a template
|
||||
#
|
||||
# chkconfig: 2345 02 82
|
||||
# description: chronyd helps keep the system time accurate by calculating \
|
||||
# and applying correction factors to compensate for the drift \
|
||||
# in the clock. chronyd can also correct the hardware clock \
|
||||
# (RTC) on some systems.
|
||||
# processname: chronyd
|
||||
# config: /etc/chrony.conf
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
# Source networking configuration.
|
||||
. /etc/sysconfig/network
|
||||
|
||||
# Set path to include chronyd in /usr/local/sbin
|
||||
PATH="$PATH:/usr/local/sbin"
|
||||
|
||||
[ -f /usr/local/sbin/chronyd ] || exit 0
|
||||
|
||||
[ -f /etc/chrony.conf ] || exit 0
|
||||
|
||||
RETVAL=0
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
# Start daemons.
|
||||
echo -n "Starting chronyd: "
|
||||
daemon chronyd
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/chrony
|
||||
echo
|
||||
;;
|
||||
stop)
|
||||
# Stop daemons.
|
||||
echo -n "Shutting down chronyd: "
|
||||
# If not dead killproc automatically sleeps for 4.1 seconds then does
|
||||
# kill -9. "chrony.txt" prefers a 5 second delay, but this should be ok.
|
||||
killproc chronyd -15
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/chrony
|
||||
echo
|
||||
;;
|
||||
status)
|
||||
status chronyd
|
||||
exit $?
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: named {start|stop|status|restart}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
||||
|
||||
100
contrib/ken_gillett_1
Normal file
100
contrib/ken_gillett_1
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# chronyd This shell script takes care of starting and stopping
|
||||
# chronyd (NTP daemon).
|
||||
#
|
||||
# chkconfig: 45 80 20
|
||||
# description: chronyd is the NTP daemon.
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
# Source networking configuration.
|
||||
. /etc/sysconfig/network
|
||||
|
||||
# Check that networking is up.
|
||||
[ ${NETWORKING} = "no" ] && exit 0
|
||||
|
||||
PREDIR="/usr/local"
|
||||
CHRONYD=$PREDIR"/sbin/chronyd"
|
||||
CHRONYC=$PREDIR"/bin/chronyc"
|
||||
|
||||
[ -x $CHRONYD -a -x $CHRONYC -a -f /etc/chrony.conf ] || exit 0
|
||||
|
||||
dochrony() {
|
||||
if [ -z "$(pidofproc chronyd)" ]; then
|
||||
echo -e "\n\tchronyd not running\n\n"
|
||||
exit 2
|
||||
fi
|
||||
KEY=`awk '$1 == "commandkey" {print $2; exit}' /etc/chrony.conf`
|
||||
PASSWORD=`awk '$1 == '$KEY' {print $2; exit}' /etc/chrony/keys`
|
||||
|
||||
$CHRONYC <<- EOF
|
||||
password $PASSWORD
|
||||
$@
|
||||
quit
|
||||
EOF
|
||||
}
|
||||
|
||||
# make the first parameter' lower case
|
||||
set - `echo $1 | awk '{print tolower($1)}';shift;echo "$@"`
|
||||
|
||||
# Expand any shortcuts.
|
||||
case "$1" in
|
||||
on|1)
|
||||
set - "online"
|
||||
;;
|
||||
off|0)
|
||||
set - "offline"
|
||||
esac
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
# Start daemons.
|
||||
echo -n "Starting chronyd: "
|
||||
daemon $CHRONYD
|
||||
if [ $? -eq 0 ]; then
|
||||
echo $(pidofproc chronyd) > /var/run/chronyd.pid
|
||||
touch /var/lock/subsys/chronyd
|
||||
fi
|
||||
echo
|
||||
;;
|
||||
stop)
|
||||
# Stop daemons.
|
||||
echo -n "Shutting down chronyd: "
|
||||
killproc chronyd
|
||||
echo
|
||||
rm -f /var/lock/subsys/chronyd
|
||||
;;
|
||||
status)
|
||||
status chronyd
|
||||
;;
|
||||
restart|reload)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f /var/lock/subsys/chronyd ]; then
|
||||
$0 stop
|
||||
$0 start
|
||||
fi
|
||||
;;
|
||||
"")
|
||||
echo "Usage: chronyd
|
||||
{start|stop|restart|reload|condrestart|status|[on|off]line etc}"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
accheck|cmdaccheck|clients|manual|rtcdata|sources|sourcestats|tracking|clients)
|
||||
dochrony "$@"
|
||||
;;
|
||||
*)
|
||||
echo -n "Chrony $1: "
|
||||
dochrony "$@" > /dev/null
|
||||
[ $? -eq 0 ] && echo_success || echo_failure
|
||||
echo
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
162
contrib/stephan_boettcher_1
Normal file
162
contrib/stephan_boettcher_1
Normal file
@@ -0,0 +1,162 @@
|
||||
From stephan@nevis1.nevis.columbia.edu Mon Jun 7 20:51:57 1999
|
||||
Date: 04 Jun 1999 00:17:25 -0400
|
||||
From: Stephan I. Boettcher <stephan@nevis1.nevis.columbia.edu>
|
||||
To: richard@rrbcurnow.freeserve.co.uk
|
||||
Subject: chrony 1.1 sysV startup script for notebooks
|
||||
|
||||
|
||||
Dear Richard,
|
||||
|
||||
I installed chrony on my notebook, running RedHat 5.1 Linux.
|
||||
It looks like it works. No problems.
|
||||
|
||||
Thank you!
|
||||
|
||||
I like to donate my sysV startup script, appended below.
|
||||
|
||||
Special feature: the `online' command scans the config file to
|
||||
selectively turn some servers online, depending on the pcmcia SCHEME.
|
||||
|
||||
booting: /etc/rc.d/init.d/chrony start
|
||||
/etc/ppp/ip-up: /etc/rc.d/init.d/chrony online
|
||||
/etc/ppp/ip-down: /etc/rc.d/init.d/chrony offline
|
||||
logrotate cron: /etc/rc.d/init.d/chrony cyclelogs
|
||||
a user: /etc/rc.d/init.d/chrony status
|
||||
a sysadmin: /etc/rc.d/init.d/chrony restart
|
||||
shutdown: /etc/rc.d/init.d/chrony stop
|
||||
|
||||
Best regards
|
||||
Stephan
|
||||
|
||||
--
|
||||
|
||||
------------------------------------------------------------------------
|
||||
Stephan Boettcher FAX: +1-914-591-4540
|
||||
Columbia University, Nevis Labs Tel: +1-914-591-2863
|
||||
P.O. Box 137, 136 South Broadway mailto:stephan@nevis1.columbia.edu
|
||||
Irvington, NY 10533, USA http://www.nevis.columbia.edu/~stephan
|
||||
------------------------------------------------------------------------
|
||||
|
||||
########################### cut here ###################################
|
||||
#! /bin/bash
|
||||
#
|
||||
# /etc/rc.d/init.d/chrony
|
||||
#
|
||||
# SYS V startup script for
|
||||
# chrony ntp daemon
|
||||
# on Linux 2.0.3x notebooks with pcmcia scheme support
|
||||
# $Id: stephan_boettcher_1,v 1.1 2000/04/24 21:36:04 richard Exp $
|
||||
#
|
||||
# 1999-06-02 SiB <stephan@nevis1.columbia.edu>
|
||||
#
|
||||
# For PCMCIA users:
|
||||
# In /etc/chrony.conf, precede the server commands for each SCHEME
|
||||
# with a comment line that contains the word SCHEME and the name of
|
||||
# the scheme(s) that should use the servers, up to the next line that
|
||||
# contains the word SCHEME. The servers must be `offline' and
|
||||
# specified by their IP address. The hostname will not do.
|
||||
#
|
||||
# Like:
|
||||
#
|
||||
# # SCHEME nevisppp nevislan
|
||||
# # stephanpc.nevis.columbia.edu
|
||||
# server 192.12.82.222 offline
|
||||
#
|
||||
# # SCHEME desyppp desylan
|
||||
#
|
||||
# # dsygw2.desy.de
|
||||
# server 131.169.30.15 offline
|
||||
# # dscomsa.desy.de
|
||||
# server 131.169.197.35 offline
|
||||
|
||||
CONF=/etc/chrony.conf
|
||||
CHRONYD=/usr/local/sbin/chronyd
|
||||
CHRONYC=/usr/local/bin/chronyc
|
||||
KEYS=/etc/chrony.keys
|
||||
|
||||
# See if we got all we need:
|
||||
|
||||
[ -f $CHRONYD -a -f $CHRONYC -a -r $CONF ] || exit
|
||||
|
||||
|
||||
[ -r $KEYS ] \
|
||||
&& CMDKEY=`awk '/^commandkey/{print $2}' $CONF` \
|
||||
&& PASSWORD=`awk -v KEY=$CMDKEY '$1==KEY{print $2}' $KEYS`
|
||||
|
||||
|
||||
case "$1" in
|
||||
|
||||
start)
|
||||
echo -n "Starting chronyd "
|
||||
$CHRONYD -r -s -f $CONF
|
||||
echo
|
||||
;;
|
||||
|
||||
stop)
|
||||
echo -n "Shutting down chronyd "
|
||||
/usr/bin/killall chronyd
|
||||
echo
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
on*)
|
||||
|
||||
[ -f /var/run/pcmcia-scheme ] && SCHEME=`cat /var/run/pcmcia-scheme`
|
||||
|
||||
awk -v SCHEME=${SCHEME:-default} -v PASSWORD=$PASSWORD \
|
||||
'
|
||||
BEGIN {
|
||||
SEL=1;
|
||||
print "password", PASSWORD;
|
||||
}
|
||||
/SCHEME/ {
|
||||
SEL=match($0, SCHEME);
|
||||
}
|
||||
SEL && /^server[ \t]*[0-9.]+[ \t].*offline/ {
|
||||
print "online 255.255.255.255/" $2;
|
||||
}
|
||||
' \
|
||||
$CONF \
|
||||
| $CHRONYC
|
||||
|
||||
;;
|
||||
|
||||
off*)
|
||||
cat <<-EOF | $CHRONYC
|
||||
password $PASSWORD
|
||||
offline
|
||||
trimrtc
|
||||
dump
|
||||
EOF
|
||||
;;
|
||||
|
||||
*log*)
|
||||
cat <<-EOF | $CHRONYC
|
||||
password $PASSWORD
|
||||
cyclelogs
|
||||
EOF
|
||||
;;
|
||||
|
||||
stat*)
|
||||
cat <<-EOF | $CHRONYC
|
||||
sources
|
||||
sourcestats
|
||||
tracking
|
||||
rtcdata
|
||||
EOF
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: chronyd {start|stop|restart|status|online|offline|cyclelogs}"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
118
contrib/wolfgang_weisselberg1
Normal file
118
contrib/wolfgang_weisselberg1
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
> Is it possible to limit chronyc to only those commands that
|
||||
> are readonly plus those necessary to bring a dialup connection up
|
||||
> and down? That is: online offline dump writertc and password.
|
||||
|
||||
This is trivial on the same host and workable for non-local
|
||||
hosts: use a wrapper program or script. An *untested*
|
||||
sample follows. To use it, best create a special user (say
|
||||
chronyc) and a special group (say chronyg). Make the script
|
||||
chronyc:chronyg, and 4750 (suid, rwxr-x---). Add all users
|
||||
who may run the script to the group chronyg.
|
||||
|
||||
Make a chrony password file e.g.
|
||||
/usr/local/etc/chrony_password. It should be owned by chronyc
|
||||
and readable only for the owner, containing only the chrony
|
||||
password (and maybe a newline) in the first line.
|
||||
|
||||
In this way only the script (call it run_chrony, for example)
|
||||
can read the password. It will allow only those commands you
|
||||
explicitely allow. You can add a password check -- especially
|
||||
if you add an internet port so you can access it over the
|
||||
internet this is advisable. You really want to add logging
|
||||
to this untested script as well.
|
||||
|
||||
|
||||
BTW, if you use some sort of PPP, you probably can use
|
||||
/etc/ppp/ip-up and /etc/ppp/ip-down to transparently set chrony
|
||||
on- and offline as the ip connection goes up and comes down.
|
||||
This is _far_ more user friendly, IMHO, and a DOS by switching
|
||||
chrony offline all the time is avoided as well.
|
||||
|
||||
|
||||
#! /usr/bin/perl -T
|
||||
use v5.6.1;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
sub laundered_command();
|
||||
sub order_chrony($$);
|
||||
sub read_password();
|
||||
sub usage($);
|
||||
|
||||
our $CHRONY = "/usr/local/bin/chronyc";
|
||||
|
||||
# NOTE: select the file system protection wisely for the
|
||||
# PASSWORDFILE!
|
||||
our $PASSWORDFILE = "/usr/local/etc/chrony_password";
|
||||
|
||||
our @ALLOWED_COMMANDS = (
|
||||
'online', # switch online mode on
|
||||
'offline', # switch online mode off
|
||||
'dump', # save measurements to file
|
||||
'writerc', # save RTC accumulated data
|
||||
|
||||
'clients', # which clients are served by us?
|
||||
'rtcdata', # Quality of RTC measurements
|
||||
'sources(?: -v)?', # Show our sources (verbose)
|
||||
'sourcestats(?: -v)?', # How good are our sources (verbose)?
|
||||
'tracking', # whom do we adjust to?
|
||||
|
||||
# 'burst \d+/\d+', # allow them to send bursts?
|
||||
);
|
||||
|
||||
usage("No command given.") unless $ARGV[0];
|
||||
|
||||
%ENV = (); # nuke all environment variables. Rather
|
||||
# drastic, but better safe than sorry!
|
||||
# Add whatever you really need to get it
|
||||
# working (again).
|
||||
$ENV{'PATH'} = '/usr/local/bin:/bin:/usr/bin';
|
||||
|
||||
order_chrony(laundered_command(), read_password());
|
||||
|
||||
exit 0; # command succeeded
|
||||
|
||||
############################################################
|
||||
|
||||
sub usage($) {
|
||||
print STDERR "Error: ", shift, "\n";
|
||||
|
||||
# OK, this eats the -v...
|
||||
print STDERR "Legal commands are:\n\t", join "\n",
|
||||
map { $_ =~ m:(\w+):; $1 } @ALLOWED_COMMANDS;
|
||||
exit 1; # error
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
sub laundered_command() {
|
||||
my $regexp = "^(" . join ( "|", @ALLOWED_COMMANDS ) . ")\$";
|
||||
my $parameters = join " ", @ARGV;
|
||||
$parameters =~ m:$regexp: or usage("Command $parameters not allowed.");
|
||||
|
||||
return $1; # this value, then, is untainted.
|
||||
};
|
||||
|
||||
############################################################
|
||||
|
||||
sub read_password() {
|
||||
open PASS, $PASSWORDFILE
|
||||
or die "Could not read protected password file: $!";
|
||||
my $password = <PASS>;
|
||||
chomp $password;
|
||||
return $password;
|
||||
};
|
||||
|
||||
############################################################
|
||||
|
||||
sub order_chrony($$) {
|
||||
my ($clean_command, $password) = @_;
|
||||
open CHRONY, "| $CHRONY &> /dev/null" or die "could not run $CHRONY: $!\n";
|
||||
print CHRONY "password $password\n";
|
||||
print CHRONY "$clean_command\n";
|
||||
close CHRONY
|
||||
or die "Error running command $clean_command\n", "\ton $CHRONY: $!\n";
|
||||
}
|
||||
|
||||
############################################################
|
||||
289
examples/chrony.conf.example
Normal file
289
examples/chrony.conf.example
Normal file
@@ -0,0 +1,289 @@
|
||||
#######################################################################
|
||||
# $Header: /cvs/src/chrony/examples/chrony.conf.example,v 1.2 2002/02/03 21:46:29 richard Exp $
|
||||
#
|
||||
# This is an example chrony configuration file. You should copy it to
|
||||
# /etc/chrony.conf after uncommenting and editing the options that you
|
||||
# want to enable. I have not included the more obscure options. Refer
|
||||
# to the documentation for these.
|
||||
#
|
||||
# Copyright 2002 Richard P. Curnow
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# 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.,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
#
|
||||
#
|
||||
#######################################################################
|
||||
### COMMENTS
|
||||
# Any of the following lines are comments (you have a choice of
|
||||
# comment start character):
|
||||
# a comment
|
||||
% a comment
|
||||
! a comment
|
||||
; a comment
|
||||
#
|
||||
# Below, the '!' form is used for lines that you might want to
|
||||
# uncomment and edit to make your own chrony.conf file.
|
||||
#
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
### SPECIFY YOUR NTP SERVERS
|
||||
# Most computers using chrony will send measurement requests to one or
|
||||
# more 'NTP servers'. You will probably find that your Internet Service
|
||||
# Provider or company have one or more NTP servers that you can specify.
|
||||
# Failing that, there are a lot of public NTP servers. There is a list
|
||||
# you can access at
|
||||
# http://www.eecis.udel.edu/~mills/ntp/servers.htm.
|
||||
|
||||
! server ntp0.your-isp.com
|
||||
! server ntp1.your-isp.com
|
||||
! server ntp.public-server.org
|
||||
|
||||
# However, for dial-up use you probably want these instead. The word
|
||||
# 'offline' means that the server is not visible at boot time. Use
|
||||
# chronyc's 'online' command to tell chronyd that these servers have
|
||||
# become visible after you go on-line.
|
||||
|
||||
! server ntp0.your-isp.com offline
|
||||
! server ntp1.your-isp.com offline
|
||||
! server ntp.public-server.org offline
|
||||
|
||||
# You may want to specify NTP 'peers' instead. If you run a network
|
||||
# with a lot of computers and want several computers running chrony to
|
||||
# have the 'front-line' interface to the public NTP servers, you can
|
||||
# 'peer' these machines together to increase robustness.
|
||||
|
||||
! peer ntp0.my-company.com
|
||||
|
||||
# There are other options to the 'server' and 'peer' directives that you
|
||||
# might want to use. For example, you can ignore measurements whose
|
||||
# round-trip-time is too large (indicating that the measurement is
|
||||
# probably useless, because you don't know which way the measurement
|
||||
# message got held up.) Consult the full documentation for details.
|
||||
|
||||
#######################################################################
|
||||
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
|
||||
#
|
||||
# To avoid changes being made to your computer's gain/loss compensation
|
||||
# when the measurement history is too erratic, you might want to enable
|
||||
# one of the following lines. The first seems good for dial-up (or
|
||||
# other high-latency connections like slow leased lines), the second
|
||||
# seems OK for a LAN environment.
|
||||
|
||||
! maxupdateskew 100
|
||||
! maxupdateskew 5
|
||||
|
||||
#######################################################################
|
||||
### FILENAMES ETC
|
||||
# Chrony likes to keep information about your computer's clock in files.
|
||||
# The 'driftfile' stores the computer's clock gain/loss rate in parts
|
||||
# per million. When chronyd starts, the system clock can be tuned
|
||||
# immediately so that it doesn't gain or lose any more time. You
|
||||
# generally want this, so it is uncommented.
|
||||
|
||||
driftfile /etc/chrony.drift
|
||||
|
||||
# If you want to use the program called chronyc to configure aspects of
|
||||
# chronyd's operation once it is running (e.g. tell it the Internet link
|
||||
# has gone up or down), you need a password. This is stored in the
|
||||
# following keys file. (You also need keys to support authenticated NTP
|
||||
# exchanges between cooperating machines.) Again, this option is
|
||||
# assumed by default.
|
||||
|
||||
keyfile /etc/chrony.keys
|
||||
|
||||
# Tell chronyd which numbered key in the file is used as the password
|
||||
# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a
|
||||
# default. Using another value will _NOT_ increase security.)
|
||||
|
||||
commandkey 1
|
||||
|
||||
# chronyd can save the measurement history for the servers to files when
|
||||
# it it exits. This is useful in 2 situations:
|
||||
#
|
||||
# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after
|
||||
# an upgrade), the old measurements will still be relevant when chronyd
|
||||
# is restarted. This will reduce the time needed to get accurate
|
||||
# gain/loss measurements, especially with a dial-up link.
|
||||
#
|
||||
# 2. Again on Linux, if you use the RTC support and start chronyd with
|
||||
# '-r -s' on bootup, measurements from the last boot will still be
|
||||
# useful (the real time clock is used to 'flywheel' chronyd between
|
||||
# boots).
|
||||
#
|
||||
# Enable these two options to use this.
|
||||
|
||||
! dumponexit
|
||||
! dumpdir /var/log/chrony
|
||||
|
||||
# chronyd writes its process ID to a file. If you try to start a second
|
||||
# copy of chronyd, it will detect that the process named in the file is
|
||||
# still running and bail out. If you want to change the path to the PID
|
||||
# file, uncomment this line and edit it. The default path is shown.
|
||||
|
||||
! pidfile /var/run/chronyd.pid
|
||||
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is only useful if your NTP servers are visible at boot
|
||||
# time. This probably means you are on a LAN. If so, the following
|
||||
# option will choose the best-looking of the servers and correct the
|
||||
# system time to that. The value '10' means that if the error is less
|
||||
# than 10 seconds, it will be gradually removed by speeding up or
|
||||
# slowing down your computer's clock until it is correct. If the error
|
||||
# is above 10 seconds, an immediate time jump will be applied to correct
|
||||
# it. Some software can get upset if the system clock jumps (especially
|
||||
# backwards), so be careful!
|
||||
|
||||
! initstepslew 10 ntp0.your-company.com ntp1.your-company.com ntp2.your-company.com
|
||||
|
||||
#######################################################################
|
||||
### LOGGING
|
||||
# If you want to log information about the time measurements chronyd has
|
||||
# gathered, you might want to enable the following lines. You probably
|
||||
# only need this if you really enjoy looking at the logs, you want to
|
||||
# produce some graphs of your system's timekeeping performance, or you
|
||||
# need help in debugging a problem.
|
||||
|
||||
! logdir /var/log/chrony
|
||||
! log measurements statistics tracking
|
||||
|
||||
If you have real time clock support enabled (see below), you might want
|
||||
this line instead:
|
||||
|
||||
! log measurements statistics tracking rtc
|
||||
|
||||
#######################################################################
|
||||
### ACTING AS AN NTP SERVER
|
||||
# You might want the computer to be an NTP server for other computers.
|
||||
# e.g. you might be running chronyd on a dial-up machine that has a LAN
|
||||
# sitting behind it with several 'satellite' computers on it.
|
||||
#
|
||||
# By default, chronyd does not allow any clients to access it. You need
|
||||
# to explicitly enable access using 'allow' and 'deny' directives.
|
||||
#
|
||||
# e.g. to enable client access from the 192.168.*.* class B subnet,
|
||||
|
||||
! allow 192.168/16
|
||||
|
||||
# .. but disallow the 192.168.100.* subnet of that,
|
||||
|
||||
! deny 192.168.100/24
|
||||
|
||||
# You can have as many allow and deny directives as you need. The order
|
||||
# is unimportant.
|
||||
|
||||
# If you want chronyd to act as an NTP broadcast server, enable and edit
|
||||
# (and maybe copy) the following line. This means that a broadcast
|
||||
# packet is sent to the address 192.168.1.255 every 60 seconds. The
|
||||
# address MUST correspond to the broadcast address of one of the network
|
||||
# interfaces on your machine. If you have multiple network interfaces,
|
||||
# add a broadcast line for each.
|
||||
|
||||
! broadcast 60 192.168.1.255
|
||||
|
||||
# If you want to present your computer's time for others to synchronise
|
||||
# with, even if you don't seem to be synchronised to any NTP servers
|
||||
# yourself, enable the following line. The value 10 may be varied
|
||||
# between 1 and 15. You should avoid small values because you will look
|
||||
# like a real NTP server. The value 10 means that you appear to be 10
|
||||
# NTP 'hops' away from an authoritative source (atomic clock, GPS
|
||||
# receiver, radio clock etc).
|
||||
|
||||
! local stratum 10
|
||||
|
||||
# Normally, chronyd will keep track of how many times each client
|
||||
# machine accesses it. The information can be accessed by the 'clients'
|
||||
# command of chronyc. You can disable this facility by uncommenting the
|
||||
# following line. This will save a bit of memory if you have many
|
||||
# clients.
|
||||
|
||||
! noclientlog
|
||||
|
||||
#######################################################################
|
||||
### REPORTING BIG CLOCK CHANGES
|
||||
# Perhaps you want to know if chronyd suddenly detects any large error
|
||||
# in your computer's clock. This might indicate a fault or a problem
|
||||
# with the server(s) you are using, for example.
|
||||
#
|
||||
# The next option causes a message to be written to syslog when chronyd
|
||||
# has to correct an error above 0.5 seconds (you can use any amount you
|
||||
# like).
|
||||
|
||||
! logchange 0.5
|
||||
|
||||
# The next option will send email to the named person when chronyd has
|
||||
# to correct an error above 0.5 seconds. (If you need to send mail to
|
||||
# several people, you need to set up a mailing list or sendmail alias
|
||||
# for them and use the address of that.)
|
||||
|
||||
! mailonchange wibble@foobar.org 0.5
|
||||
|
||||
#######################################################################
|
||||
### COMMAND ACCESS
|
||||
# The program chronyc is used to show the current operation of chronyd
|
||||
# and to change parts of its configuration whilst it is running.
|
||||
|
||||
# Normally, chronyd will only allow connections from chronyc on the same
|
||||
# machine as itself. This is for security. If you have a subnet
|
||||
# 192.168.*.* and you want to be able to use chronyc from any machine on
|
||||
# it, you could uncomment the following line. (Edit this to your own
|
||||
# situation.)
|
||||
|
||||
! cmdallow 192.168/16
|
||||
|
||||
# You can add as many 'cmdallow' and 'cmddeny' lines as you like. The
|
||||
# syntax and meaning is the same as for 'allow' and 'deny', except that
|
||||
# 'cmdallow' and 'cmddeny' control access to the chronyd's command port.
|
||||
|
||||
# NOTE, even if the host where you run chronyc is granted access, you
|
||||
# still need a command key set up and you have to know the password to
|
||||
# put into chronyc to allow you to modify chronyd's parameters. By
|
||||
# default all you can do is view information about chronyd's operation.
|
||||
|
||||
# Some people have reported that the need the following line to allow
|
||||
# chronyc to work even on the same machine. This should not be
|
||||
# necessary, and the problem is being investigated. You can leave this
|
||||
# line enabled, as it's benign otherwise.
|
||||
|
||||
cmdallow 127.0.0.1
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME CLOCK
|
||||
# chronyd can characterise the system's real-time clock. This is the
|
||||
# clock that keeps running when the power is turned off, so that the
|
||||
# machine knows the approximate time when it boots again. The error at
|
||||
# a particular epoch and gain/loss rate can be written to a file and
|
||||
# used later by chronyd when it is started with the '-s' option.
|
||||
#
|
||||
# You need to have 'enhanced RTC support' compiled into your Linux
|
||||
# kernel. (Note, these options apply only to Linux.)
|
||||
|
||||
! rtcfile /etc/chrony.rtc
|
||||
|
||||
# Your RTC can be set to keep Universal Coordinated Time (UTC) or local
|
||||
# time. (Local time means UTC +/- the effect of your timezone.) If you
|
||||
# use UTC, chronyd will function correctly even if the computer is off
|
||||
# at the epoch when you enter or leave summer time (aka daylight saving
|
||||
# time). However, if you dual boot your system with Microsoft Windows,
|
||||
# that will work better if your RTC maintains local time. You take your
|
||||
# pick!
|
||||
|
||||
! rtconutc
|
||||
|
||||
# By default chronyd assumes that the enhanced RTC device is accessed as
|
||||
# /dev/rtc. If it's accessed somewhere else on your system (e.g. you're
|
||||
# using devfs), uncomment and edit the following line.
|
||||
|
||||
! rtcdevice /dev/misc/rtc
|
||||
|
||||
#######################################################################
|
||||
27
examples/chrony.keys.example
Normal file
27
examples/chrony.keys.example
Normal file
@@ -0,0 +1,27 @@
|
||||
#######################################################################
|
||||
# $Header: /cvs/src/chrony/examples/chrony.keys.example,v 1.1 2002/01/31 00:00:08 richard Exp $
|
||||
#
|
||||
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
|
||||
# after editing it to set up the key(s) you want to use. In most situations,
|
||||
# you will require a single key (the 'commandkey') so that you can supply a
|
||||
# password to chronyc to enable you to modify chronyd's operation whilst it is
|
||||
# running.
|
||||
#
|
||||
# Copyright 2002 Richard P. Curnow
|
||||
#
|
||||
#######################################################################
|
||||
# A valid key line looks like this
|
||||
|
||||
1 a_key
|
||||
|
||||
# It must consist of an integer, followed by whitespace, followed by a block of
|
||||
# text with no spaces in it. (You cannot put a space in a key). If you wanted
|
||||
# to use the above line as your commandkey (i.e. chronyc password), you would
|
||||
# put the following line into chrony.conf (remove the # from the start):
|
||||
|
||||
# commandkey 1
|
||||
|
||||
# You might want to define more keys if you use the MD5 authentication facility
|
||||
# in the network time protocol to authenticate request/response packets between
|
||||
# trusted clients and servers.
|
||||
|
||||
384
faq.txt
Normal file
384
faq.txt
Normal file
@@ -0,0 +1,384 @@
|
||||
@@PROLOGUE
|
||||
<html>
|
||||
<head>
|
||||
<title>Frequently asked questions</title>
|
||||
<meta name="description" content="Chrony FAQ (frequently asked questions)">
|
||||
<meta name="keywords" content="chrony,network time protocol,NTP,RFC 1305,dial-up connection,real time clock,RTC,Linux,FAQ,frequently asked questns">
|
||||
<?php
|
||||
$root = ".";
|
||||
include "$root/styles.php";
|
||||
?>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php
|
||||
include 'main_banner.php';
|
||||
include 'header.php';
|
||||
?>
|
||||
<?php pretty_h1("Introduction") ?>
|
||||
<p>
|
||||
This is a set of questions and answers to common problems and issues.
|
||||
<p>
|
||||
As I receive more emails about the software, I will add new questions
|
||||
to this page.
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
The author can be reached by email
|
||||
<a href="mailto:rc@rc0.org.uk">
|
||||
</a>
|
||||
<p>
|
||||
<b>PLEASE</b>
|
||||
include the word "chrony" in your subject line if possible (so that my
|
||||
mail reader can keep my mail sorted by topic)!
|
||||
<hr>
|
||||
|
||||
<br clear=all>
|
||||
@@ENDPROLOGUE
|
||||
S: Administrative issues
|
||||
|
||||
Q: Where can I get chrony source code?
|
||||
Via the home page, see below.
|
||||
|
||||
Q: Are there any packaged versions of chrony?
|
||||
I am aware of packages for Debian, Mandrake and Redhat. I am not personally
|
||||
involved with how these are built or distributed.
|
||||
|
||||
Q: Where is the home page?
|
||||
It is currently at <a href="http://chrony.sunsite.dk/">http://chrony.sunsite.dk/</a>.
|
||||
|
||||
Q: Is there a mailing list?
|
||||
Yes, it's currently at chrony-users@sunsite.dk. There is a low-volume
|
||||
list called chrony-announce which is just for announcements of new releases or
|
||||
similar matters of high importance. You can join the lists by sending a
|
||||
message to <a href="mailto:chrony-users-subscribe@sunsite.dk">chrony-users-subscribe@sunsite.dk</a> or
|
||||
<a href="mailto:chrony-announce-subscribe@sunsite.dk">chrony-announce-subscribe@sunsite.dk</a> respectively.
|
||||
|
||||
For those who want to contribute to the development of chrony, there is a
|
||||
developers' mailing list. You can subscribe by sending mail to
|
||||
<a href="mailto:chrony-dev-subscribe@sunsite.dk">chrony-dev-subscribe@sunsite.dk</a>.
|
||||
|
||||
Q: What licence is applied to chrony?
|
||||
Starting from version 1.15, chrony is licensed under the GNU General Public
|
||||
License. Versions prior to 1.15 were licensed under a custom BSD-like
|
||||
license.
|
||||
|
||||
If you want to use parts of chrony in non-free software, you will need to use
|
||||
older versions of the source code. Alternatively, contact me - I may be
|
||||
prepared to licence parts of the source code to suit your purposes. I am quite
|
||||
sympathetic to projects licensed under other free/open-source (but non-GPL)
|
||||
licences, as well as to commercial projects which are of a single-customer
|
||||
"turnkey" nature (as opposed to mass-market "shrink-wrap" or "floating-licence"
|
||||
products).
|
||||
|
||||
S: Chrony compared to other programs
|
||||
Q: How does chrony compare to xntpd?
|
||||
If your computer is permenently connected, or connected for long periods (that
|
||||
is, for the several hours it takes xntpd to settle down), or you need to
|
||||
support hardware reference clocks to your computer, then xntpd will work fine.
|
||||
Apart from not supporting hardware clocks, chrony will work fine too.
|
||||
|
||||
If your computer connects to the 'net for 5 minutes once a day (or something
|
||||
like that), or you turn your (Linux v2.0) computer off when you're not using
|
||||
it, or you want to use NTP on an isolated network with no hardware clocks in
|
||||
sight, chrony will work much better for you.
|
||||
|
||||
The reason I wrote chrony was that I could not get xntpd to do
|
||||
anything sensible on my PC at home, which is connected to the 'net for
|
||||
about 5 minutes once or twice a day, mainly to upload/download email
|
||||
and news. Nowadays it is also turned off for 22-23 hours a day, when
|
||||
not in use. I wanted a program which would :
|
||||
|
||||
- slew the time to correct it when I go online and NTP servers become visible
|
||||
|
||||
- determine the rate at which the computer gains or loses time and use this
|
||||
information to keep it reasonably correct between connects to the 'net. This
|
||||
has to be done using a method that does not care about the intermittent
|
||||
availability of the references or the fact the computer is turned off between
|
||||
groups of measurements..
|
||||
|
||||
- maintain the time across reboots, by working out the error and drift rate of
|
||||
the computer's real-time clock and using this information to set the system
|
||||
clock correctly at boot up. (In the last few months, it became impossible for
|
||||
me to leave my computer powered permanently.)
|
||||
|
||||
Also, when working with isolated networks with no true time references
|
||||
at all, I found xntpd gave me no help with managing the local clock's
|
||||
gain/loss rate on the NTP master node (which I set from my watch). I
|
||||
added some automated support in chrony to deal with this.
|
||||
|
||||
S: Compilation issues
|
||||
Q:How do I apply source patches?
|
||||
Sometimes I release source patches rather than a full version when I need to
|
||||
provide a fix for small problems. Supposing you have chrony-1.X.tar.gz and a
|
||||
source patch chrony-1.X-1.X.1.gz. The steps required are:
|
||||
|
||||
tar xzvf ../chrony-1.X.tar.gz
|
||||
cd chrony-1.X
|
||||
gunzip < ../../chrony-1.X-1.X.1.gz | patch -p1
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
Q:Can I compile chrony with an ANSI-C compiler that is not GCC v2.x?
|
||||
I have had reports that chrony can be compiled with GCC v1.42, by using the
|
||||
following trick when running make
|
||||
|
||||
make CC='gcc -D__FUNCTION__=\"function_not_available\"'
|
||||
|
||||
(this gets around the lack of a __FUNCTION__ macro in GCC v1.)
|
||||
|
||||
The same trick may be enough to allow other compilers to be used.
|
||||
|
||||
Q: I get errors like 'client.c:44: readline/readline.h: file not found'
|
||||
Read the section about 'readline' in the INSTALL file or in chrony.txt. You
|
||||
may need to disable readline support (e.g. if you haven't got readline
|
||||
installed at all, or just don't want it), or specify the location of the
|
||||
readline files (e.g. if you've installed them in a non-standard place).
|
||||
|
||||
Q: I have RedHat 7.3 and can't compile rtc_linux.c (error in spinlock.h)
|
||||
The following solution has been found for this. Enter the following 3 commands
|
||||
(as root):
|
||||
|
||||
cd /usr/include/
|
||||
mv linux linux.rh
|
||||
ln -s /usr/src/linux/include/linux ./linux
|
||||
|
||||
The problem seems to be that RedHat provide their own kernel header files in
|
||||
/usr/include/linux. Besides differing from those used by your current kernel,
|
||||
if you compiled it yourself, they also seem to have been changed in a way that
|
||||
causes a problem compiling chrony. Chrony compiles fine with standard kernel
|
||||
header files.
|
||||
|
||||
There have also been reports that just replacing the file
|
||||
/usr/src/linux/spinlock.h by the equivalent file from a vanilla kernel source
|
||||
tree is sufficient to fix the problem.
|
||||
|
||||
S: Selection of NTP servers
|
||||
Q: I have several computers on a LAN. Should I make one the master, or make them all clients of an external server?
|
||||
I think the best configuration is to make one computer the master, with the
|
||||
others as clients of it. Add a 'local' directive to the master's chrony.conf
|
||||
file. This configuration will be better because
|
||||
|
||||
* the load on the external connection is less
|
||||
* the load on the external NTP server(s) is less
|
||||
* if your external connection goes down, the computers on the LAN will maintain
|
||||
a common time with each other.
|
||||
|
||||
S: Addressing issues
|
||||
Q: I get the following error message : "Could not get IP adress for localhost"
|
||||
Add a line like the following to your /etc/hosts file
|
||||
127.0.0.1 localhost
|
||||
|
||||
Q: I have problems if I put the names of my NTP servers in the chrony.conf file.
|
||||
If you have no connection to the Internet at boot time, chrony won't be able to
|
||||
turn the names into IP addresses when it starts. There seem to be 2 solutions:
|
||||
|
||||
1. Put the numeric IP addresses in the chrony.conf file
|
||||
or
|
||||
2. Put the server->IP address mappings in your /etc/hosts file and ensure that
|
||||
/etc/host.conf reads 'order hosts,bind'.
|
||||
|
||||
The problem is that chronyd (currently) isn't designed in a way that allows
|
||||
hostname->IP address lookups during normal operation. I hope to work on this
|
||||
problem very soon.
|
||||
|
||||
S: My computer is not synchronising.
|
||||
This is the most common problem. There are a number of reasons, see the
|
||||
following questions.
|
||||
|
||||
Q: Behind a firewall?
|
||||
If there is a firewall between you and the NTP server you're trying to use,
|
||||
the packets may be blocked. Try using a tool like etherfind or tcpdump to see
|
||||
if you're getting responses from the server. If you have an external modem,
|
||||
see if the receive light blinks straight after the transmit light (when the
|
||||
link is quiet apart from the NTP traffic.) Try adding 'log measurements' to
|
||||
the chrony.conf file and look in the measurements.log file after chrony has
|
||||
been running for a short period. See if any measurements appear.
|
||||
|
||||
Most people run chronyd on the firewall itself, to avoid all issues of UDP
|
||||
packet forwarding and/or masquerading.
|
||||
|
||||
Q: Do you have a non-permanant (i.e. intermittent) Internet connection?
|
||||
Check that you're using chronyc's 'online' and 'offline' commands
|
||||
appropriately. Again, check in measurements.log to see if you're getting any
|
||||
data back from the server.
|
||||
|
||||
Q: In measurements.log, do the '7' and '8' flag columns always show zero?
|
||||
Do you have a 'local stratum X' directive in the chrony.conf file? If X is
|
||||
lower than the stratum of the server you're trying to use, this situation will
|
||||
arise. You should always make X quite high (e.g. 10) in this directive.
|
||||
|
||||
S: Issues with chronyd
|
||||
|
||||
Q: chronyd crashes after a syslog message "adjtimex failed for set frequency"
|
||||
The usual cause is that the kernel is running with a different value of 'HZ'
|
||||
(the timer interrupt rate) than the value that was found in the kernel header
|
||||
files when chrony was compiled. The chrony.conf file can include options to
|
||||
modify the HZ value (see the discussion of linux_hz and linux_freq_scale in the
|
||||
documentation), however the problem is to find the value of HZ being used.
|
||||
|
||||
At the end of the chrony v1.18 section of the <a href="./download.php">download page</a>
|
||||
you'll find instructions on how to do this.
|
||||
|
||||
This will be fixed in version 1.19, by getting chronyd to auto-detect the
|
||||
kernel's value rather than relying on the compiled-in default.
|
||||
|
||||
S: Issues with chronyc
|
||||
|
||||
Q: I keep getting the error '510 No command access from this host --- Reply not authenticated'.
|
||||
Make sure that the chrony.conf file (on the computer where chronyd is running)
|
||||
has a 'cmdallow' entry for the computer you are running chronyc on. This
|
||||
shouldn't be necessary for localhost, but some people still seem to need an
|
||||
entry like 'cmdallow 127.0.0.1'. (It would be good to understand why problem
|
||||
only affects some people).
|
||||
|
||||
Q: I cannot log in from chronyc to carry out privileged tasks.
|
||||
This is the second most common problem.
|
||||
|
||||
Perhaps your /etc/chrony.keys file is badly formatted. Make sure that the
|
||||
final line has a line feed at the end, otherwise the key on that line will work
|
||||
as though the last character is missing. (Note, this bug was fixed in version
|
||||
1.16.)
|
||||
|
||||
Q: When I enter a command and hit <Return>, chronyc hangs
|
||||
This probably means that chronyc cannot communicate with chronyd.
|
||||
|
||||
Perhaps chronyd is not running. Try using the ps command (e.g. on Linux, 'ps
|
||||
-auxw') to see if it's running. Or try 'netstat -a' and see if the ports
|
||||
123/udp and 323/udp are listening. If chronyd is not running, you may have a
|
||||
problem with the way you are trying to start it (e.g. at boot time).
|
||||
|
||||
Perhaps you have a firewall set up in a way that blocks packets on port
|
||||
323/udp. You need to amend the firewall configuration in this case.
|
||||
|
||||
Q: Is the chronyc<->chronyd protocol documented anywhere?
|
||||
Only by the source code :-) See cmdmon.c (chronyd side) and client.c (chronyc
|
||||
side).
|
||||
|
||||
S: Real-time clock issues.
|
||||
Q: What is the real-time clock (RTC)?
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It works with 1 second resolution. chronyd can monitor the rate at which the
|
||||
real-time clock gains or loses time, and compensate for it when you set the
|
||||
system time from it at the next reboot. See the documentation for details.
|
||||
|
||||
Q: I want to use chronyd's real-time clock support. Must I disable hwclock?
|
||||
The hwclock program is often set-up by default in the boot and shutdown scripts
|
||||
with many Linux installations. If you want to use chronyd's real-time clock
|
||||
support, the important thing is to disable hwclock in the <b>shutdown</b>
|
||||
procedure. If you don't, it will over-write the RTC with a new value, unknown
|
||||
to chronyd. At the next reboot, chronyd will compensate this (wrong) time with
|
||||
its estimate of how far the RTC has drifted whilst the power was off, giving a
|
||||
meaningless initial system time.
|
||||
|
||||
There is no need to remove hwclock from the boot process, as long as chronyd is
|
||||
started after it has run.
|
||||
|
||||
Q: I just keep getting the '513 RTC driver not running' message
|
||||
For the real time clock support to work, you need the following three things:
|
||||
|
||||
* a kernel that is supported (e.g. 2.2 onwards)
|
||||
* enhanced RTC support compiled into the kernel
|
||||
* an 'rtcfile' directive in your chrony.conf file.
|
||||
|
||||
S: Problems with isolated networks.
|
||||
|
||||
Q: When I use the 'settime' command, chronyd crashes.
|
||||
If you enter times that are too far away from the real time, chronyd will
|
||||
think the system clock runs fast or slow by an excessive amount. The required
|
||||
compensation factor will be outside the bounds for the adjtimex() system call.
|
||||
chronyd will crash when it tries to apply such an excessive adjustment.
|
||||
|
||||
S: Microsoft Windows
|
||||
|
||||
Q: Does chrony support Windows?
|
||||
No. The chronyc program (the command-line client used for configuring
|
||||
chronyd while it is running) has been successfully built and run under Cygwin
|
||||
in the past. chronyd is not portable, because part of it is very
|
||||
system-dependent. It needs adapting to work with Windows' equivalent of the
|
||||
adjtimex() call, and it needs to be made to work as an NT service.
|
||||
|
||||
Q: Are there any plans to support Windows?
|
||||
I have no personal plans to do this. I have neither the time nor the
|
||||
Windows programming expertise. Some time ago I did start work on a port which
|
||||
I was developing under Cygwin. Anyone is welcome to pick this work up and
|
||||
contribute it back to the project.
|
||||
|
||||
Q: What alternative NTP clients are there for Windows?
|
||||
Some of the names I've seen mentioned are
|
||||
- Automachron
|
||||
- NetTime (nettime.sourceforge.net)
|
||||
|
||||
S: NTP-specific issues
|
||||
Q: Can chrony be driven from broadcast NTP servers?
|
||||
No. I remember looking at how they worked when I was first writing chrony.
|
||||
Since the 'target market' then was dial-up systems, broadcast packets were not
|
||||
relevant so I didn't bother working out how to deal with the complexities of
|
||||
doing the delay estimation.
|
||||
|
||||
I no longer have root access to a LAN environment to develop and test broadcast
|
||||
server support. Neither have I the time to work on this. I would be very
|
||||
happy to accept a patch from anyone who can develop, test and debug the
|
||||
necessary changes!
|
||||
|
||||
Q: Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
|
||||
Yes. Starting from version 1.17, chrony has this capability.
|
||||
|
||||
Q: Can chrony keep the system clock a fixed offset away from real time?
|
||||
I have not experimented much, but I don't believe this would be possible as
|
||||
the program currently stands.
|
||||
|
||||
Q: What happens if the network connection is dropped without using chronyc's 'offline' command first?
|
||||
In this case chronyd will keep trying to access the server(s) that it thinks
|
||||
are online. Eventually it will decide that they are unreachable and no longer
|
||||
consider itself synchronised to them. If you have other computers on your LAN
|
||||
accessing the computer that is affected this way, they too will become
|
||||
'unsynchronised', unless you have the 'local' directive set up on the master
|
||||
computer.
|
||||
|
||||
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
|
||||
useful to avoid this situation.
|
||||
|
||||
S: Development
|
||||
|
||||
Q: Can I get the source via CVS from anywhere?
|
||||
Yes. See <a href="http://chrony.sunsite.dk/cvs.php">http://chrony.sunsite.dk/cvs.php</a> for information. Currently there is
|
||||
only anonymous read-only access. I keep the master copy on my own PC, which is
|
||||
more convenient for me because I don't have to connect to the Internet to do
|
||||
CVS operations on the files. So for now, there is no read-write access for
|
||||
other developers. Please email me your patches + documentation instead.
|
||||
|
||||
S: Linux-specific issues
|
||||
|
||||
Q: Why does the source code include kernel header files?
|
||||
The program needs to see the definitions of structures used to interact with
|
||||
the real time clock (via /dev/rtc) and with the adjtimex() system call. Sadly
|
||||
this has led to a number of compilation problems with newer kernels which have
|
||||
been increasingly hard to fix in a way that makes the code compilable on all
|
||||
Linux kernel versions (from 2.0 up anyway, I doubt 1.x still works.) Hopefully
|
||||
the situation will not deteriorate further with future kernel versions.
|
||||
|
||||
Q: I get "Could not open /dev/rtc, Device or resource busy" in my syslog file.
|
||||
Check that you haven't accidentally got two copies of chronyd running (perhaps
|
||||
defined in different start-up scripts.)
|
||||
|
||||
S: Solaris-specific issues
|
||||
Q: On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr.
|
||||
(The dosynctodr variable controls whether Solaris couples the equivalent of its
|
||||
BIOS clock into its system clock at regular intervals). The Solaris port of
|
||||
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
|
||||
has changed which prevents the same technique working. I no longer have root
|
||||
access to any Solaris machines to work on this, and am reliant on somebody
|
||||
developing the patch and testing it. A good starting point would be to see if
|
||||
xntpd has been modified to work for Solaris 2.8.
|
||||
|
||||
@@EPILOGUE
|
||||
<hr>
|
||||
|
||||
Back to
|
||||
<a href="mailto:rc@rc0.org.uk?subject=chrony">the author</a>'s
|
||||
<a href="http://www.rc0.org.uk/">main page</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ENDEPILOGUE
|
||||
140
faqgen.pl
Normal file
140
faqgen.pl
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# $Header
|
||||
|
||||
# Copyright 2001 Richard P. Curnow
|
||||
# LICENCE
|
||||
|
||||
# A script to generate an HTML FAQ page from a text input file. The input is assumed to consist of the following:
|
||||
# Lines starting with 'S:'. These introduce sections.
|
||||
# Lines starting with 'Q:'. These are the topics of questions.
|
||||
# Body text (either as an introduction to the sections, or as answers to the questions.
|
||||
# The body text is set as pre-formatted.
|
||||
|
||||
$| = 1;
|
||||
|
||||
@prologue = ();
|
||||
@epilogue = ();
|
||||
|
||||
@sections=(); # section titles
|
||||
@sect_text=(); # introductory text in sections
|
||||
|
||||
@questions=(); # questions in sections
|
||||
@answers=(); # answers to questions
|
||||
|
||||
$sn = -1;
|
||||
$had_q = 0;
|
||||
|
||||
#{{{ Parse input
|
||||
while (<>) {
|
||||
if (m/\@\@PROLOG/o) {
|
||||
while (<>) {
|
||||
last if (m/^\@\@ENDPROLOG/);
|
||||
push (@prologue, $_);
|
||||
}
|
||||
} elsif (m/\@\@EPILOG/o) {
|
||||
while (<>) {
|
||||
last if (m/^\@\@ENDEPILOG/);
|
||||
push (@epilogue, $_);
|
||||
}
|
||||
} elsif (m/^[sS]:[ \t]*(.*)$/) {
|
||||
chomp;
|
||||
$qn = -1;
|
||||
++$sn;
|
||||
$sections[$sn] = &guard($1);
|
||||
$sect_text[$sn] = "";
|
||||
$questions[$sn] = [ ];
|
||||
$answers[$sn] = [ ];
|
||||
$had_q = 0;
|
||||
} elsif (/^[qQ]:[ \t]*(.*)$/) {
|
||||
chomp;
|
||||
die unless ($sn >= 0);
|
||||
++$qn;
|
||||
$questions[$sn]->[$qn] = &guard($1);
|
||||
$had_q = 1;
|
||||
} else {
|
||||
if ($had_q) {
|
||||
if ($qn >= 0) {
|
||||
$answers[$sn]->[$qn] .= $_;
|
||||
}
|
||||
} else {
|
||||
if ($sect_text[$sn] ne "" || $_ !~ /^\s*$/) {
|
||||
$sect_text[$sn] .= $_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#}}}
|
||||
|
||||
# Emit file header
|
||||
if ($#prologue >= 0) {
|
||||
print @prologue;
|
||||
} else {
|
||||
print <<EOF;
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Chrony Frequently Asked Questions
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<font face=\"arial,helvetica\" size=+4><b>Table of contents</b></font>
|
||||
EOF
|
||||
}
|
||||
|
||||
# Emit table of contents
|
||||
print "<ul>\n";
|
||||
for $sn (0 .. $#sections) {
|
||||
print "<b><li> <a href=\"#section_".($sn+1)."\">".($sn+1).".</a> ".$sections[$sn]."</b>\n";
|
||||
print " <ul>\n";
|
||||
for $qn (0 .. $#{$questions[$sn]}) {
|
||||
$sq = ($sn+1).".".($qn+1);
|
||||
print " <li> <a href=\"#question_".$sq."\">".$sq.".</a> ".$questions[$sn]->[$qn]."\n";
|
||||
#print " <li> ".$sq.". ".$questions[$sn]->[$qn]."\n";
|
||||
}
|
||||
print " </ul>\n";
|
||||
}
|
||||
print "</ul>\n";
|
||||
|
||||
# Emit main sections
|
||||
for $sn (0 .. $#sections) {
|
||||
print "<hr>\n";
|
||||
print "<a name=section_".($sn+1).">\n";
|
||||
#print "<b><font size=+2 face=\"arial,helvetica\">".($sn+1).". ".$sections[$sn]."</font></b>\n";
|
||||
print "<?php pretty_h2(\"".($sn+1).". ".$sections[$sn]."\"); ?>\n";
|
||||
if ($sect_text[$sn] ne "") {
|
||||
print "<pre>\n";
|
||||
print $sect_text[$sn];
|
||||
print "</pre>\n";
|
||||
}
|
||||
for $qn (0 .. $#{$questions[$sn]}) {
|
||||
$sq = ($sn+1).".".($qn+1);
|
||||
print "<p>\n";
|
||||
print "<a name=question_".$sq.">\n";
|
||||
print "<font size=+1 face=\"arial,helvetica\">".$sq.". ".$questions[$sn]->[$qn]."</font>\n";
|
||||
print "<pre>\n";
|
||||
print $answers[$sn]->[$qn];
|
||||
print "</pre>\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Print footer
|
||||
if ($#epilogue >= 0) {
|
||||
print @epilogue;
|
||||
} else {
|
||||
print <<EOF;
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
#{{{ sub guard {
|
||||
sub guard {
|
||||
# Hide wierd tags etc
|
||||
my ($x) = @_;
|
||||
return $x;
|
||||
}
|
||||
#}}}
|
||||
|
||||
|
||||
28
getdate.h
Normal file
28
getdate.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Modified from the original to add stdlib.h and string.h */
|
||||
|
||||
#ifndef GOT_GETDATE_H
|
||||
#define GOT_GETDATE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
time_t get_date (const char *p, const time_t *now);
|
||||
|
||||
#endif /* GOT_GETDATE_H */
|
||||
243
keys.c
Normal file
243
keys.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/keys.c,v 1.11 2003/01/20 22:52:07 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Module for managing keys used for authenticating NTP packets and commands
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "keys.h"
|
||||
#include "conf.h"
|
||||
#include "memory.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned long id;
|
||||
char *val;
|
||||
int len;
|
||||
} Key;
|
||||
|
||||
#define MAX_KEYS 256
|
||||
|
||||
static int n_keys;
|
||||
static Key keys[MAX_KEYS];
|
||||
|
||||
static int command_key_valid;
|
||||
static int command_key_pos;
|
||||
static int cache_valid;
|
||||
static unsigned long cache_key_id;
|
||||
static int cache_key_pos;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
KEY_Initialise(void)
|
||||
{
|
||||
n_keys = 0;
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
KEY_Reload();
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
KEY_Finalise(void)
|
||||
{
|
||||
/* Nothing to do */
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Compare two keys */
|
||||
|
||||
static int
|
||||
compare_keys_by_id(const void *a, const void *b)
|
||||
{
|
||||
const Key *c = (const Key *) a;
|
||||
const Key *d = (const Key *) b;
|
||||
|
||||
if (c->id < d->id) {
|
||||
return -1;
|
||||
} else if (c->id > d->id) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
#define KEYLEN 2047
|
||||
#define SKEYLEN "2047"
|
||||
|
||||
void
|
||||
KEY_Reload(void)
|
||||
{
|
||||
int i, len1;
|
||||
char *key_file;
|
||||
FILE *in;
|
||||
unsigned long key_id;
|
||||
char line[KEYLEN+1], keyval[KEYLEN+1];
|
||||
|
||||
for (i=0; i<n_keys; i++) {
|
||||
Free(keys[i].val);
|
||||
}
|
||||
|
||||
n_keys = 0;
|
||||
|
||||
key_file = CNF_GetKeysFile();
|
||||
|
||||
if (key_file) {
|
||||
in = fopen(key_file, "r");
|
||||
if (in) {
|
||||
while (fgets(line, sizeof(line), in)) {
|
||||
len1 = strlen(line) - 1;
|
||||
|
||||
/* Guard against removing last character of the line
|
||||
* if the last line of the file is missing an end-of-line */
|
||||
if (line[len1] == '\n') {
|
||||
line[len1] = '\0';
|
||||
}
|
||||
|
||||
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
|
||||
keys[n_keys].id = key_id;
|
||||
keys[n_keys].len = strlen(keyval);
|
||||
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
|
||||
strcpy(keys[n_keys].val, keyval);
|
||||
n_keys++;
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
|
||||
/* Sort keys into order. Note, if there's a duplicate, it is
|
||||
arbitrary which one we use later - the user should have been
|
||||
more careful! */
|
||||
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
lookup_key(unsigned long id)
|
||||
{
|
||||
Key specimen, *where;
|
||||
int pos;
|
||||
|
||||
specimen.id = id;
|
||||
where = (Key *) bsearch((void *)&specimen, (void *)keys, n_keys, sizeof(Key), compare_keys_by_id);
|
||||
if (!where) {
|
||||
return -1;
|
||||
} else {
|
||||
pos = where - keys;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
KEY_CommandKey(char **key, int *len)
|
||||
{
|
||||
unsigned long command_key_id;
|
||||
|
||||
if (!command_key_valid) {
|
||||
command_key_id = CNF_GetCommandKey();
|
||||
command_key_pos = lookup_key(command_key_id);
|
||||
command_key_valid = 1;
|
||||
}
|
||||
|
||||
if (command_key_pos >= 0) {
|
||||
*key = keys[command_key_pos].val;
|
||||
*len = keys[command_key_pos].len;
|
||||
} else {
|
||||
*key = "";
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetKey(unsigned long key_id, char **key, int *len)
|
||||
{
|
||||
if (!cache_valid || key_id != cache_key_id) {
|
||||
cache_valid = 1;
|
||||
cache_key_pos = lookup_key(key_id);
|
||||
cache_key_id = key_id;
|
||||
}
|
||||
|
||||
if (cache_key_pos >= 0) {
|
||||
*key = keys[cache_key_pos].val;
|
||||
*len = keys[cache_key_pos].len;
|
||||
return 1;
|
||||
} else {
|
||||
*key = "";
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_KeyKnown(unsigned long key_id)
|
||||
{
|
||||
int position;
|
||||
|
||||
if (cache_valid && (key_id == cache_key_id)) {
|
||||
return 1;
|
||||
} else {
|
||||
|
||||
position = lookup_key(key_id);
|
||||
|
||||
if (position >= 0) {
|
||||
/* Store key in cache, we will probably be using it in a
|
||||
minute... */
|
||||
cache_valid = 1;
|
||||
cache_key_pos = position;
|
||||
cache_key_id = key_id;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
keys.h
Normal file
44
keys.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/keys.h,v 1.8 2002/02/28 23:27:10 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header for key management module
|
||||
*/
|
||||
|
||||
#ifndef GOT_KEYS_H
|
||||
#define GOT_KEYS_H
|
||||
|
||||
extern void KEY_Initialise(void);
|
||||
extern void KEY_Finalise(void);
|
||||
|
||||
extern void KEY_Reload(void);
|
||||
|
||||
extern void KEY_CommandKey(char **key, int *len);
|
||||
|
||||
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
|
||||
extern int KEY_KeyKnown(unsigned long key_id);
|
||||
|
||||
#endif /* GOT_KEYS_H */
|
||||
574
local.c
Normal file
574
local.c
Normal file
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/local.c,v 1.20 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
The routines in this file present a common local (system) clock
|
||||
interface to the rest of the software.
|
||||
|
||||
They interface with the system specific driver files in sys_*.c
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "local.h"
|
||||
#include "localp.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Variable to store the current frequency, in ppm */
|
||||
static double current_freq_ppm;
|
||||
|
||||
/* ================================================== */
|
||||
/* Store the system dependent drivers */
|
||||
|
||||
static lcl_ReadFrequencyDriver drv_read_freq;
|
||||
static lcl_SetFrequencyDriver drv_set_freq;
|
||||
static lcl_AccrueOffsetDriver drv_accrue_offset;
|
||||
static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
|
||||
static lcl_OffsetCorrectionDriver drv_offset_convert;
|
||||
static lcl_ImmediateStepDriver drv_immediate_step;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Types and variables associated with handling the parameter change
|
||||
list */
|
||||
|
||||
typedef struct _ChangeListEntry {
|
||||
struct _ChangeListEntry *next;
|
||||
struct _ChangeListEntry *prev;
|
||||
LCL_ParameterChangeHandler handler;
|
||||
void *anything;
|
||||
} ChangeListEntry;
|
||||
|
||||
static ChangeListEntry change_list;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Types and variables associated with handling the parameter change
|
||||
list */
|
||||
|
||||
typedef struct _DispersionNotifyListEntry {
|
||||
struct _DispersionNotifyListEntry *next;
|
||||
struct _DispersionNotifyListEntry *prev;
|
||||
LCL_DispersionNotifyHandler handler;
|
||||
void *anything;
|
||||
} DispersionNotifyListEntry;
|
||||
|
||||
static DispersionNotifyListEntry dispersion_notify_list;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int precision_log;
|
||||
static double precision_quantum;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Define the number of increments of the system clock that we want
|
||||
to see to be fairly sure that we've got something approaching
|
||||
the minimum increment. Even on a crummy implementation that can't
|
||||
interpolate between 10ms ticks, we should get this done in
|
||||
under 1s of busy waiting. */
|
||||
#define NITERS 100
|
||||
|
||||
static void
|
||||
calculate_sys_precision(void)
|
||||
{
|
||||
struct timeval tv, old_tv, first_tv;
|
||||
struct timezone tz;
|
||||
int dusec, best_dusec;
|
||||
int iters;
|
||||
|
||||
gettimeofday(&old_tv, &tz);
|
||||
first_tv = old_tv;
|
||||
best_dusec = 1000000; /* Assume we must be better than a second */
|
||||
iters = 0;
|
||||
do {
|
||||
gettimeofday(&tv, &tz);
|
||||
dusec = 1000000*(tv.tv_sec - old_tv.tv_sec) + (tv.tv_usec - old_tv.tv_usec);
|
||||
old_tv = tv;
|
||||
if (dusec > 0) {
|
||||
if (dusec < best_dusec) {
|
||||
best_dusec = dusec;
|
||||
}
|
||||
iters++;
|
||||
}
|
||||
} while (iters < NITERS);
|
||||
if (!(best_dusec > 0)) {
|
||||
CROAK("best_dusec should be positive");
|
||||
}
|
||||
precision_log = 0;
|
||||
while (best_dusec < 500000) {
|
||||
precision_log--;
|
||||
best_dusec *= 2;
|
||||
}
|
||||
|
||||
precision_quantum = 1.0 / (double)(1<<(-precision_log));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_Initialise(void)
|
||||
{
|
||||
change_list.next = change_list.prev = &change_list;
|
||||
|
||||
dispersion_notify_list.next = dispersion_notify_list.prev = &dispersion_notify_list;
|
||||
|
||||
/* Null out the system drivers, so that we die
|
||||
if they never get defined before use */
|
||||
|
||||
drv_read_freq = NULL;
|
||||
drv_set_freq = NULL;
|
||||
drv_accrue_offset = NULL;
|
||||
drv_offset_convert = NULL;
|
||||
|
||||
/* This ought to be set from the system driver layer */
|
||||
current_freq_ppm = 0.0;
|
||||
|
||||
calculate_sys_precision();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_Finalise(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Routine to read the system precision as a log to base 2 value. */
|
||||
int
|
||||
LCL_GetSysPrecisionAsLog(void)
|
||||
{
|
||||
return precision_log;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Routine to read the system precision in terms of the actual time step */
|
||||
|
||||
double
|
||||
LCL_GetSysPrecisionAsQuantum(void)
|
||||
{
|
||||
return precision_quantum;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
|
||||
{
|
||||
ChangeListEntry *ptr, *new_entry;
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
CROAK("a handler is already registered");
|
||||
}
|
||||
}
|
||||
|
||||
new_entry = MallocNew(ChangeListEntry);
|
||||
|
||||
new_entry->handler = handler;
|
||||
new_entry->anything = anything;
|
||||
|
||||
/* Chain it into the list */
|
||||
new_entry->next = &change_list;
|
||||
new_entry->prev = change_list.prev;
|
||||
change_list.prev->next = new_entry;
|
||||
change_list.prev = new_entry;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Remove a handler */
|
||||
extern
|
||||
void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything)
|
||||
{
|
||||
|
||||
ChangeListEntry *ptr;
|
||||
int ok;
|
||||
|
||||
ptr = NULL;
|
||||
ok = 0;
|
||||
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
if (ptr->handler == handler && ptr->anything == anything) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
CROAK("did not find a matching handler");
|
||||
}
|
||||
|
||||
/* Unlink entry from the list */
|
||||
ptr->next->prev = ptr->prev;
|
||||
ptr->prev->next = ptr->next;
|
||||
|
||||
free(ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything)
|
||||
{
|
||||
DispersionNotifyListEntry *ptr, *new_entry;
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
CROAK("a handler is already registered");
|
||||
}
|
||||
}
|
||||
|
||||
new_entry = MallocNew(DispersionNotifyListEntry);
|
||||
|
||||
new_entry->handler = handler;
|
||||
new_entry->anything = anything;
|
||||
|
||||
/* Chain it into the list */
|
||||
new_entry->next = &dispersion_notify_list;
|
||||
new_entry->prev = dispersion_notify_list.prev;
|
||||
dispersion_notify_list.prev->next = new_entry;
|
||||
dispersion_notify_list.prev = new_entry;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Remove a handler */
|
||||
extern
|
||||
void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything)
|
||||
{
|
||||
|
||||
DispersionNotifyListEntry *ptr;
|
||||
int ok;
|
||||
|
||||
ptr = NULL;
|
||||
ok = 0;
|
||||
|
||||
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
|
||||
if (ptr->handler == handler && ptr->anything == anything) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
CROAK("no matching handler found");
|
||||
}
|
||||
|
||||
/* Unlink entry from the list */
|
||||
ptr->next->prev = ptr->prev;
|
||||
ptr->prev->next = ptr->next;
|
||||
|
||||
free(ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* At the moment, this is just gettimeofday(), because
|
||||
I can't think of a Unix system where it would not be */
|
||||
|
||||
void
|
||||
LCL_ReadRawTime(struct timeval *result)
|
||||
{
|
||||
struct timezone tz;
|
||||
|
||||
if (!(gettimeofday(result, &tz) >= 0)) {
|
||||
CROAK("Could not get time of day");
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_ReadCookedTime(struct timeval *result, double *err)
|
||||
{
|
||||
struct timeval raw;
|
||||
double correction;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
|
||||
/* For now, cheat and set the error to zero in all cases.
|
||||
*/
|
||||
|
||||
*err = 0.0;
|
||||
|
||||
/* Call system specific driver to get correction */
|
||||
(*drv_offset_convert)(&raw, &correction);
|
||||
UTI_AddDoubleToTimeval(&raw, correction, result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
LCL_GetOffsetCorrection(struct timeval *raw)
|
||||
{
|
||||
double correction;
|
||||
(*drv_offset_convert)(raw, &correction);
|
||||
return correction;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This is just a simple passthrough of the system specific routine */
|
||||
|
||||
double
|
||||
LCL_ReadAbsoluteFrequency(void)
|
||||
{
|
||||
return (*drv_read_freq)();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This involves both setting the absolute frequency with the
|
||||
system-specific driver, as well as calling all notify handlers */
|
||||
|
||||
void
|
||||
LCL_SetAbsoluteFrequency(double afreq_ppm)
|
||||
{
|
||||
ChangeListEntry *ptr;
|
||||
struct timeval raw, cooked;
|
||||
double correction;
|
||||
double dfreq;
|
||||
|
||||
/* Call the system-specific driver for setting the frequency */
|
||||
|
||||
(*drv_set_freq)(afreq_ppm);
|
||||
|
||||
dfreq = 1.0e-6 * (afreq_ppm - current_freq_ppm) / (1.0 - 1.0e-6 * current_freq_ppm);
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
(drv_offset_convert)(&raw, &correction);
|
||||
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
(ptr->handler)(&raw, &cooked, dfreq, afreq_ppm, 0.0, 0, ptr->anything);
|
||||
}
|
||||
|
||||
current_freq_ppm = afreq_ppm;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateDeltaFrequency(double dfreq)
|
||||
{
|
||||
ChangeListEntry *ptr;
|
||||
struct timeval raw, cooked;
|
||||
double correction;
|
||||
|
||||
/* Work out new absolute frequency. Note that absolute frequencies
|
||||
are handled in units of ppm, whereas the 'dfreq' argument is in
|
||||
terms of the gradient of the (offset) v (local time) function. */
|
||||
|
||||
current_freq_ppm = (1.0 - dfreq) * current_freq_ppm +
|
||||
(1.0e6 * dfreq);
|
||||
|
||||
/* Call the system-specific driver for setting the frequency */
|
||||
(*drv_set_freq)(current_freq_ppm);
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
(drv_offset_convert)(&raw, &correction);
|
||||
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
(ptr->handler)(&raw, &cooked, dfreq, current_freq_ppm, 0.0, 0, ptr->anything);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateOffset(double offset)
|
||||
{
|
||||
ChangeListEntry *ptr;
|
||||
struct timeval raw, cooked;
|
||||
double correction;
|
||||
|
||||
/* In this case, the cooked time to be passed to the notify clients
|
||||
has to be the cooked time BEFORE the change was made */
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
(drv_offset_convert)(&raw, &correction);
|
||||
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
|
||||
|
||||
(*drv_accrue_offset)(offset);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
(ptr->handler)(&raw, &cooked, 0.0, current_freq_ppm, offset, 0, ptr->anything);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_ApplyStepOffset(double offset)
|
||||
{
|
||||
ChangeListEntry *ptr;
|
||||
struct timeval raw, cooked;
|
||||
double correction;
|
||||
|
||||
/* In this case, the cooked time to be passed to the notify clients
|
||||
has to be the cooked time BEFORE the change was made */
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
(drv_offset_convert)(&raw, &correction);
|
||||
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
|
||||
|
||||
(*drv_apply_step_offset)(offset);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
(ptr->handler)(&raw, &cooked, 0.0, current_freq_ppm, offset, 1, ptr->anything);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
|
||||
{
|
||||
ChangeListEntry *ptr;
|
||||
struct timeval raw, cooked;
|
||||
double correction;
|
||||
double old_freq_ppm;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
(drv_offset_convert)(&raw, &correction);
|
||||
/* Due to modifying the offset, this has to be the cooked time prior
|
||||
to the change we are about to make */
|
||||
UTI_AddDoubleToTimeval(&raw, correction, &cooked);
|
||||
|
||||
old_freq_ppm = current_freq_ppm;
|
||||
|
||||
/* Work out new absolute frequency. Note that absolute frequencies
|
||||
are handled in units of ppm, whereas the 'dfreq' argument is in
|
||||
terms of the gradient of the (offset) v (local time) function. */
|
||||
current_freq_ppm = (1.0 - dfreq) * old_freq_ppm +
|
||||
(1.0e6 * dfreq);
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
|
||||
old_freq_ppm, current_freq_ppm, doffset);
|
||||
#endif
|
||||
|
||||
/* Call the system-specific driver for setting the frequency */
|
||||
(*drv_set_freq)(current_freq_ppm);
|
||||
(*drv_accrue_offset)(doffset);
|
||||
|
||||
/* Dispatch to all handlers */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
(ptr->handler)(&raw, &cooked, dfreq, current_freq_ppm, doffset, 0, ptr->anything);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
lcl_InvokeDispersionNotifyHandlers(double dispersion)
|
||||
{
|
||||
DispersionNotifyListEntry *ptr;
|
||||
|
||||
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
|
||||
(ptr->handler)(dispersion, ptr->anything);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
|
||||
lcl_SetFrequencyDriver set_freq,
|
||||
lcl_AccrueOffsetDriver accrue_offset,
|
||||
lcl_ApplyStepOffsetDriver apply_step_offset,
|
||||
lcl_OffsetCorrectionDriver offset_convert,
|
||||
lcl_ImmediateStepDriver immediate_step)
|
||||
{
|
||||
drv_read_freq = read_freq;
|
||||
drv_set_freq = set_freq;
|
||||
drv_accrue_offset = accrue_offset;
|
||||
drv_apply_step_offset = apply_step_offset;
|
||||
drv_offset_convert = offset_convert;
|
||||
drv_immediate_step = immediate_step;
|
||||
|
||||
current_freq_ppm = (*drv_read_freq)();
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Look at the current difference between the system time and the NTP
|
||||
time, and make a step to cancel it. */
|
||||
|
||||
int
|
||||
LCL_MakeStep(void)
|
||||
{
|
||||
if (drv_immediate_step) {
|
||||
(drv_immediate_step)();
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Local, "Made step to system time to apply remaining slew");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
184
local.h
Normal file
184
local.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/local.h,v 1.16 2002/02/28 23:27:10 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module provides an interface to the system time, and
|
||||
insulates the rest of the program from the different way
|
||||
that interface has to be done on various operating systems.
|
||||
*/
|
||||
|
||||
#ifndef GOT_LOCAL_H
|
||||
#define GOT_LOCAL_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
/* Read the system clock. This is analogous to gettimeofday(),
|
||||
but with the timezone information ignored */
|
||||
extern void LCL_ReadRawTime(struct timeval *);
|
||||
|
||||
/* Read the system clock, corrected according to all accumulated
|
||||
drifts and uncompensated offsets.
|
||||
|
||||
In a kernel implementation with vernier frequency control (like
|
||||
Linux), and if we were to apply offsets by stepping the clock, this
|
||||
would be identical to raw time. In any other case (use of
|
||||
adjtime()-like interface to correct offsets, and to adjust the
|
||||
frequency), we must correct the raw time to get this value */
|
||||
|
||||
extern void LCL_ReadCookedTime(struct timeval *t, double *err);
|
||||
|
||||
/* Read the current offset between the system clock and true time
|
||||
(i.e. 'cooked' - 'raw') (in seconds). Only intended for use in
|
||||
status reporting, really. */
|
||||
|
||||
extern double LCL_GetOffsetCorrection(struct timeval *raw);
|
||||
|
||||
/* Type of routines that may be invoked as callbacks when there is a
|
||||
change to the frequency or offset.
|
||||
|
||||
raw : raw local clock time at which change occurred
|
||||
|
||||
cooked : cooked local time at which change occurred
|
||||
|
||||
dfreq : delta frequency relative to previous value (in terms of
|
||||
seconds gained by system clock per unit system clock time)
|
||||
|
||||
afreq : absolute frequency relative to uncompensated system (in
|
||||
terms of ppm seconds gained by system clock per unit of the
|
||||
uncalibrated system clock)
|
||||
|
||||
doffset : delta offset applied (positive => make local system fast
|
||||
by that amount, negative => make it slow by that amount)
|
||||
|
||||
is_step_change : true if change is being applied as a jump (using
|
||||
settimeofday rather than adjtime)
|
||||
|
||||
anything : Passthrough argument from call to registration routine */
|
||||
|
||||
|
||||
typedef void (*LCL_ParameterChangeHandler)
|
||||
(struct timeval *raw, struct timeval *cooked,
|
||||
double dfreq, double afreq_ppm,
|
||||
double doffset, int is_step_change,
|
||||
void *anything
|
||||
);
|
||||
|
||||
/* Add a handler. Then handler MUST NOT deregister itself!!! */
|
||||
extern void LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything);
|
||||
|
||||
/* Remove a handler */
|
||||
extern void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler, void *anything);
|
||||
|
||||
/* Function type for handlers to be called back when an indeterminate
|
||||
offset is introduced into the local time. This situation occurs
|
||||
when the frequency must be adjusted to effect a clock slew and
|
||||
there is doubt about one of the endpoints of the interval over
|
||||
which the frequency change was applied.It is expected that such
|
||||
handlers will add extra dispersion to any existing samples stored
|
||||
in their registers.
|
||||
|
||||
dispersion : The bound on how much error has been introduced in the
|
||||
local clock, in seconds.
|
||||
|
||||
anything : passthrough from the registration routine
|
||||
|
||||
*/
|
||||
|
||||
typedef void (*LCL_DispersionNotifyHandler)(double dispersion, void *anything);
|
||||
|
||||
/* Register a handler for being notified of dispersion being added to
|
||||
the local clock. The handler MUST NOT unregister itself!!! */
|
||||
|
||||
extern void LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything);
|
||||
|
||||
/* Delete a handler */
|
||||
|
||||
extern void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anything);
|
||||
|
||||
|
||||
/* Read the absolute system frequency, relative to the uncompensated
|
||||
system. Returned in units of parts per million. Thus the result of
|
||||
this is how many seconds fast the uncompensated system would be after
|
||||
its own time has reached 1 million seconds from the start of the
|
||||
measurement. */
|
||||
extern double LCL_ReadAbsoluteFrequency(void);
|
||||
|
||||
/* Routine to set the absolute frequency. Only expected to be used
|
||||
when either (i) reading the drift from a file at the start of a
|
||||
run, or (ii) responsing to a user parameter 'poke'. This is
|
||||
defined in ppm, as for the absolute frequency reading routine. */
|
||||
|
||||
extern void LCL_SetAbsoluteFrequency(double afreq);
|
||||
|
||||
/* Routine to apply a change of frequency to the local clock. The
|
||||
argument is the estimated gain (positive) or loss (negative) of the
|
||||
local clock relative to true time, per unit time of the PREVIOUS
|
||||
frequency setting of the local clock. This is assumed to be based
|
||||
on a regression of y=offset v x=cooked local time. */
|
||||
|
||||
extern void LCL_AccumulateDeltaFrequency(double dfreq);
|
||||
|
||||
/* Routine to apply an offset (in seconds) to the local clock. The
|
||||
argument should be positive to move the clock backwards (i.e. the
|
||||
local clock is currently fast of true time), or negative to move it
|
||||
forwards (i.e. it is currently slow of true time). */
|
||||
|
||||
extern void LCL_AccumulateOffset(double offset);
|
||||
|
||||
/* Routine to apply an immediate offset by doing a sudden step if
|
||||
possible. (Intended for use after an initial estimate of offset has
|
||||
been obtained, so that we don't end up using adjtime to achieve a
|
||||
slew of an hour or something like that). A positive argument means
|
||||
the system clock is fast on true time, i.e. it needs to be stepped
|
||||
backwards. (Same convention as for AccumulateOffset routine). */
|
||||
|
||||
extern void LCL_ApplyStepOffset(double offset);
|
||||
|
||||
/* Perform the combination of modifying the frequency and applying
|
||||
a slew, in one easy step */
|
||||
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
|
||||
|
||||
/* Routine to read the system precision as a log to base 2 value. */
|
||||
extern int LCL_GetSysPrecisionAsLog(void);
|
||||
|
||||
/* Routine to read the system precision in terms of the actual time step */
|
||||
extern double LCL_GetSysPrecisionAsQuantum(void);
|
||||
|
||||
/* Routine to initialise the module (to be called once at program
|
||||
start-up) */
|
||||
|
||||
extern void LCL_Initialise(void);
|
||||
|
||||
/* Routine to finalise the module (to be called once at end of
|
||||
run). */
|
||||
extern void LCL_Finalise(void);
|
||||
|
||||
/* Routine to convert the outstanding system clock error to a step and
|
||||
apply it, e.g. if the system clock has ended up an hour wrong due
|
||||
to a timezone problem. */
|
||||
extern int LCL_MakeStep(void);
|
||||
|
||||
#endif /* GOT_LOCAL_H */
|
||||
73
localp.h
Normal file
73
localp.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/localp.h,v 1.9 2002/02/28 23:27:10 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Private include file for local.c and all system dependent
|
||||
driver modules.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GOT_LOCALP_H
|
||||
#define GOT_LOCALP_H
|
||||
|
||||
/* System driver to read the current local frequency, in ppm relative
|
||||
to nominal. A positive value indicates that the local clock runs
|
||||
fast when uncompensated. */
|
||||
typedef double (*lcl_ReadFrequencyDriver)(void);
|
||||
|
||||
/* System driver to set the current local frequency, in ppm relative
|
||||
to nominal. A positive value indicates that the local clock runs
|
||||
fast when uncompensated. */
|
||||
typedef void (*lcl_SetFrequencyDriver)(double freq_ppm);
|
||||
|
||||
/* System driver to accrue an offset. A positive argument means slew
|
||||
the clock forwards. */
|
||||
typedef void (*lcl_AccrueOffsetDriver)(double offset);
|
||||
|
||||
/* System driver to apply a step offset. A positive argument means step
|
||||
the clock forwards. */
|
||||
typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
|
||||
|
||||
/* System driver to convert a raw time to an adjusted (cooked) time.
|
||||
The number of seconds returned in 'corr' have to be added to the
|
||||
raw time to get the corrected time */
|
||||
typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr);
|
||||
|
||||
/* System driver to stop slewing the current offset and to apply is
|
||||
as an immediate step instead */
|
||||
typedef void (*lcl_ImmediateStepDriver)(void);
|
||||
|
||||
extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
|
||||
|
||||
extern void
|
||||
lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
|
||||
lcl_SetFrequencyDriver set_freq,
|
||||
lcl_AccrueOffsetDriver accrue_offset,
|
||||
lcl_ApplyStepOffsetDriver apply_step_offset,
|
||||
lcl_OffsetCorrectionDriver offset_convert,
|
||||
lcl_ImmediateStepDriver immediate_step_driver);
|
||||
|
||||
#endif /* GOT_LOCALP_H */
|
||||
216
logging.c
Normal file
216
logging.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/logging.c,v 1.13 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Module to handle logging of diagnostic information
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "logging.h"
|
||||
#include "version.h"
|
||||
|
||||
/* ================================================== */
|
||||
/* Flag indicating we have initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
static int is_detached = 0;
|
||||
|
||||
#ifdef WINNT
|
||||
static FILE *logfile;
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
/* Init function */
|
||||
|
||||
void
|
||||
LOG_Initialise(void)
|
||||
{
|
||||
initialised = 1;
|
||||
|
||||
#ifdef WINNT
|
||||
logfile = fopen("./chronyd.err", "a");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Fini function */
|
||||
|
||||
void
|
||||
LOG_Finalise(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
}
|
||||
#else
|
||||
if (is_detached) {
|
||||
closelog();
|
||||
}
|
||||
#endif
|
||||
|
||||
initialised = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *format, ...)
|
||||
{
|
||||
char buf[2048];
|
||||
va_list other_args;
|
||||
va_start(other_args, format);
|
||||
vsprintf(buf, format, other_args);
|
||||
va_end(other_args);
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s\n", buf);
|
||||
}
|
||||
#else
|
||||
if (is_detached) {
|
||||
switch (severity) {
|
||||
case LOGS_INFO:
|
||||
syslog(LOG_INFO, "%s", buf);
|
||||
break;
|
||||
case LOGS_WARN:
|
||||
syslog(LOG_WARNING, "%s", buf);
|
||||
break;
|
||||
case LOGS_ERR:
|
||||
default:
|
||||
syslog(LOG_ERR, "%s", buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
volatile void
|
||||
LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
|
||||
{
|
||||
char buf[2048];
|
||||
va_list other_args;
|
||||
va_start(other_args, format);
|
||||
vsprintf(buf, format, other_args);
|
||||
va_end(other_args);
|
||||
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fprintf(logfile, "Fatal error : %s\n", buf);
|
||||
}
|
||||
#else
|
||||
if (is_detached) {
|
||||
syslog(LOG_CRIT, "Fatal error : %s", buf);
|
||||
} else {
|
||||
fprintf(stderr, "Fatal error : %s\n", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
MAI_CleanupAndExit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_Position(const char *filename, int line_number, const char *function_name)
|
||||
{
|
||||
#ifdef WINNT
|
||||
#else
|
||||
time_t t;
|
||||
struct tm stm;
|
||||
char buf[64];
|
||||
if (!is_detached) {
|
||||
/* Don't clutter up syslog with internal debugging info */
|
||||
time(&t);
|
||||
stm = *gmtime(&t);
|
||||
strftime(buf, sizeof(buf), "%d-%H:%M:%S", &stm);
|
||||
fprintf(stderr, "%s:%d:(%s)[%s] ", filename, line_number, function_name, buf);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_GoDaemon(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int pid, fd;
|
||||
|
||||
/* Does this preserve existing signal handlers? */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
||||
} else if (pid > 0) {
|
||||
exit(0); /* In the 'grandparent' */
|
||||
} else {
|
||||
|
||||
setsid();
|
||||
|
||||
/* Do 2nd fork, as-per recommended practice for launching daemons. */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
|
||||
} else if (pid > 0) {
|
||||
exit(0); /* In the 'parent' */
|
||||
} else {
|
||||
/* In the child we want to leave running as the daemon */
|
||||
|
||||
/* Don't keep stdin/out/err from before. */
|
||||
for (fd=0; fd<1024; fd++) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
is_detached = 1;
|
||||
|
||||
openlog("chronyd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Logging, "chronyd version %s starting", PROGRAM_VERSION_STRING);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
97
logging.h
Normal file
97
logging.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/logging.h,v 1.15 2002/02/28 23:27:10 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for diagnostic logging module
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_LOGGING_H
|
||||
#define GOT_LOGGING_H
|
||||
|
||||
/* Definition of severity */
|
||||
typedef enum {
|
||||
LOGS_INFO,
|
||||
LOGS_WARN,
|
||||
LOGS_ERR
|
||||
} LOG_Severity;
|
||||
|
||||
/* Definition of facility. Each message is tagged with who generated
|
||||
it, so that the user can customise what level of reporting he gets
|
||||
for each area of the software */
|
||||
typedef enum {
|
||||
LOGF_Reference,
|
||||
LOGF_NtpIO,
|
||||
LOGF_NtpCore,
|
||||
LOGF_NtpSources,
|
||||
LOGF_Scheduler,
|
||||
LOGF_SourceStats,
|
||||
LOGF_Sources,
|
||||
LOGF_Local,
|
||||
LOGF_Util,
|
||||
LOGF_Main,
|
||||
LOGF_Configure,
|
||||
LOGF_CmdMon,
|
||||
LOGF_Acquire,
|
||||
LOGF_Manual,
|
||||
LOGF_Logging,
|
||||
LOGF_Rtc,
|
||||
LOGF_Regress,
|
||||
LOGF_SysLinux,
|
||||
LOGF_SysSolaris,
|
||||
LOGF_SysSunOS,
|
||||
LOGF_SysWinnt,
|
||||
LOGF_RtcLinux
|
||||
} LOG_Facility;
|
||||
|
||||
/* Init function */
|
||||
extern void LOG_Initialise(void);
|
||||
|
||||
/* Fini function */
|
||||
extern void LOG_Finalise(void);
|
||||
|
||||
/* Line logging function */
|
||||
extern void LOG_Line_Function(LOG_Severity severity, LOG_Facility facility, const char *format, ...);
|
||||
|
||||
/* Logging function for fatal errors */
|
||||
extern volatile void LOG_Fatal_Function(LOG_Facility facility, const char *format, ...);
|
||||
|
||||
/* Position in code reporting function */
|
||||
extern void LOG_Position(const char *filename, int line_number, const char *function_name);
|
||||
|
||||
extern void LOG_GoDaemon(void);
|
||||
|
||||
/* Line logging macro. If the compiler is GNU C, we take advantage of
|
||||
being able to get the function name also. */
|
||||
#if defined(__GNUC__)
|
||||
#define LOG LOG_Position(__FILE__, __LINE__, __FUNCTION__); LOG_Line_Function
|
||||
#define LOG_FATAL LOG_Position(__FILE__, __LINE__, __FUNCTION__); LOG_Fatal_Function
|
||||
#else
|
||||
#define LOG LOG_Position(__FILE__, __LINE__, ""); LOG_Line_Function
|
||||
#define LOG_FATAL LOG_Position(__FILE__, __LINE__, ""); LOG_Fatal_Function
|
||||
#endif /* defined (__GNUC__) */
|
||||
|
||||
#endif /* GOT_LOGGING_H */
|
||||
311
main.c
Normal file
311
main.c
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/main.c,v 1.30 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
The main program
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "sched.h"
|
||||
#include "local.h"
|
||||
#include "sys.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "sources.h"
|
||||
#include "sourcestats.h"
|
||||
#include "reference.h"
|
||||
#include "logging.h"
|
||||
#include "conf.h"
|
||||
#include "cmdmon.h"
|
||||
#include "keys.h"
|
||||
#include "acquire.h"
|
||||
#include "manual.h"
|
||||
#include "version.h"
|
||||
#include "rtc.h"
|
||||
#include "clientlog.h"
|
||||
#include "broadcast.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Set when the initialisation chain has been completed. Prevents finalisation
|
||||
* chain being run if a fatal error happened early. */
|
||||
|
||||
static int initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int reload = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
delete_pidfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
/* Don't care if this fails, there's not a lot we can do */
|
||||
unlink(pidfile);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
volatile void
|
||||
MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(0);
|
||||
|
||||
if (CNF_GetDumpOnExit()) {
|
||||
SRC_DumpSources();
|
||||
}
|
||||
|
||||
RTC_Finalise();
|
||||
MNL_Finalise();
|
||||
ACQ_Finalise();
|
||||
CAM_Finalise();
|
||||
KEY_Finalise();
|
||||
CLG_Finalise();
|
||||
NIO_Finalise();
|
||||
NSR_Finalise();
|
||||
NCR_Finalise();
|
||||
BRD_Finalise();
|
||||
SRC_Finalise();
|
||||
SST_Finalise();
|
||||
REF_Finalise();
|
||||
SYS_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
|
||||
delete_pidfile();
|
||||
|
||||
LOG_Finalise();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
signal_cleanup(int x)
|
||||
{
|
||||
LOG(LOGS_WARN, LOGF_Main, "chronyd exiting on signal");
|
||||
MAI_CleanupAndExit();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
post_acquire_hook(void *anything)
|
||||
{
|
||||
|
||||
CNF_AddSources();
|
||||
CNF_AddBroadcasts();
|
||||
if (reload) {
|
||||
/* Note, we want reload to come well after the initialisation from
|
||||
the real time clock - this gives us a fighting chance that the
|
||||
system-clock scale for the reloaded samples still has a
|
||||
semblence of validity about it. */
|
||||
SRC_ReloadSources();
|
||||
}
|
||||
CNF_SetupAccessRestrictions();
|
||||
|
||||
RTC_StartMeasurements();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
post_init_rtc_hook(void *anything)
|
||||
{
|
||||
CNF_ProcessInitStepSlew(post_acquire_hook, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 1 if the process exists on the system. */
|
||||
|
||||
static int
|
||||
does_process_exist(int pid)
|
||||
{
|
||||
int status;
|
||||
status = getsid(pid);
|
||||
if (status >= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
maybe_another_chronyd_running(int *other_pid)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *in;
|
||||
int pid, count;
|
||||
|
||||
*other_pid = 0;
|
||||
|
||||
in = fopen(pidfile, "r");
|
||||
if (!in) return 0;
|
||||
|
||||
count = fscanf(in, "%d", &pid);
|
||||
fclose(in);
|
||||
|
||||
if (count != 1) return 0;
|
||||
|
||||
*other_pid = pid;
|
||||
return does_process_exist(pid);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
write_lockfile(void)
|
||||
{
|
||||
const char *pidfile = CNF_GetPidFile();
|
||||
FILE *out;
|
||||
|
||||
out = fopen(pidfile, "w");
|
||||
if (!out) {
|
||||
LOG(LOGS_ERR, LOGF_Main, "could not open lockfile %s for writing", pidfile);
|
||||
} else {
|
||||
fprintf(out, "%d\n", getpid());
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int main
|
||||
(int argc, char **argv)
|
||||
{
|
||||
char *conf_file = NULL;
|
||||
int debug = 0;
|
||||
int do_init_rtc = 0;
|
||||
int other_pid;
|
||||
|
||||
LOG_Initialise();
|
||||
|
||||
/* Parse command line options */
|
||||
while (++argv, (--argc)>0) {
|
||||
|
||||
if (!strcmp("-f", *argv)) {
|
||||
++argv, --argc;
|
||||
conf_file = *argv;
|
||||
} else if (!strcmp("-r", *argv)) {
|
||||
reload = 1;
|
||||
} else if (!strcmp("-s", *argv)) {
|
||||
do_init_rtc = 1;
|
||||
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
printf("chronyd (chrony) version %s\n", PROGRAM_VERSION_STRING);
|
||||
exit(0);
|
||||
} else if (!strcmp("-d", *argv)) {
|
||||
debug = 1;
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Main, "Unrecognized command line option [%s]", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SYS_WINNT
|
||||
if (getuid() != 0) {
|
||||
/* This write to the terminal is OK, it comes before we turn into a daemon */
|
||||
fprintf(stderr,"Not superuser\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Turn into a daemon */
|
||||
if (!debug) {
|
||||
LOG_GoDaemon();
|
||||
}
|
||||
|
||||
/* Check whether another chronyd may already be running. Do this after
|
||||
* forking, so that message logging goes to the right place (i.e. syslog), in
|
||||
* case this chronyd is being run from a boot script. */
|
||||
if (maybe_another_chronyd_running(&other_pid)) {
|
||||
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
|
||||
other_pid, CNF_GetPidFile());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
|
||||
* be done *AFTER* the daemon-creation fork() */
|
||||
write_lockfile();
|
||||
#endif
|
||||
|
||||
CNF_ReadFile(conf_file);
|
||||
|
||||
if (do_init_rtc) {
|
||||
RTC_TimePreInit();
|
||||
}
|
||||
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
SYS_Initialise();
|
||||
REF_Initialise();
|
||||
SST_Initialise();
|
||||
SRC_Initialise();
|
||||
BRD_Initialise();
|
||||
NCR_Initialise();
|
||||
NSR_Initialise();
|
||||
NIO_Initialise();
|
||||
CLG_Initialise();
|
||||
KEY_Initialise();
|
||||
CAM_Initialise();
|
||||
ACQ_Initialise();
|
||||
MNL_Initialise();
|
||||
RTC_Initialise();
|
||||
|
||||
/* From now on, it is safe to do finalisation on exit */
|
||||
initialised = 1;
|
||||
|
||||
if (do_init_rtc) {
|
||||
RTC_TimeInit(post_init_rtc_hook, NULL);
|
||||
} else {
|
||||
post_init_rtc_hook(NULL);
|
||||
}
|
||||
|
||||
signal(SIGINT, signal_cleanup);
|
||||
signal(SIGTERM, signal_cleanup);
|
||||
#if !defined(WINNT)
|
||||
signal(SIGQUIT, signal_cleanup);
|
||||
signal(SIGHUP, signal_cleanup);
|
||||
#endif /* WINNT */
|
||||
|
||||
/* The program normally runs under control of the main loop in
|
||||
the scheduler. */
|
||||
SCH_MainLoop();
|
||||
|
||||
MAI_CleanupAndExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
39
main.h
Normal file
39
main.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/main.h,v 1.8 2002/02/28 23:27:10 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for main routine
|
||||
*/
|
||||
|
||||
#ifndef GOT_MAIN_H
|
||||
#define GOT_MAIN_H
|
||||
|
||||
/* Function to clean up at end of run */
|
||||
extern volatile void MAI_CleanupAndExit(void);
|
||||
|
||||
#endif /* GOT_MAIN_H */
|
||||
|
||||
|
||||
331
manual.c
Normal file
331
manual.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/manual.c,v 1.20 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines for implementing manual input of real time.
|
||||
|
||||
The daemon accepts manual time input over the control connection,
|
||||
and adjusts the system time to match. Besides this, though, it can
|
||||
determine the average rate of time loss or gain of the local system
|
||||
and adjust the frequency accordingly.
|
||||
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "manual.h"
|
||||
#include "logging.h"
|
||||
#include "local.h"
|
||||
#include "conf.h"
|
||||
#include "util.h"
|
||||
#include "ntp.h"
|
||||
#include "reference.h"
|
||||
#include "regress.h"
|
||||
|
||||
static int enabled = 0;
|
||||
|
||||
/* More recent samples at highest indices */
|
||||
typedef struct {
|
||||
struct timeval when; /* This is our 'cooked' time */
|
||||
double orig_offset; /*+ Not modified by slew samples */
|
||||
double offset; /*+ if we are fast of the supplied reference */
|
||||
double residual; /*+ regression residual (sign convention given by
|
||||
(measured-predicted)) */
|
||||
} Sample;
|
||||
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
static Sample samples[16];
|
||||
static int n_samples;
|
||||
|
||||
static int replace_margin;
|
||||
static int error;
|
||||
|
||||
/* Eventually these constants need to be user-defined in conf file */
|
||||
#define REPLACE_MARGIN 300
|
||||
#define ERROR_MARGIN 0.2
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
slew_samples(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *not_used);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MNL_Initialise(void)
|
||||
{
|
||||
if (CNF_GetManualEnabled()) {
|
||||
enabled = 1;
|
||||
} else {
|
||||
enabled = 0;
|
||||
}
|
||||
|
||||
n_samples = 0;
|
||||
|
||||
replace_margin = REPLACE_MARGIN;
|
||||
error = ERROR_MARGIN;
|
||||
|
||||
LCL_AddParameterChangeHandler(slew_samples, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MNL_Finalise(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
estimate_and_set_system(struct timeval *now, int offset_provided, double offset, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
{
|
||||
double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
|
||||
double b0, b1;
|
||||
int n_runs, best_start; /* Unused results from regression analyser */
|
||||
int i;
|
||||
double freq = 0.0;
|
||||
double skew = 0.099999999; /* All 9's when printed to log file */
|
||||
int found_freq;
|
||||
double slew_by;
|
||||
|
||||
if (n_samples > 1) {
|
||||
for (i=0; i<n_samples; i++) {
|
||||
UTI_DiffTimevalsToDouble(&agos[i], &samples[n_samples-1].when, &samples[i].when);
|
||||
offsets[i] = samples[i].offset;
|
||||
}
|
||||
|
||||
RGR_FindBestRobustRegression(agos, offsets, n_samples,
|
||||
1.0e-8, /* 0.01ppm easily good enough for this! */
|
||||
&b0, &b1, &n_runs, &best_start);
|
||||
|
||||
|
||||
/* Ignore b0 from regression; treat offset as being the most
|
||||
recently entered value. (If the administrator knows he's put
|
||||
an outlier in, he will rerun the settime operation.) However,
|
||||
the frequency estimate comes from the regression. */
|
||||
|
||||
freq = -b1;
|
||||
found_freq = 1;
|
||||
} else {
|
||||
if (offset_provided) {
|
||||
b0 = offset;
|
||||
} else {
|
||||
b0 = 0.0;
|
||||
}
|
||||
b1 = freq = 0.0;
|
||||
found_freq = 0;
|
||||
}
|
||||
|
||||
if (offset_provided) {
|
||||
slew_by = offset;
|
||||
} else {
|
||||
slew_by = b0;
|
||||
}
|
||||
|
||||
if (found_freq) {
|
||||
LOG(LOGS_INFO, LOGF_Manual,
|
||||
"Making a frequency change of %.3fppm and a slew of %.6f\n",
|
||||
1.0e6 * freq, slew_by);
|
||||
|
||||
REF_SetManualReference(now,
|
||||
slew_by,
|
||||
freq, skew);
|
||||
} else {
|
||||
LOG(LOGS_INFO, LOGF_Manual, "Making a slew of %.6f", slew_by);
|
||||
REF_SetManualReference(now,
|
||||
slew_by,
|
||||
0.0, skew);
|
||||
}
|
||||
|
||||
if (offset_cs) *offset_cs = (long)(0.5 + 100.0 * b0);
|
||||
if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
|
||||
if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
/* Calculate residuals to store them */
|
||||
for (i=0; i<n_samples; i++) {
|
||||
samples[i].residual = offsets[i] - (b0 + agos[i] * b1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
|
||||
{
|
||||
struct timeval now;
|
||||
double local_clock_err;
|
||||
double offset;
|
||||
int i;
|
||||
|
||||
if (enabled) {
|
||||
|
||||
/* Check whether timestamp is within margin of old one */
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
|
||||
UTI_DiffTimevalsToDouble(&offset, &now, ts);
|
||||
|
||||
/* Check if buffer full up */
|
||||
if (n_samples == MAX_SAMPLES) {
|
||||
/* Shift samples down */
|
||||
for (i=1; i<n_samples; i++) {
|
||||
samples[i-1] = samples[i];
|
||||
}
|
||||
--n_samples;
|
||||
}
|
||||
|
||||
samples[n_samples].when = now;
|
||||
samples[n_samples].offset = offset;
|
||||
samples[n_samples].orig_offset = offset;
|
||||
++n_samples;
|
||||
|
||||
estimate_and_set_system(&now, 1, offset, offset_cs, dfreq_ppm, new_afreq_ppm);
|
||||
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
slew_samples(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *not_used)
|
||||
{
|
||||
double elapsed, delta_time;
|
||||
int i;
|
||||
for (i=0; i<n_samples; i++) {
|
||||
UTI_DiffTimevalsToDouble(&elapsed, cooked, &samples[i].when);
|
||||
delta_time = elapsed * dfreq - doffset;
|
||||
UTI_AddDoubleToTimeval(&samples[i].when, delta_time, &samples[i].when);
|
||||
samples[i].offset += delta_time;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MNL_Enable(void)
|
||||
{
|
||||
enabled = 1;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MNL_Disable(void)
|
||||
{
|
||||
enabled = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MNL_Reset(void)
|
||||
{
|
||||
n_samples = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
|
||||
protocol */
|
||||
|
||||
void
|
||||
MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n_samples > max) {
|
||||
*n = max;
|
||||
} else {
|
||||
*n = n_samples;
|
||||
}
|
||||
|
||||
for (i=0; i<n_samples && i<max; i++) {
|
||||
report[i].when = samples[i].when.tv_sec;
|
||||
report[i].slewed_offset = samples[i].offset;
|
||||
report[i].orig_offset = samples[i].orig_offset;
|
||||
report[i].residual = samples[i].residual;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Delete a sample if it's within range, re-estimate the error and
|
||||
drift and apply it to the system clock. */
|
||||
|
||||
int
|
||||
MNL_DeleteSample(int index)
|
||||
{
|
||||
int i;
|
||||
struct timeval now;
|
||||
double local_clock_err;
|
||||
|
||||
if ((index < 0) || (index >= n_samples)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Crunch the samples down onto the one being deleted */
|
||||
|
||||
for (i=index; i<(n_samples-1); i++) {
|
||||
samples[i] = samples[i+1];
|
||||
}
|
||||
|
||||
n_samples -= 1;
|
||||
|
||||
/* Now re-estimate. NULLs because we don't want the parameters back
|
||||
in this case. */
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
estimate_and_set_system(&now, 0, 0.0, NULL, NULL, NULL);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
49
manual.h
Normal file
49
manual.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/manual.h,v 1.12 2002/02/28 23:27:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for manual time input module.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_MANUAL_H
|
||||
#define GOT_MANUAL_H
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "reports.h"
|
||||
|
||||
extern void MNL_Initialise(void);
|
||||
extern void MNL_Finalise(void);
|
||||
extern int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm);
|
||||
|
||||
extern void MNL_Enable(void);
|
||||
extern void MNL_Disable(void);
|
||||
extern void MNL_Reset(void);
|
||||
|
||||
extern void MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n);
|
||||
extern int MNL_DeleteSample(int index);
|
||||
|
||||
#endif /* GOT_MANUAL_H */
|
||||
322
md5.c
Normal file
322
md5.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
***********************************************************************
|
||||
** md5.c -- the source code for MD5 routines **
|
||||
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
|
||||
** Created: 2/17/90 RLR **
|
||||
** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
|
||||
** Revised (for MD5): RLR 4/27/91 **
|
||||
** -- G modified to have y&~z instead of y&z **
|
||||
** -- FF, GG, HH modified to add in last register done **
|
||||
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
|
||||
** -- distinct additive constant for each step **
|
||||
** -- round 4 added, working mod 7 **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
|
||||
** **
|
||||
** License to copy and use this software is granted provided that **
|
||||
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
|
||||
** Digest Algorithm" in all material mentioning or referencing this **
|
||||
** software or this function. **
|
||||
** **
|
||||
** License is also granted to make and use derivative works **
|
||||
** provided that such works are identified as "derived from the RSA **
|
||||
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
|
||||
** material mentioning or referencing the derived work. **
|
||||
** **
|
||||
** RSA Data Security, Inc. makes no representations concerning **
|
||||
** either the merchantability of this software or the suitability **
|
||||
** of this software for any particular purpose. It is provided "as **
|
||||
** is" without express or implied warranty of any kind. **
|
||||
** **
|
||||
** These notices must be retained in any copies of any part of this **
|
||||
** documentation and/or software. **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** Message-digest routines: **
|
||||
** To form the message digest for a message M **
|
||||
** (1) Initialize a context buffer mdContext using MD5Init **
|
||||
** (2) Call MD5Update on mdContext and M **
|
||||
** (3) Call MD5Final on mdContext **
|
||||
** The message digest is now in mdContext->digest[0...15] **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
/* forward declaration */
|
||||
static void Transform (UINT4 *, UINT4 *);
|
||||
|
||||
#ifdef __STDC__
|
||||
static const
|
||||
#else
|
||||
static
|
||||
#endif
|
||||
unsigned char PADDING[64] = {
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions */
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits */
|
||||
#if defined(FAST_MD5) && defined(__GNUC__) && defined(mc68000)
|
||||
/*
|
||||
* If we're on a 68000 based CPU and using a GNU C compiler with
|
||||
* inline assembly code, we can speed this up a bit.
|
||||
*/
|
||||
inline UINT4 ROTATE_LEFT(UINT4 x, int n)
|
||||
{
|
||||
asm("roll %2,%0" : "=d" (x) : "0" (x), "Ir" (n));
|
||||
return x;
|
||||
}
|
||||
#else
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
#endif
|
||||
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
|
||||
/* Rotation is separate from addition to prevent recomputation */
|
||||
#define FF(a, b, c, d, x, s, ac) \
|
||||
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) \
|
||||
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) \
|
||||
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) \
|
||||
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/* The routine MD5Init initializes the message-digest context
|
||||
mdContext. All fields are set to zero.
|
||||
*/
|
||||
void MD5Init (mdContext)
|
||||
MD5_CTX *mdContext;
|
||||
{
|
||||
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
|
||||
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
mdContext->buf[0] = (UINT4)0x67452301;
|
||||
mdContext->buf[1] = (UINT4)0xefcdab89;
|
||||
mdContext->buf[2] = (UINT4)0x98badcfe;
|
||||
mdContext->buf[3] = (UINT4)0x10325476;
|
||||
}
|
||||
|
||||
/* The routine MD5Update updates the message-digest context to
|
||||
account for the presence of each of the characters inBuf[0..inLen-1]
|
||||
in the message whose digest is being computed.
|
||||
*/
|
||||
void MD5Update (mdContext, inBuf, inLen)
|
||||
MD5_CTX *mdContext;
|
||||
unsigned const char *inBuf;
|
||||
unsigned int inLen;
|
||||
{
|
||||
UINT4 in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/* update number of bits */
|
||||
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
|
||||
mdContext->i[1]++;
|
||||
mdContext->i[0] += ((UINT4)inLen << 3);
|
||||
mdContext->i[1] += ((UINT4)inLen >> 29);
|
||||
|
||||
while (inLen--) {
|
||||
/* add new character to buffer, increment mdi */
|
||||
mdContext->in[mdi++] = *inBuf++;
|
||||
|
||||
/* transform if necessary */
|
||||
if (mdi == 0x40) {
|
||||
for (i = 0, ii = 0; i < 16; i++, ii += 4)
|
||||
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
|
||||
(((UINT4)mdContext->in[ii+2]) << 16) |
|
||||
(((UINT4)mdContext->in[ii+1]) << 8) |
|
||||
((UINT4)mdContext->in[ii]);
|
||||
Transform (mdContext->buf, in);
|
||||
mdi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The routine MD5Final terminates the message-digest computation and
|
||||
ends with the desired message digest in mdContext->digest[0...15].
|
||||
*/
|
||||
|
||||
void MD5Final (mdContext)
|
||||
MD5_CTX *mdContext;
|
||||
{
|
||||
UINT4 in[16];
|
||||
int mdi;
|
||||
unsigned int i, ii;
|
||||
unsigned int padLen;
|
||||
|
||||
/* save number of bits */
|
||||
in[14] = mdContext->i[0];
|
||||
in[15] = mdContext->i[1];
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
|
||||
|
||||
/* pad out to 56 mod 64 */
|
||||
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
|
||||
MD5Update (mdContext, PADDING, padLen);
|
||||
|
||||
/* append length in bits and transform */
|
||||
for (i = 0, ii = 0; i < 14; i++, ii += 4)
|
||||
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
|
||||
(((UINT4)mdContext->in[ii+2]) << 16) |
|
||||
(((UINT4)mdContext->in[ii+1]) << 8) |
|
||||
((UINT4)mdContext->in[ii]);
|
||||
Transform (mdContext->buf, in);
|
||||
|
||||
/* store buffer in digest */
|
||||
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
|
||||
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
|
||||
mdContext->digest[ii+1] =
|
||||
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
|
||||
mdContext->digest[ii+2] =
|
||||
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
|
||||
mdContext->digest[ii+3] =
|
||||
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic MD5 step. Transforms buf based on in.
|
||||
*/
|
||||
static void Transform (buf, in)
|
||||
UINT4 *buf;
|
||||
UINT4 *in;
|
||||
{
|
||||
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
|
||||
|
||||
/* Round 1 */
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
|
||||
FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */
|
||||
FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */
|
||||
FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */
|
||||
FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */
|
||||
FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */
|
||||
FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */
|
||||
GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG ( d, a, b, c, in[10], S22, 0x2441453); /* 22 */
|
||||
GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */
|
||||
GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */
|
||||
HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH ( b, c, d, a, in[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */
|
||||
II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */
|
||||
II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */
|
||||
II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */
|
||||
II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */
|
||||
II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */
|
||||
II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */
|
||||
II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */
|
||||
II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** End of md5.c **
|
||||
******************************** (cut) ********************************
|
||||
*/
|
||||
60
md5.h
Normal file
60
md5.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
***********************************************************************
|
||||
** md5.h -- header file for implementation of MD5 **
|
||||
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
|
||||
** Created: 2/17/90 RLR **
|
||||
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
|
||||
** Revised (for MD5): RLR 4/27/91 **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
|
||||
** **
|
||||
** License to copy and use this software is granted provided that **
|
||||
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
|
||||
** Digest Algorithm" in all material mentioning or referencing this **
|
||||
** software or this function. **
|
||||
** **
|
||||
** License is also granted to make and use derivative works **
|
||||
** provided that such works are identified as "derived from the RSA **
|
||||
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
|
||||
** material mentioning or referencing the derived work. **
|
||||
** **
|
||||
** RSA Data Security, Inc. makes no representations concerning **
|
||||
** either the merchantability of this software or the suitability **
|
||||
** of this software for any particular purpose. It is provided "as **
|
||||
** is" without express or implied warranty of any kind. **
|
||||
** **
|
||||
** These notices must be retained in any copies of any part of this **
|
||||
** documentation and/or software. **
|
||||
***********************************************************************
|
||||
*/
|
||||
|
||||
#ifdef HAS_STDINT_H
|
||||
#include <stdint.h>
|
||||
#elif defined(HAS_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/* typedef a 32-bit type */
|
||||
typedef uint32_t UINT4;
|
||||
|
||||
/* Data structure for MD5 (Message-Digest) computation */
|
||||
typedef struct {
|
||||
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
|
||||
UINT4 buf[4]; /* scratch buffer */
|
||||
unsigned char in[64]; /* input buffer */
|
||||
unsigned char digest[16]; /* actual digest after MD5Final call */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init (MD5_CTX *mdContext);
|
||||
void MD5Update (MD5_CTX *, unsigned const char *, unsigned int);
|
||||
void MD5Final (MD5_CTX *);
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
** End of md5.h **
|
||||
******************************** (cut) ********************************
|
||||
*/
|
||||
43
memory.h
Normal file
43
memory.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/memory.h,v 1.7 2002/02/28 23:27:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for memory functions
|
||||
*/
|
||||
|
||||
#ifndef GOT_MEMORY_H
|
||||
#define GOT_MEMORY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define Malloc(x) malloc(x)
|
||||
#define MallocNew(T) ((T *) malloc(sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))
|
||||
#define Realloc(x,y) realloc(x,y)
|
||||
#define ReallocArray(T,n,x) ((T *) realloc((void *)(x), (n)*sizeof(T)))
|
||||
#define Free(x) free(x)
|
||||
|
||||
#endif /* GOT_MEMORY_H */
|
||||
135
mkdirpp.c
Normal file
135
mkdirpp.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/mkdirpp.c,v 1.10 2002/11/03 22:49:17 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
A function for creating a directory and any parent directories that
|
||||
don't exist.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "mkdirpp.h"
|
||||
|
||||
static int
|
||||
do_dir(char *p)
|
||||
{
|
||||
int status;
|
||||
struct stat buf;
|
||||
|
||||
#if defined(TEST)
|
||||
fprintf(stderr, "do_dir(%s)\n", p);
|
||||
#endif
|
||||
|
||||
/* See if directory exists */
|
||||
status = stat(p, &buf);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno == ENOENT) {
|
||||
/* Try to create directory */
|
||||
status = mkdir(p, 0755);
|
||||
return status;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_ISDIR(buf.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 0 if the directory couldn't be created, 1 if it could (or
|
||||
already existed) */
|
||||
|
||||
int
|
||||
mkdir_and_parents(const char *path)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
int i, j, k, last;
|
||||
len = strlen(path);
|
||||
|
||||
p = (char *) malloc(1 + len);
|
||||
|
||||
i = k = 0;
|
||||
while (1) {
|
||||
p[i++] = path[k++];
|
||||
|
||||
if (path[k] == '/' || !path[k]) {
|
||||
p[i] = 0;
|
||||
|
||||
if (do_dir(p) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!path[k]) {
|
||||
/* End of the string */
|
||||
break;
|
||||
}
|
||||
|
||||
/* check whether its a trailing / or group of / */
|
||||
last = 1;
|
||||
j = k+1;
|
||||
while (path[j]) {
|
||||
if (path[j] != '/') {
|
||||
k = j - 1; /* Pick up a / into p[] thru the assignment at the top of the loop */
|
||||
last = 0;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path[k]) break;
|
||||
|
||||
}
|
||||
|
||||
free(p);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(TEST)
|
||||
int main(int argc, char **argv) {
|
||||
if (argc > 1) {
|
||||
/* Invert sense of result */
|
||||
return mkdir_and_parents(argv[1]) ? 0 : 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
35
mkdirpp.h
Normal file
35
mkdirpp.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/mkdirpp.h,v 1.6 2002/02/28 23:27:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_MKDIRPP_H
|
||||
#define GOT_MKDIRPP_H
|
||||
|
||||
extern int mkdir_and_parents(const char *path);
|
||||
|
||||
#endif
|
||||
92
nameserv.c
Normal file
92
nameserv.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/nameserv.c,v 1.13 2002/02/28 23:27:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Functions to do name to IP address conversion
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "nameserv.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
unsigned long
|
||||
DNS_Name2IPAddress(const char *name)
|
||||
{
|
||||
struct hostent *host;
|
||||
unsigned char *address0;
|
||||
unsigned long result;
|
||||
|
||||
host = gethostbyname(name);
|
||||
if (host == NULL) {
|
||||
result = DNS_Failed_Address;
|
||||
} else {
|
||||
address0 = host->h_addr_list[0];
|
||||
result = ((((unsigned long)address0[0])<<24) |
|
||||
(((unsigned long)address0[1])<<16) |
|
||||
(((unsigned long)address0[2])<<8) |
|
||||
(((unsigned long)address0[3])));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
const char *
|
||||
DNS_IPAddress2Name(unsigned long ip_addr)
|
||||
{
|
||||
struct hostent *host;
|
||||
static char buffer[16];
|
||||
unsigned int a, b, c, d;
|
||||
unsigned long addr;
|
||||
|
||||
addr = htonl(ip_addr);
|
||||
if (addr == 0UL) {
|
||||
/* Catch this as a special case that will never resolve to
|
||||
anything */
|
||||
strcpy(buffer, "0.0.0.0");
|
||||
return buffer;
|
||||
} else {
|
||||
host = gethostbyaddr((const char *) &addr, sizeof(ip_addr), AF_INET);
|
||||
if (!host) {
|
||||
a = (ip_addr >> 24) & 0xff;
|
||||
b = (ip_addr >> 16) & 0xff;
|
||||
c = (ip_addr >> 8) & 0xff;
|
||||
d = (ip_addr) & 0xff;
|
||||
sprintf(buffer, "%u.%u.%u.%u", a, b, c, d);
|
||||
return buffer;
|
||||
} else {
|
||||
return host->h_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
42
nameserv.h
Normal file
42
nameserv.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/nameserv.h,v 1.8 2002/02/28 23:27:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Module header for nameserver functions
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GOT_NAMESERV_H
|
||||
#define GOT_NAMESERV_H
|
||||
|
||||
static const unsigned long DNS_Failed_Address = 0x0UL;
|
||||
|
||||
extern unsigned long DNS_Name2IPAddress(const char *name);
|
||||
|
||||
const char *DNS_IPAddress2Name(unsigned long ip_addr);
|
||||
|
||||
#endif /* GOT_NAMESERV_H */
|
||||
|
||||
116
ntp.h
Normal file
116
ntp.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp.h,v 1.11 2003/04/10 21:28:11 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file containing common NTP bits and pieces
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_H
|
||||
#define GOT_NTP_H
|
||||
|
||||
#ifdef HAS_STDINT_H
|
||||
#include <stdint.h>
|
||||
#elif defined(HAS_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
} NTP_int64;
|
||||
|
||||
typedef uint32_t NTP_int32;
|
||||
|
||||
#define AUTH_DATA_LEN 16
|
||||
|
||||
/* Type definition for leap bits */
|
||||
typedef enum {
|
||||
LEAP_Normal = 0,
|
||||
LEAP_InsertSecond = 1,
|
||||
LEAP_DeleteSecond = 2,
|
||||
LEAP_Unsynchronised = 3
|
||||
} NTP_Leap;
|
||||
|
||||
typedef enum {
|
||||
MODE_UNDEFINED = 0,
|
||||
MODE_ACTIVE = 1,
|
||||
MODE_PASSIVE = 2,
|
||||
MODE_CLIENT = 3,
|
||||
MODE_SERVER = 4,
|
||||
MODE_BROADCAST = 5
|
||||
} NTP_Mode;
|
||||
|
||||
typedef struct {
|
||||
uint8_t lvm;
|
||||
uint8_t stratum;
|
||||
int8_t poll;
|
||||
int8_t precision;
|
||||
NTP_int32 root_delay;
|
||||
NTP_int32 root_dispersion;
|
||||
NTP_int32 reference_id;
|
||||
NTP_int64 reference_ts;
|
||||
NTP_int64 originate_ts;
|
||||
NTP_int64 receive_ts;
|
||||
NTP_int64 transmit_ts;
|
||||
NTP_int32 auth_keyid;
|
||||
uint8_t auth_data[AUTH_DATA_LEN];
|
||||
} NTP_Packet;
|
||||
|
||||
/* We have to declare a buffer type to hold a datagram read from the
|
||||
network. Even though we won't be using them (yet?!), this must be
|
||||
large enough to hold NTP control messages. */
|
||||
|
||||
/* Define the maximum number of bytes that can be read in a single
|
||||
message. (This is cribbed from ntp.h in the xntpd source code). */
|
||||
|
||||
#define MAX_NTP_MESSAGE_SIZE (468+12+16+4)
|
||||
|
||||
typedef union {
|
||||
NTP_Packet ntp_pkt;
|
||||
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
|
||||
} ReceiveBuffer;
|
||||
|
||||
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
inline static double
|
||||
int32_to_double(NTP_int32 x)
|
||||
{
|
||||
return (double) ntohl(x) / 65536.0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
inline static NTP_int32
|
||||
double_to_int32(double x)
|
||||
{
|
||||
return htonl((NTP_int32)(0.5 + 65536.0 * x));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#endif /* GOT_NTP_H */
|
||||
1867
ntp_core.c
Normal file
1867
ntp_core.c
Normal file
File diff suppressed because it is too large
Load Diff
105
ntp_core.h
Normal file
105
ntp_core.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp_core.h,v 1.16 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for the main NTP protocol engine
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_CORE_H
|
||||
#define GOT_NTP_CORE_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "addressing.h"
|
||||
#include "srcparams.h"
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* This is a private data type used for storing the instance record for
|
||||
each source that we are chiming with */
|
||||
typedef struct NCR_Instance_Record *NCR_Instance;
|
||||
|
||||
/* Init and fini functions */
|
||||
extern void NCR_Initialise(void);
|
||||
extern void NCR_Finalise(void);
|
||||
|
||||
/* Get a new instance for a server */
|
||||
extern NCR_Instance NCR_GetServerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params);
|
||||
|
||||
/* Get a new instance for a peer */
|
||||
extern NCR_Instance NCR_GetPeerInstance(NTP_Remote_Address *remote_addr, SourceParameters *params);
|
||||
|
||||
/* Destroy an instance */
|
||||
extern void NCR_DestroyInstance(NCR_Instance instance);
|
||||
|
||||
/* This routine is called when a new packet arrives off the network,
|
||||
and it relates to a source we have an ongoing protocol exchange with */
|
||||
extern void NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance data);
|
||||
|
||||
/* This routine is called when a new packet arrives off the network,
|
||||
and we do not recognize its source */
|
||||
extern void NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* This routine is called when a new authenticated packet arrives off
|
||||
the network, and it relates to a source we have an ongoing protocol
|
||||
exchange with */
|
||||
extern void NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, NCR_Instance data);
|
||||
|
||||
/* This routine is called when a new authenticated packet arrives off
|
||||
the network, and we do not recognize its source */
|
||||
extern void NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Slew receive and transmit times in instance records */
|
||||
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);
|
||||
|
||||
/* Take a particular source online (i.e. start sampling it) */
|
||||
extern void NCR_TakeSourceOnline(NCR_Instance inst);
|
||||
|
||||
/* Take a particular source offline (i.e. stop sampling it, without
|
||||
marking it unreachable in the source selection stuff) */
|
||||
extern void NCR_TakeSourceOffline(NCR_Instance inst);
|
||||
|
||||
extern void NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll);
|
||||
|
||||
extern void NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll);
|
||||
|
||||
extern void NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay);
|
||||
|
||||
extern void NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio);
|
||||
|
||||
extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
|
||||
|
||||
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *now);
|
||||
|
||||
extern int NCR_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all);
|
||||
extern int NCR_CheckAccessRestriction(unsigned long ip_addr);
|
||||
|
||||
extern void NCR_CycleLogFile(void);
|
||||
|
||||
extern void NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
|
||||
int *burst_online, int *burst_offline);
|
||||
|
||||
#endif /* GOT_NTP_CORE_H */
|
||||
297
ntp_io.c
Normal file
297
ntp_io.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp_io.c,v 1.23 2003/04/01 20:54:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This file deals with the IO aspects of reading and writing NTP packets
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "sched.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "conf.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/* The file descriptor for the socket */
|
||||
static int sock_fd;
|
||||
|
||||
/* Flag indicating that we have been initialised */
|
||||
static int initialised=0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Forward prototypes */
|
||||
static void read_from_socket(void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
do_size_checks(void)
|
||||
{
|
||||
/* Assertions to check the sizes of certain data types
|
||||
and the positions of certain record fields */
|
||||
|
||||
/* Check that certain invariants are true */
|
||||
assert(sizeof(NTP_int32) == 4);
|
||||
assert(sizeof(NTP_int64) == 8);
|
||||
|
||||
/* Check offsets of all fields in the NTP packet format */
|
||||
assert(offsetof(NTP_Packet, lvm) == 0);
|
||||
assert(offsetof(NTP_Packet, stratum) == 1);
|
||||
assert(offsetof(NTP_Packet, poll) == 2);
|
||||
assert(offsetof(NTP_Packet, precision) == 3);
|
||||
assert(offsetof(NTP_Packet, root_delay) == 4);
|
||||
assert(offsetof(NTP_Packet, root_dispersion) == 8);
|
||||
assert(offsetof(NTP_Packet, reference_id) == 12);
|
||||
assert(offsetof(NTP_Packet, reference_ts) == 16);
|
||||
assert(offsetof(NTP_Packet, originate_ts) == 24);
|
||||
assert(offsetof(NTP_Packet, receive_ts) == 32);
|
||||
assert(offsetof(NTP_Packet, transmit_ts) == 40);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Initialise(void)
|
||||
{
|
||||
struct sockaddr_in my_addr;
|
||||
unsigned short port_number;
|
||||
unsigned long bind_address;
|
||||
int on_off = 1;
|
||||
|
||||
assert(!initialised);
|
||||
initialised = 1;
|
||||
|
||||
do_size_checks();
|
||||
|
||||
port_number = CNF_GetNTPPort();
|
||||
|
||||
/* Open Internet domain UDP socket for NTP message transmissions */
|
||||
|
||||
#if 0
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
#else
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
if (sock_fd < 0) {
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not open socket : %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Make the socket capable of re-using an old address */
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set reuseaddr socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
|
||||
/* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set broadcast socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
|
||||
/* Bind the port */
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(port_number);
|
||||
|
||||
CNF_GetBindAddress(&bind_address);
|
||||
|
||||
if (bind_address != 0UL) {
|
||||
my_addr.sin_addr.s_addr = htonl(bind_address);
|
||||
} else {
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_NtpIO, "Initialising, socket fd=%d", sock_fd);
|
||||
#endif
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not bind socket : %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Register handler for read events on the socket */
|
||||
SCH_AddInputFileHandler(sock_fd, read_from_socket, NULL);
|
||||
|
||||
#if 0
|
||||
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK | O_NDELAY) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not make socket non-blocking");
|
||||
}
|
||||
|
||||
if (ioctl(sock_fd, I_SETSIG, S_INPUT) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not enable signal");
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Finalise(void)
|
||||
{
|
||||
if (sock_fd >= 0) {
|
||||
SCH_RemoveInputFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
}
|
||||
sock_fd = -1;
|
||||
initialised = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
read_from_socket(void *anything)
|
||||
{
|
||||
/* This should only be called when there is something
|
||||
to read, otherwise it will block. */
|
||||
|
||||
int status;
|
||||
ReceiveBuffer message;
|
||||
int message_length;
|
||||
struct sockaddr_in where_from;
|
||||
int from_length;
|
||||
unsigned int flags = 0;
|
||||
struct timeval now;
|
||||
NTP_Remote_Address remote_addr;
|
||||
double local_clock_err;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
from_length = sizeof(where_from);
|
||||
message_length = sizeof(message);
|
||||
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
status = recvfrom(sock_fd, (char *)&message, message_length, flags,
|
||||
(struct sockaddr *)&where_from, &from_length);
|
||||
|
||||
/* Don't bother checking if read failed or why if it did. More
|
||||
likely than not, it will be connection refused, resulting from a
|
||||
previous sendto() directing a datagram at a port that is not
|
||||
listening (which appears to generate an ICMP response, and on
|
||||
some architectures e.g. Linux this is translated into an error
|
||||
reponse on a subsequent recvfrom). */
|
||||
|
||||
if (status > 0) {
|
||||
remote_addr.ip_addr = ntohl(where_from.sin_addr.s_addr);
|
||||
remote_addr.port = ntohs(where_from.sin_port);
|
||||
|
||||
if (status == NTP_NORMAL_PACKET_SIZE) {
|
||||
|
||||
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
|
||||
|
||||
} else if (status == sizeof(NTP_Packet)) {
|
||||
|
||||
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
|
||||
|
||||
} else {
|
||||
|
||||
/* Just ignore the packet if it's not of a recognized length */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send an unauthenticated packet to a given address */
|
||||
|
||||
void
|
||||
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
struct sockaddr_in remote;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(remote_addr->port);
|
||||
remote.sin_addr.s_addr = htonl(remote_addr->ip_addr);
|
||||
|
||||
if (sendto(sock_fd, (void *) packet, NTP_NORMAL_PACKET_SIZE, 0,
|
||||
(struct sockaddr *) &remote, sizeof(remote)) < 0) {
|
||||
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to :%s%d : %s",
|
||||
UTI_IPToDottedQuad(remote_addr->ip_addr), remote_addr->port, strerror(errno));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Send an authenticated packet to a given address */
|
||||
|
||||
void
|
||||
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
struct sockaddr_in remote;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(remote_addr->port);
|
||||
remote.sin_addr.s_addr = htonl(remote_addr->ip_addr);
|
||||
|
||||
if (sendto(sock_fd, (void *) packet, sizeof(NTP_Packet), 0,
|
||||
(struct sockaddr *) &remote, sizeof(remote)) < 0) {
|
||||
LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to :%s%d : %s",
|
||||
UTI_IPToDottedQuad(remote_addr->ip_addr), remote_addr->port, strerror(errno));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* We ought to use getservbyname, but I can't really see this changing */
|
||||
#define ECHO_PORT 7
|
||||
|
||||
void
|
||||
NIO_SendEcho(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
unsigned long magic_message = 0xbe7ab1e7UL;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(ECHO_PORT);
|
||||
addr.sin_addr.s_addr = htonl(remote_addr->ip_addr);
|
||||
|
||||
/* Just ignore error status on send - this is not a big deal anyway */
|
||||
sendto(sock_fd, (void *) &magic_message, sizeof(unsigned long), 0,
|
||||
(struct sockaddr *) &addr, sizeof(addr));
|
||||
|
||||
|
||||
}
|
||||
53
ntp_io.h
Normal file
53
ntp_io.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp_io.h,v 1.9 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header file for the NTP socket I/O bits.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_IO_H
|
||||
#define GOT_NTP_IO_H
|
||||
|
||||
#include "ntp.h"
|
||||
#include "addressing.h"
|
||||
|
||||
/* Function to initialise the module. */
|
||||
extern void NIO_Initialise(void);
|
||||
|
||||
/* Function to finalise the module */
|
||||
extern void NIO_Finalise(void);
|
||||
|
||||
/* Function to transmit a packet */
|
||||
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to transmit an authenticated packet */
|
||||
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Function to send a datagram to a remote machine's UDP echo port. */
|
||||
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr);
|
||||
|
||||
#endif /* GOT_NTP_IO_H */
|
||||
499
ntp_sources.c
Normal file
499
ntp_sources.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp_sources.c,v 1.17 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Functions which manage the pool of NTP sources that we are currently
|
||||
a client of or peering with.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "ntp_sources.h"
|
||||
#include "ntp_core.h"
|
||||
#include "util.h"
|
||||
#include "logging.h"
|
||||
#include "local.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Record type private to this file, used to store information about
|
||||
particular sources */
|
||||
typedef struct {
|
||||
NTP_Remote_Address remote_addr; /* The address of this source */
|
||||
int in_use; /* Whether this slot in the table is in use */
|
||||
NCR_Instance data; /* Data for the protocol engine for this source */
|
||||
} SourceRecord;
|
||||
|
||||
#define N_RECORDS 256
|
||||
|
||||
/* Fixed size table, because we use a hard coded hash algorithm. It
|
||||
is rather unlikely we would have anything approaching this number
|
||||
of sources. */
|
||||
static SourceRecord records[N_RECORDS];
|
||||
|
||||
static int n_sources;
|
||||
|
||||
/* The largest number of sources we want to have stored in the hash table */
|
||||
#define MAX_SOURCES 64
|
||||
|
||||
/* ================================================== */
|
||||
/* Forward prototypes */
|
||||
static void
|
||||
slew_sources(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Flag indicating whether module is initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_Initialise(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
records[i].in_use = 0;
|
||||
}
|
||||
n_sources = 0;
|
||||
initialised = 1;
|
||||
|
||||
LCL_AddParameterChangeHandler(slew_sources, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_Finalise(void)
|
||||
{
|
||||
initialised = 0;
|
||||
return; /* Nothing to do yet */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return slot number and whether the IP address was matched or not.
|
||||
found = 0 => Neither IP nor port matched, empty slot returned
|
||||
found = 1 => Only IP matched, port doesn't match
|
||||
found = 2 => Both IP and port matched.
|
||||
|
||||
It is assumed that there can only ever be one record for a
|
||||
particular IP address. (If a different port comes up, it probably
|
||||
means someone is running ntpdate -d or something). Thus, if we
|
||||
match the IP address we stop the search regardless of whether the
|
||||
port number matches.
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
|
||||
{
|
||||
unsigned long hash;
|
||||
unsigned long ip = remote_addr->ip_addr;
|
||||
unsigned short port = remote_addr->port;
|
||||
|
||||
assert(N_RECORDS == 256);
|
||||
|
||||
/* Compute hash value just by xor'ing the 4 bytes of the address together */
|
||||
hash = ip ^ (ip >> 16);
|
||||
hash = (hash ^ (hash >> 8)) & 0xff;
|
||||
|
||||
while ((records[hash].in_use) &&
|
||||
(records[hash].remote_addr.ip_addr != ip)) {
|
||||
hash++;
|
||||
if (hash == 256) hash = 0;
|
||||
}
|
||||
|
||||
if (records[hash].in_use) {
|
||||
if (records[hash].remote_addr.port == port) {
|
||||
*found = 2;
|
||||
} else {
|
||||
*found = 1;
|
||||
}
|
||||
*slot = hash;
|
||||
} else {
|
||||
*found = 0;
|
||||
*slot = hash;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Procedure to add a new server source (to which this machine will be
|
||||
a client) */
|
||||
NSR_Status
|
||||
NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params)
|
||||
{
|
||||
int slot, found;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%08lx port=%d", (unsigned long)remote_addr->ip_addr, remote_addr->port);
|
||||
#endif
|
||||
|
||||
/* Find empty bin & check that we don't have the address already */
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found) {
|
||||
return NSR_AlreadyInUse;
|
||||
} else {
|
||||
if (n_sources == MAX_SOURCES) {
|
||||
return NSR_TooManySources;
|
||||
} else {
|
||||
n_sources++;
|
||||
records[slot].remote_addr = *remote_addr;
|
||||
records[slot].in_use = 1;
|
||||
records[slot].data = NCR_GetServerInstance(remote_addr, params); /* Will need params passing through */
|
||||
return NSR_Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Procedure to add a new peer. */
|
||||
NSR_Status
|
||||
NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params)
|
||||
{
|
||||
int slot, found;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_NtpSources, "IP=%08lx port=%d", (unsigned long) remote_addr->ip_addr, remote_addr->port);
|
||||
#endif
|
||||
|
||||
/* Find empty bin & check that we don't have the address already */
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found) {
|
||||
return NSR_AlreadyInUse;
|
||||
} else {
|
||||
if (n_sources == MAX_SOURCES) {
|
||||
return NSR_TooManySources;
|
||||
} else {
|
||||
n_sources++;
|
||||
records[slot].remote_addr = *remote_addr;
|
||||
records[slot].in_use = 1;
|
||||
records[slot].data = NCR_GetPeerInstance(remote_addr, params); /* Will need params passing through */
|
||||
return NSR_Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Procedure to remove a source. We don't bother whether the port
|
||||
address is matched - we're only interested in removing a record for
|
||||
the right IP address. Thus the caller can specify the port number
|
||||
as zero if it wishes. */
|
||||
NSR_Status
|
||||
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
int slot, found;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (!found) {
|
||||
return NSR_NoSuchSource;
|
||||
} else {
|
||||
n_sources--;
|
||||
records[slot].in_use = 0;
|
||||
NCR_DestroyInstance(records[slot].data);
|
||||
return NSR_Success;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This routine is called by ntp_io when a new packet arrives off the network.*/
|
||||
void
|
||||
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
int slot, found;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_NtpSources, "from (%s,%d) at %s",
|
||||
UTI_IPToDottedQuad(remote_addr->ip_addr),
|
||||
remote_addr->port, UTI_TimevalToString(now));
|
||||
#endif
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found == 2) { /* Must match IP address AND port number */
|
||||
NCR_ProcessNoauthKnown(message, now, records[slot].data);
|
||||
} else {
|
||||
NCR_ProcessNoauthUnknown(message, now, remote_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
|
||||
void
|
||||
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
int slot, found;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
find_slot(remote_addr, &slot, &found);
|
||||
if (found == 2) {
|
||||
NCR_ProcessAuthKnown(message, now, records[slot].data);
|
||||
} else {
|
||||
NCR_ProcessAuthUnknown(message, now, remote_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
slew_sources(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *anything)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
if (records[i].in_use) {
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "IP=%s dfreq=%f doff=%f",
|
||||
UTI_IPToDottedQuad(records[i].remote_addr.ip_addr), dfreq, doffset);
|
||||
#endif
|
||||
|
||||
NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_TakeSourcesOnline(unsigned long mask, unsigned long address)
|
||||
{
|
||||
int i;
|
||||
int any;
|
||||
unsigned long ip;
|
||||
|
||||
any = 0;
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
if (records[i].in_use) {
|
||||
ip = records[i].remote_addr.ip_addr;
|
||||
if ((ip & mask) == address) {
|
||||
any = 1;
|
||||
NCR_TakeSourceOnline(records[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_TakeSourcesOffline(unsigned long mask, unsigned long address)
|
||||
{
|
||||
int i;
|
||||
int any;
|
||||
unsigned long ip;
|
||||
|
||||
any = 0;
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
if (records[i].in_use) {
|
||||
ip = records[i].remote_addr.ip_addr;
|
||||
if ((ip & mask) == address) {
|
||||
any = 1;
|
||||
NCR_TakeSourceOffline(records[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_ModifyMinpoll(unsigned long address, int new_minpoll)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = address;
|
||||
addr.port = 0;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMinpoll(records[slot].data, new_minpoll);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_ModifyMaxpoll(unsigned long address, int new_maxpoll)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = address;
|
||||
addr.port = 0;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxpoll(records[slot].data, new_maxpoll);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_ModifyMaxdelay(unsigned long address, double new_max_delay)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = address;
|
||||
addr.port = 0;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxdelay(records[slot].data, new_max_delay);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_ModifyMaxdelayratio(unsigned long address, double new_max_delay_ratio)
|
||||
{
|
||||
int slot, found;
|
||||
NTP_Remote_Address addr;
|
||||
addr.ip_addr = address;
|
||||
addr.port = 0;
|
||||
|
||||
find_slot(&addr, &slot, &found);
|
||||
if (found == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NCR_ModifyMaxdelayratio(records[slot].data, new_max_delay_ratio);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
|
||||
unsigned long mask, unsigned long address)
|
||||
{
|
||||
int i;
|
||||
int any;
|
||||
unsigned long ip;
|
||||
|
||||
any = 0;
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
if (records[i].in_use) {
|
||||
ip = records[i].remote_addr.ip_addr;
|
||||
if ((ip & mask) == address) {
|
||||
any = 1;
|
||||
NCR_InitiateSampleBurst(records[i].data, n_good_samples, n_total_samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* The ip address is assumed to be completed on input, that is how we
|
||||
identify the source record. */
|
||||
|
||||
void
|
||||
NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
|
||||
{
|
||||
NTP_Remote_Address rem_addr;
|
||||
int slot, found;
|
||||
|
||||
rem_addr.ip_addr = report->ip_addr;
|
||||
rem_addr.port = 0;
|
||||
find_slot(&rem_addr, &slot, &found);
|
||||
if (found) {
|
||||
NCR_ReportSource(records[slot].data, report, now);
|
||||
} else {
|
||||
report->poll = 0;
|
||||
report->latest_meas_ago = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_GetActivityReport(RPT_ActivityReport *report)
|
||||
{
|
||||
int i;
|
||||
|
||||
report->online = 0;
|
||||
report->offline = 0;
|
||||
report->burst_online = 0;
|
||||
report->burst_offline = 0;
|
||||
|
||||
for (i=0; i<N_RECORDS; i++) {
|
||||
if (records[i].in_use) {
|
||||
NCR_IncrementActivityCounters(records[i].data, &report->online, &report->offline,
|
||||
&report->burst_online, &report->burst_offline);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
99
ntp_sources.h
Normal file
99
ntp_sources.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/ntp_sources.h,v 1.12 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header for the part of the software that deals with the set of
|
||||
current NTP servers and peers, which can resolve an IP address into
|
||||
a source record for further processing.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_SOURCES_H
|
||||
#define GOT_NTP_SOURCES_H
|
||||
|
||||
#include "ntp.h"
|
||||
#include "addressing.h"
|
||||
#include "srcparams.h"
|
||||
#include "ntp_core.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* Status values returned by operations that indirectly result from user
|
||||
input. */
|
||||
typedef enum {
|
||||
NSR_Success, /* Operation successful */
|
||||
NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */
|
||||
NSR_AlreadyInUse, /* AddServer, AddPeer - attempt to add a source that is already known */
|
||||
NSR_TooManySources /* AddServer, AddPeer - too many sources already present */
|
||||
} NSR_Status;
|
||||
|
||||
/* Procedure to add a new server source (to which this machine will be
|
||||
a client) */
|
||||
extern NSR_Status NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params);
|
||||
|
||||
/* Procedure to add a new peer source. We will use symmetric active
|
||||
mode packets when communicating with this source */
|
||||
extern NSR_Status NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params);
|
||||
|
||||
/* Procedure to remove a source */
|
||||
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet arrives off the network */
|
||||
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
|
||||
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* Initialisation function */
|
||||
extern void NSR_Initialise(void);
|
||||
|
||||
/* Finalisation function */
|
||||
extern void NSR_Finalise(void);
|
||||
|
||||
/* This routine is used to indicate that sources whose IP addresses
|
||||
match a particular subnet should be set online again. Returns a
|
||||
flag indicating whether any hosts matched the address */
|
||||
extern int NSR_TakeSourcesOnline(unsigned long mask, unsigned long address);
|
||||
|
||||
/* This routine is used to indicate that sources whose IP addresses
|
||||
match a particular subnet should be set offline. Returns a flag
|
||||
indicating whether any hosts matched the address */
|
||||
extern int NSR_TakeSourcesOffline(unsigned long mask, unsigned long address);
|
||||
|
||||
extern int NSR_ModifyMinpoll(unsigned long address, int new_minpoll);
|
||||
|
||||
extern int NSR_ModifyMaxpoll(unsigned long address, int new_maxpoll);
|
||||
|
||||
extern int NSR_ModifyMaxdelay(unsigned long address, double new_max_delay);
|
||||
|
||||
extern int NSR_ModifyMaxdelayratio(unsigned long address, double new_max_delay_ratio);
|
||||
|
||||
extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, unsigned long mask, unsigned long address);
|
||||
|
||||
extern void NSR_ReportSource(RPT_SourceReport *report, struct timeval *now);
|
||||
|
||||
extern void NSR_GetActivityReport(RPT_ActivityReport *report);
|
||||
|
||||
#endif /* GOT_NTP_SOURCES_H */
|
||||
240
pktlength.c
Normal file
240
pktlength.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/pktlength.c,v 1.12 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines to compute the expected length of a command or reply packet.
|
||||
These operate on the RAW NETWORK packets, from the point of view of
|
||||
integer endianness within the structures.
|
||||
|
||||
*/
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "pktlength.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
PKL_CommandLength(CMD_Request *r)
|
||||
{
|
||||
int type;
|
||||
type = ntohs(r->command);
|
||||
if (type < 0 || type >= N_REQUEST_TYPES) {
|
||||
return 0;
|
||||
} else {
|
||||
switch (type) {
|
||||
|
||||
case REQ_NULL:
|
||||
return offsetof(CMD_Request, data);
|
||||
case REQ_ONLINE:
|
||||
return offsetof(CMD_Request, data.online.EOR);
|
||||
case REQ_OFFLINE:
|
||||
return offsetof(CMD_Request, data.offline.EOR);
|
||||
case REQ_BURST:
|
||||
return offsetof(CMD_Request, data.burst.EOR);
|
||||
case REQ_MODIFY_MINPOLL:
|
||||
return offsetof(CMD_Request, data.modify_minpoll.EOR);
|
||||
case REQ_MODIFY_MAXPOLL:
|
||||
return offsetof(CMD_Request, data.modify_maxpoll.EOR);
|
||||
case REQ_DUMP:
|
||||
return offsetof(CMD_Request, data.dump.EOR);
|
||||
case REQ_MODIFY_MAXDELAY:
|
||||
return offsetof(CMD_Request, data.modify_maxdelay.EOR);
|
||||
case REQ_MODIFY_MAXDELAYRATIO:
|
||||
return offsetof(CMD_Request, data.modify_maxdelayratio.EOR);
|
||||
case REQ_MODIFY_MAXUPDATESKEW:
|
||||
return offsetof(CMD_Request, data.modify_maxupdateskew.EOR);
|
||||
case REQ_LOGON :
|
||||
return offsetof(CMD_Request, data.logon.EOR);
|
||||
case REQ_SETTIME :
|
||||
return offsetof(CMD_Request, data.settime.EOR);
|
||||
case REQ_LOCAL :
|
||||
return offsetof(CMD_Request, data.local.EOR);
|
||||
case REQ_MANUAL :
|
||||
return offsetof(CMD_Request, data.manual.EOR);
|
||||
case REQ_N_SOURCES :
|
||||
return offsetof(CMD_Request, data.n_sources.EOR);
|
||||
case REQ_SOURCE_DATA :
|
||||
return offsetof(CMD_Request, data.source_data.EOR);
|
||||
case REQ_REKEY :
|
||||
return offsetof(CMD_Request, data.rekey.EOR);
|
||||
case REQ_ALLOW :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_ALLOWALL :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_DENY :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_DENYALL :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_CMDALLOW :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_CMDALLOWALL :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_CMDDENY :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_CMDDENYALL :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_ACCHECK :
|
||||
return offsetof(CMD_Request, data.ac_check.EOR);
|
||||
case REQ_CMDACCHECK :
|
||||
return offsetof(CMD_Request, data.ac_check.EOR);
|
||||
case REQ_ADD_SERVER :
|
||||
return offsetof(CMD_Request, data.ntp_source.EOR);
|
||||
case REQ_ADD_PEER :
|
||||
return offsetof(CMD_Request, data.ntp_source.EOR);
|
||||
case REQ_DEL_SOURCE :
|
||||
return offsetof(CMD_Request, data.del_source.EOR);
|
||||
case REQ_WRITERTC :
|
||||
return offsetof(CMD_Request, data.writertc.EOR);
|
||||
case REQ_DFREQ :
|
||||
return offsetof(CMD_Request, data.dfreq.EOR);
|
||||
case REQ_DOFFSET :
|
||||
return offsetof(CMD_Request, data.doffset.EOR);
|
||||
case REQ_TRACKING :
|
||||
return offsetof(CMD_Request, data.tracking.EOR);
|
||||
case REQ_SOURCESTATS :
|
||||
return offsetof(CMD_Request, data.sourcestats.EOR);
|
||||
case REQ_RTCREPORT :
|
||||
return offsetof(CMD_Request, data.rtcreport.EOR);
|
||||
case REQ_TRIMRTC :
|
||||
return offsetof(CMD_Request, data.trimrtc.EOR);
|
||||
case REQ_CYCLELOGS :
|
||||
return offsetof(CMD_Request, data.cyclelogs.EOR);
|
||||
case REQ_SUBNETS_ACCESSED :
|
||||
{
|
||||
unsigned long ns;
|
||||
ns = ntohl(r->data.subnets_accessed.n_subnets);
|
||||
return (offsetof(CMD_Request, data.subnets_accessed.subnets) +
|
||||
ns * sizeof(REQ_SubnetsAccessed_Subnet));
|
||||
}
|
||||
case REQ_CLIENT_ACCESSES:
|
||||
{
|
||||
unsigned long nc;
|
||||
nc = ntohl(r->data.client_accesses.n_clients);
|
||||
return (offsetof(CMD_Request, data.client_accesses.client_ips) +
|
||||
nc * sizeof(unsigned long));
|
||||
}
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX:
|
||||
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
|
||||
case REQ_MANUAL_LIST:
|
||||
return offsetof(CMD_Request, data.manual_list.EOR);
|
||||
case REQ_MANUAL_DELETE:
|
||||
return offsetof(CMD_Request, data.manual_delete.EOR);
|
||||
case REQ_MAKESTEP:
|
||||
return offsetof(CMD_Request, data.make_step.EOR);
|
||||
case REQ_ACTIVITY:
|
||||
return offsetof(CMD_Request, data.activity.EOR);
|
||||
default:
|
||||
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch-all case */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
PKL_ReplyLength(CMD_Reply *r)
|
||||
{
|
||||
int type;
|
||||
type = ntohs(r->reply);
|
||||
/* Note that reply type codes start from 1, not 0 */
|
||||
if (type < 1 || type >= N_REPLY_TYPES) {
|
||||
return 0;
|
||||
} else {
|
||||
switch (type) {
|
||||
case RPY_NULL:
|
||||
return offsetof(CMD_Reply, data.null.EOR);
|
||||
case RPY_N_SOURCES:
|
||||
return offsetof(CMD_Reply, data.n_sources.EOR);
|
||||
case RPY_SOURCE_DATA:
|
||||
return offsetof(CMD_Reply, data.source_data.EOR);
|
||||
case RPY_MANUAL_TIMESTAMP:
|
||||
return offsetof(CMD_Reply, data.manual_timestamp.EOR);
|
||||
case RPY_TRACKING:
|
||||
return offsetof(CMD_Reply, data.tracking.EOR);
|
||||
case RPY_SOURCESTATS:
|
||||
return offsetof(CMD_Reply, data.sourcestats.EOR);
|
||||
case RPY_RTC:
|
||||
return offsetof(CMD_Reply, data.rtc.EOR);
|
||||
case RPY_SUBNETS_ACCESSED :
|
||||
{
|
||||
unsigned long ns = ntohl(r->data.subnets_accessed.n_subnets);
|
||||
if (r->status == htons(STT_SUCCESS)) {
|
||||
return (offsetof(CMD_Reply, data.subnets_accessed.subnets) +
|
||||
ns * sizeof(RPY_SubnetsAccessed_Subnet));
|
||||
} else {
|
||||
return offsetof(CMD_Reply, data);
|
||||
}
|
||||
}
|
||||
case RPY_CLIENT_ACCESSES:
|
||||
{
|
||||
unsigned long nc = ntohl(r->data.client_accesses.n_clients);
|
||||
if (r->status == htons(STT_SUCCESS)) {
|
||||
return (offsetof(CMD_Reply, data.client_accesses.clients) +
|
||||
nc * sizeof(RPY_ClientAccesses_Client));
|
||||
} else {
|
||||
return offsetof(CMD_Reply, data);
|
||||
}
|
||||
}
|
||||
case RPY_CLIENT_ACCESSES_BY_INDEX:
|
||||
{
|
||||
unsigned long nc = ntohl(r->data.client_accesses_by_index.n_clients);
|
||||
if (r->status == htons(STT_SUCCESS)) {
|
||||
return (offsetof(CMD_Reply, data.client_accesses_by_index.clients) +
|
||||
nc * sizeof(RPY_ClientAccesses_Client));
|
||||
} else {
|
||||
return offsetof(CMD_Reply, data);
|
||||
}
|
||||
}
|
||||
case RPY_MANUAL_LIST:
|
||||
{
|
||||
unsigned long ns = ntohl(r->data.manual_list.n_samples);
|
||||
if (r->status == htons(STT_SUCCESS)) {
|
||||
return (offsetof(CMD_Reply, data.manual_list.samples) +
|
||||
ns * sizeof(RPY_ManualListSample));
|
||||
} else {
|
||||
return offsetof(CMD_Reply, data);
|
||||
}
|
||||
}
|
||||
case RPY_ACTIVITY:
|
||||
return offsetof(CMD_Reply, data.activity.EOR);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
42
pktlength.h
Normal file
42
pktlength.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/pktlength.h,v 1.4 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header for pktlength.c, routines for working out the expected length
|
||||
of a network command/reply packet.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_PKTLENGTH_H
|
||||
#define GOT_PKTLENGTH_H
|
||||
|
||||
#include "candm.h"
|
||||
|
||||
extern int PKL_CommandLength(CMD_Request *r);
|
||||
|
||||
extern int PKL_ReplyLength(CMD_Reply *r);
|
||||
|
||||
#endif /* GOT_PKTLENGTH_H */
|
||||
709
reference.c
Normal file
709
reference.c
Normal file
@@ -0,0 +1,709 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/reference.c,v 1.40 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This module keeps track of the source which we are claiming to be
|
||||
our reference, for the purposes of generating outgoing NTP packets */
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "reference.h"
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "local.h"
|
||||
#include "mkdirpp.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int are_we_synchronised;
|
||||
static int enable_local_stratum;
|
||||
static int local_stratum;
|
||||
static NTP_Leap our_leap_status;
|
||||
static int our_stratum;
|
||||
static unsigned long our_ref_id;
|
||||
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
|
||||
static double our_offset;
|
||||
static double our_skew;
|
||||
static double our_residual_freq;
|
||||
static double our_root_delay;
|
||||
static double our_root_dispersion;
|
||||
|
||||
static double max_update_skew;
|
||||
|
||||
/* Flag indicating that we are initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
/* Flag and threshold for logging clock changes to syslog */
|
||||
static int do_log_change;
|
||||
static double log_change_threshold;
|
||||
|
||||
/* Flag, threshold and user for sending mail notification on large clock changes */
|
||||
static int do_mail_change;
|
||||
static double mail_change_threshold;
|
||||
static char *mail_change_user;
|
||||
|
||||
/* Filename of the drift file. */
|
||||
static char *drift_file=NULL;
|
||||
|
||||
static void update_drift_file(double, double);
|
||||
|
||||
#define MAIL_PROGRAM "/usr/lib/sendmail"
|
||||
|
||||
/* ================================================== */
|
||||
/* File to which statistics are logged, NULL if none */
|
||||
static FILE *logfile = NULL;
|
||||
static char *logfilename = NULL;
|
||||
static unsigned long logwrites = 0;
|
||||
|
||||
#define TRACKING_LOG "tracking.log"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Day number of 1 Jan 1970 */
|
||||
#define MJD_1970 40587
|
||||
|
||||
/* Reference ID supplied when we are locally referenced */
|
||||
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_Initialise(void)
|
||||
{
|
||||
char *direc;
|
||||
FILE *in;
|
||||
char line[1024];
|
||||
double file_freq_ppm, file_skew_ppm;
|
||||
double our_frequency_ppm;
|
||||
|
||||
are_we_synchronised = 0;
|
||||
our_leap_status = LEAP_Normal;
|
||||
initialised = 1;
|
||||
our_root_dispersion = 1.0;
|
||||
our_root_delay = 1.0;
|
||||
our_frequency_ppm = 0.0;
|
||||
our_skew = 1.0; /* i.e. rather bad */
|
||||
our_residual_freq = 0.0;
|
||||
|
||||
/* Now see if we can get the drift file opened */
|
||||
drift_file = CNF_GetDriftFile();
|
||||
if (drift_file) {
|
||||
in = fopen(drift_file, "r");
|
||||
if (in) {
|
||||
if (fgets(line, sizeof(line), in)) {
|
||||
if (sscanf(line, "%lf%lf", &file_freq_ppm, &file_skew_ppm) == 2) {
|
||||
/* We have read valid data */
|
||||
our_frequency_ppm = file_freq_ppm;
|
||||
our_skew = 1.0e-6 * file_skew_ppm;
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not parse valid frequency and skew from driftfile %s",
|
||||
drift_file);
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not read valid frequency and skew from driftfile %s",
|
||||
drift_file);
|
||||
}
|
||||
fclose(in);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not open driftfile %s for reading",
|
||||
drift_file);
|
||||
}
|
||||
|
||||
update_drift_file(our_frequency_ppm,our_skew);
|
||||
}
|
||||
|
||||
LCL_SetAbsoluteFrequency(our_frequency_ppm);
|
||||
|
||||
if (CNF_GetLogTracking()) {
|
||||
direc = CNF_GetLogDir();
|
||||
if (!mkdir_and_parents(direc)) {
|
||||
LOG(LOGS_ERR, LOGF_Reference, "Could not create directory %s", direc);
|
||||
logfile = NULL;
|
||||
} else {
|
||||
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(TRACKING_LOG));
|
||||
strcpy(logfilename, direc);
|
||||
strcat(logfilename, "/");
|
||||
strcat(logfilename, TRACKING_LOG);
|
||||
logfile = fopen(logfilename, "a");
|
||||
if (!logfile) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Couldn't open logfile %s for update", logfilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
|
||||
|
||||
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
|
||||
|
||||
CNF_GetLogChange(&do_log_change, &log_change_threshold);
|
||||
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
|
||||
|
||||
/* And just to prevent anything wierd ... */
|
||||
if (do_log_change) {
|
||||
log_change_threshold = fabs(log_change_threshold);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_Finalise(void)
|
||||
{
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
}
|
||||
|
||||
initialised = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
Sqr(double x)
|
||||
{
|
||||
return x*x;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
#if 0
|
||||
static double
|
||||
Cube(double x)
|
||||
{
|
||||
return x*x*x;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
/* Update the drift coefficients to the file. */
|
||||
|
||||
static void
|
||||
update_drift_file(double freq_ppm, double skew)
|
||||
{
|
||||
struct stat buf;
|
||||
char *temp_drift_file;
|
||||
FILE *out;
|
||||
|
||||
/* Create a temporary file with a '.tmp' extension. */
|
||||
|
||||
temp_drift_file = (char*) Malloc(strlen(drift_file)+8);
|
||||
|
||||
if(!temp_drift_file) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(temp_drift_file,drift_file);
|
||||
strcat(temp_drift_file,".tmp");
|
||||
|
||||
out = fopen(temp_drift_file, "w");
|
||||
if (!out) {
|
||||
Free(temp_drift_file);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not open temporary driftfile %s.tmp for writing",
|
||||
drift_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write the frequency and skew parameters in ppm */
|
||||
fprintf(out, "%20.4f %20.4f\n", freq_ppm, 1.0e6 * skew);
|
||||
|
||||
fclose(out);
|
||||
|
||||
/* Clone the file attributes from the existing file if there is one. */
|
||||
|
||||
if (!stat(drift_file,&buf)) {
|
||||
chown(temp_drift_file,buf.st_uid,buf.st_gid);
|
||||
chmod(temp_drift_file,buf.st_mode&0777);
|
||||
}
|
||||
|
||||
/* Rename the temporary file to the correct location (see rename(2) for details). */
|
||||
|
||||
if (rename(temp_drift_file,drift_file)) {
|
||||
unlink(temp_drift_file);
|
||||
Free(temp_drift_file);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not replace old driftfile %s with new one %s.tmp (%d)",
|
||||
drift_file,drift_file);
|
||||
return;
|
||||
}
|
||||
|
||||
Free(temp_drift_file);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define BUFLEN 255
|
||||
#define S_MAX_USER_LEN "128"
|
||||
|
||||
static void
|
||||
maybe_log_offset(double offset)
|
||||
{
|
||||
double abs_offset;
|
||||
FILE *p;
|
||||
char buffer[BUFLEN], host[BUFLEN];
|
||||
time_t now;
|
||||
struct tm stm;
|
||||
|
||||
abs_offset = fabs(offset);
|
||||
|
||||
if (do_log_change &&
|
||||
(abs_offset > log_change_threshold)) {
|
||||
LOG(LOGS_WARN, LOGF_Reference,
|
||||
"System clock wrong by %.6f seconds, adjustment started",
|
||||
-offset);
|
||||
}
|
||||
|
||||
if (do_mail_change &&
|
||||
(abs_offset > mail_change_threshold)) {
|
||||
sprintf(buffer, "%s %." S_MAX_USER_LEN "s", MAIL_PROGRAM, mail_change_user);
|
||||
p = popen(buffer, "w");
|
||||
if (p) {
|
||||
if (gethostname(host, sizeof(host)) < 0) {
|
||||
strcpy(host, "<UNKNOWN>");
|
||||
}
|
||||
fprintf(p, "Subject: chronyd reports change to system clock on node [%s]\n", host);
|
||||
fputs("\n", p);
|
||||
now = time(NULL);
|
||||
stm = *localtime(&now);
|
||||
strftime(buffer, sizeof(buffer), "On %A, %d %B %Y\n with the system clock reading %H:%M:%S (%Z)", &stm);
|
||||
fputs(buffer, p);
|
||||
/* If offset < 0 the local clock is slow, so we are applying a
|
||||
positive change to it to bring it into line, hence the
|
||||
negation of 'offset' in the next statement (and earlier) */
|
||||
fprintf(p,
|
||||
"\n\nchronyd started to apply an adjustment of %.3f seconds to it,\n"
|
||||
" which exceeded the reporting threshold of %.3f seconds\n\n",
|
||||
-offset, mail_change_threshold);
|
||||
pclose(p);
|
||||
} else {
|
||||
LOG(LOGS_ERR, LOGF_Reference,
|
||||
"Could not send mail notification to user %s\n",
|
||||
mail_change_user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
void
|
||||
REF_SetReference(int stratum,
|
||||
NTP_Leap leap,
|
||||
unsigned long ref_id,
|
||||
struct timeval *ref_time,
|
||||
double offset,
|
||||
double frequency,
|
||||
double skew,
|
||||
double root_delay,
|
||||
double root_dispersion
|
||||
)
|
||||
{
|
||||
double previous_skew, new_skew;
|
||||
double previous_freq, new_freq;
|
||||
double old_weight, new_weight, sum_weight;
|
||||
double delta_freq1, delta_freq2;
|
||||
double skew1, skew2;
|
||||
double our_frequency;
|
||||
|
||||
double abs_freq_ppm;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
/* If we get a serious rounding error in the source stats regression
|
||||
processing, there is a remote chance that the skew argument is a
|
||||
'not a number'. If such a quantity gets propagated into the
|
||||
machine's kernel clock variables, nasty things will happen ..
|
||||
|
||||
To guard against this we need to check whether the skew argument
|
||||
is a reasonable real number. I don't think isnan, isinf etc are
|
||||
platform independent, so the following algorithm is used. */
|
||||
|
||||
{
|
||||
double t;
|
||||
t = (skew + skew) / skew; /* Skew shouldn't be zero either */
|
||||
if ((t < 1.9) || (t > 2.1)) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Bogus skew value encountered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
are_we_synchronised = 1;
|
||||
our_stratum = stratum + 1;
|
||||
our_leap_status = leap;
|
||||
our_ref_id = ref_id;
|
||||
our_ref_time = *ref_time;
|
||||
our_offset = offset;
|
||||
our_root_delay = root_delay;
|
||||
our_root_dispersion = root_dispersion;
|
||||
|
||||
/* Eliminate updates that are based on totally unreliable frequency
|
||||
information */
|
||||
|
||||
if (fabs(skew) < max_update_skew) {
|
||||
|
||||
previous_skew = our_skew;
|
||||
new_skew = skew;
|
||||
|
||||
previous_freq = 0.0; /* We assume that the local clock is running
|
||||
according to our previously determined
|
||||
value; note that this is a delta frequency
|
||||
--- absolute frequencies are only known in
|
||||
the local module. */
|
||||
new_freq = frequency;
|
||||
|
||||
/* Set new frequency based on weighted average of old and new skew. */
|
||||
|
||||
old_weight = 1.0 / Sqr(previous_skew);
|
||||
new_weight = 3.0 / Sqr(new_skew);
|
||||
|
||||
sum_weight = old_weight + new_weight;
|
||||
|
||||
our_frequency = (previous_freq * old_weight + new_freq * new_weight) / sum_weight;
|
||||
|
||||
delta_freq1 = previous_freq - our_frequency;
|
||||
delta_freq2 = new_freq - our_frequency;
|
||||
|
||||
skew1 = sqrt((Sqr(delta_freq1) * old_weight + Sqr(delta_freq2) * new_weight) / sum_weight);
|
||||
skew2 = (previous_skew * old_weight + new_skew * new_weight) / sum_weight;
|
||||
our_skew = skew1 + skew2;
|
||||
|
||||
our_residual_freq = new_freq - our_frequency;
|
||||
|
||||
maybe_log_offset(our_offset);
|
||||
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset);
|
||||
|
||||
} else {
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
|
||||
#endif
|
||||
maybe_log_offset(our_offset);
|
||||
LCL_AccumulateOffset(our_offset);
|
||||
|
||||
our_residual_freq = frequency;
|
||||
}
|
||||
|
||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
if (logfile) {
|
||||
|
||||
if (((logwrites++) % 32) == 0) {
|
||||
fprintf(logfile,
|
||||
"=======================================================================\n"
|
||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset\n"
|
||||
"=======================================================================\n");
|
||||
}
|
||||
|
||||
fprintf(logfile, "%s %-15s %2d %10.3f %10.3f %10.3e\n",
|
||||
UTI_TimeToLogForm(ref_time->tv_sec),
|
||||
UTI_IPToDottedQuad(our_ref_id),
|
||||
our_stratum,
|
||||
abs_freq_ppm,
|
||||
1.0e6*our_skew,
|
||||
our_offset);
|
||||
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
if (drift_file) {
|
||||
update_drift_file(abs_freq_ppm, our_skew);
|
||||
}
|
||||
|
||||
/* And now set the freq and offset to zero */
|
||||
our_frequency = 0.0;
|
||||
our_offset = 0.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_SetManualReference
|
||||
(
|
||||
struct timeval *ref_time,
|
||||
double offset,
|
||||
double frequency,
|
||||
double skew
|
||||
)
|
||||
{
|
||||
int millisecond;
|
||||
double abs_freq_ppm;
|
||||
|
||||
/* We are not synchronised to an external source, as such. This is
|
||||
only supposed to be used with the local source option, really
|
||||
... */
|
||||
are_we_synchronised = 0;
|
||||
|
||||
our_skew = skew;
|
||||
our_residual_freq = 0.0;
|
||||
|
||||
maybe_log_offset(offset);
|
||||
LCL_AccumulateFrequencyAndOffset(frequency, offset);
|
||||
|
||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
if (logfile) {
|
||||
millisecond = ref_time->tv_usec / 1000;
|
||||
|
||||
fprintf(logfile, "%5s %-15s %2d %10.3f %10.3f %10.3e\n",
|
||||
UTI_TimeToLogForm(ref_time->tv_sec),
|
||||
"127.127.1.1",
|
||||
our_stratum,
|
||||
abs_freq_ppm,
|
||||
1.0e6*our_skew,
|
||||
our_offset);
|
||||
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
if (drift_file) {
|
||||
update_drift_file(abs_freq_ppm, our_skew);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_SetUnsynchronised(void)
|
||||
{
|
||||
/* Variables required for logging to statistics log */
|
||||
int millisecond;
|
||||
struct timeval now;
|
||||
double local_clock_err;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (logfile) {
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
|
||||
millisecond = now.tv_usec / 1000;
|
||||
|
||||
fprintf(logfile, "%s %-15s 0 %10.3f %10.3f %10.3e\n",
|
||||
UTI_TimeToLogForm(now.tv_sec),
|
||||
"0.0.0.0",
|
||||
LCL_ReadAbsoluteFrequency(),
|
||||
1.0e6*our_skew,
|
||||
0.0);
|
||||
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
are_we_synchronised = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_GetReferenceParams
|
||||
(
|
||||
struct timeval *local_time,
|
||||
int *is_synchronised,
|
||||
NTP_Leap *leap_status,
|
||||
int *stratum,
|
||||
unsigned long *ref_id,
|
||||
struct timeval *ref_time,
|
||||
double *root_delay,
|
||||
double *root_dispersion
|
||||
)
|
||||
{
|
||||
double elapsed;
|
||||
double extra_dispersion;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (are_we_synchronised) {
|
||||
|
||||
*is_synchronised = 1;
|
||||
|
||||
*stratum = our_stratum;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, local_time, &our_ref_time);
|
||||
extra_dispersion = (our_skew + fabs(our_residual_freq)) * elapsed;
|
||||
|
||||
*leap_status = our_leap_status;
|
||||
*ref_id = our_ref_id;
|
||||
*ref_time = our_ref_time;
|
||||
*root_delay = our_root_delay;
|
||||
*root_dispersion = our_root_dispersion + extra_dispersion;
|
||||
|
||||
} else if (enable_local_stratum) {
|
||||
|
||||
*is_synchronised = 1;
|
||||
|
||||
*stratum = local_stratum;
|
||||
*ref_id = LOCAL_REFERENCE_ID;
|
||||
/* Make the reference time be now less a second - this will
|
||||
scarcely affect the client, but will ensure that the transmit
|
||||
timestamp cannot come before this (which would cause test 6 to
|
||||
fail in the client's read routine) if the local system clock's
|
||||
read routine is broken in any way. */
|
||||
*ref_time = *local_time;
|
||||
--ref_time->tv_sec;
|
||||
|
||||
/* Not much else we can do for leap second bits - maybe need to
|
||||
have a way for the administrator to feed leap bits in */
|
||||
*leap_status = LEAP_Normal;
|
||||
|
||||
*root_delay = 0.0;
|
||||
*root_dispersion = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
} else {
|
||||
|
||||
*is_synchronised = 0;
|
||||
|
||||
*leap_status = LEAP_Unsynchronised;
|
||||
*stratum = 0;
|
||||
*ref_id = 0UL;
|
||||
ref_time->tv_sec = ref_time->tv_usec = 0;
|
||||
/* These values seem to be standard for a client, and
|
||||
any peer or client of ours will ignore them anyway because
|
||||
we don't claim to be synchronised */
|
||||
*root_dispersion = 1.0;
|
||||
*root_delay = 1.0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
REF_GetOurStratum(void)
|
||||
{
|
||||
if (are_we_synchronised) {
|
||||
return our_stratum;
|
||||
} else if (enable_local_stratum) {
|
||||
return local_stratum;
|
||||
} else {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_ModifyMaxupdateskew(double new_max_update_skew)
|
||||
{
|
||||
max_update_skew = new_max_update_skew * 1.0e-6;
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Reference, "New max update skew = %.3fppm", new_max_update_skew);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_EnableLocal(int stratum)
|
||||
{
|
||||
enable_local_stratum = 1;
|
||||
local_stratum = stratum;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_DisableLocal(void)
|
||||
{
|
||||
enable_local_stratum = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
{
|
||||
double elapsed;
|
||||
double extra_dispersion;
|
||||
struct timeval now_raw, now_cooked;
|
||||
double correction;
|
||||
|
||||
LCL_ReadRawTime(&now_raw);
|
||||
correction = LCL_GetOffsetCorrection(&now_raw);
|
||||
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
|
||||
|
||||
if (are_we_synchronised) {
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time);
|
||||
extra_dispersion = (our_skew + fabs(our_residual_freq)) * elapsed;
|
||||
|
||||
rep->ref_id = our_ref_id;
|
||||
rep->stratum = our_stratum;
|
||||
rep->ref_time = our_ref_time;
|
||||
UTI_DoubleToTimeval(correction, &rep->current_correction);
|
||||
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
|
||||
rep->skew_ppm = 1.0e6 * our_skew;
|
||||
rep->root_delay = our_root_delay;
|
||||
rep->root_dispersion = our_root_dispersion + extra_dispersion;
|
||||
|
||||
} else if (enable_local_stratum) {
|
||||
|
||||
rep->ref_id = LOCAL_REFERENCE_ID;
|
||||
rep->stratum = local_stratum;
|
||||
rep->ref_time = now_cooked;
|
||||
UTI_DoubleToTimeval(correction, &rep->current_correction);
|
||||
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
rep->resid_freq_ppm = 0.0;
|
||||
rep->skew_ppm = 0.0;
|
||||
rep->root_delay = 0.0;
|
||||
rep->root_dispersion = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
} else {
|
||||
|
||||
rep->ref_id = 0UL;
|
||||
rep->stratum = 0;
|
||||
rep->ref_time.tv_sec = 0;
|
||||
rep->ref_time.tv_usec = 0;
|
||||
UTI_DoubleToTimeval(correction, &rep->current_correction);
|
||||
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
rep->resid_freq_ppm = 0.0;
|
||||
rep->skew_ppm = 0.0;
|
||||
rep->root_delay = 0.0;
|
||||
rep->root_dispersion = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_CycleLogFile(void)
|
||||
{
|
||||
if (logfile && logfilename) {
|
||||
fclose(logfile);
|
||||
logfile = fopen(logfilename, "a");
|
||||
if (!logfile) {
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Could not reopen logfile %s", logfilename);
|
||||
}
|
||||
logwrites = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
147
reference.h
Normal file
147
reference.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/reference.h,v 1.13 2002/02/28 23:27:12 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header file for the module that keeps track of the current
|
||||
reference.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_REFERENCE_H
|
||||
#define GOT_REFERENCE_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* Init function */
|
||||
extern void REF_Initialise(void);
|
||||
|
||||
/* Fini function */
|
||||
extern void REF_Finalise(void);
|
||||
|
||||
/* Function which takes a local cooked time and returns the estimated
|
||||
time of the reference. It also returns the other parameters
|
||||
required for forming the outgoing NTP packet.
|
||||
|
||||
local_time is the cooked local time returned by the LCL module
|
||||
|
||||
is_synchronised indicates whether we are synchronised to anything
|
||||
at the moment.
|
||||
|
||||
leap indicates the current leap status
|
||||
|
||||
stratum is the stratum of this machine, when considered to be sync'd to the
|
||||
reference
|
||||
|
||||
ref_id is the reference_id of the source
|
||||
|
||||
ref_time is the time at which the we last set the reference source up
|
||||
|
||||
root_delay is the root delay of the sample we are using
|
||||
|
||||
root_dispersion is the root dispersion of the sample we are using, with all the
|
||||
skew etc added on.
|
||||
|
||||
*/
|
||||
|
||||
extern void REF_GetReferenceParams
|
||||
(
|
||||
struct timeval *local_time,
|
||||
int *is_synchronised,
|
||||
NTP_Leap *leap,
|
||||
int *stratum,
|
||||
unsigned long *ref_id,
|
||||
struct timeval *ref_time,
|
||||
double *root_delay,
|
||||
double *root_dispersion
|
||||
);
|
||||
|
||||
/* Function called by the clock selection process to register a new
|
||||
reference source and its parameters
|
||||
|
||||
stratum is the stratum of the reference
|
||||
|
||||
leap is the leap status read from the source
|
||||
|
||||
ref_id is the reference id of the reference
|
||||
|
||||
ref_time is the time at which the parameters are assumed to be
|
||||
correct, in terms of local time
|
||||
|
||||
frequency is the amount of local clock gain relative to the
|
||||
reference per unit time interval of the local clock
|
||||
|
||||
skew is the maximum estimated frequency error (so we are within
|
||||
[frequency+-skew])
|
||||
|
||||
root_delay is the root delay of the sample we are using
|
||||
|
||||
root_dispersion is the root dispersion of the sample we are using
|
||||
|
||||
*/
|
||||
|
||||
extern void REF_SetReference
|
||||
(
|
||||
int stratum,
|
||||
NTP_Leap leap,
|
||||
unsigned long ref_id,
|
||||
struct timeval *ref_time,
|
||||
double offset,
|
||||
double frequency,
|
||||
double skew,
|
||||
double root_delay,
|
||||
double root_dispersion
|
||||
);
|
||||
|
||||
extern void REF_SetManualReference
|
||||
(
|
||||
struct timeval *ref_time,
|
||||
double offset,
|
||||
double frequency,
|
||||
double skew
|
||||
);
|
||||
|
||||
/* Mark the local clock as unsynchronised */
|
||||
extern void
|
||||
REF_SetUnsynchronised(void);
|
||||
|
||||
/* Return the current stratum of this host or zero if the host is not
|
||||
synchronised */
|
||||
extern int REF_GetOurStratum(void);
|
||||
|
||||
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
|
||||
extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
|
||||
|
||||
extern void REF_EnableLocal(int stratum);
|
||||
extern void REF_DisableLocal(void);
|
||||
|
||||
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
||||
|
||||
extern void REF_CycleLogFile(void);
|
||||
|
||||
#endif /* GOT_REFERENCE_H */
|
||||
628
regress.c
Normal file
628
regress.c
Normal file
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/regress.c,v 1.31 2003/01/20 22:24:20 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Regression algorithms.
|
||||
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "regress.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MAX_POINTS 128
|
||||
|
||||
void
|
||||
RGR_WeightedRegression
|
||||
(double *x, /* independent variable */
|
||||
double *y, /* measured data */
|
||||
double *w, /* weightings (large => data
|
||||
less reliable) */
|
||||
|
||||
int n, /* number of data points */
|
||||
|
||||
/* And now the results */
|
||||
|
||||
double *b0, /* estimated y axis intercept */
|
||||
double *b1, /* estimated slope */
|
||||
double *s2, /* estimated variance of data points */
|
||||
|
||||
double *sb0, /* estimated standard deviation of
|
||||
intercept */
|
||||
double *sb1 /* estimated standard deviation of
|
||||
slope */
|
||||
|
||||
/* Could add correlation stuff later if required */
|
||||
)
|
||||
{
|
||||
double P, Q, U, V, W;
|
||||
double diff;
|
||||
double u, ui, aa;
|
||||
int i;
|
||||
|
||||
if (n<3) {
|
||||
CROAK("Insufficient points");
|
||||
}
|
||||
|
||||
W = U = 0;
|
||||
for (i=0; i<n; i++) {
|
||||
U += x[i] / w[i];
|
||||
W += 1.0 / w[i];
|
||||
}
|
||||
|
||||
u = U / W;
|
||||
|
||||
/* Calculate statistics from data */
|
||||
P = Q = V = 0.0;
|
||||
for (i=0; i<n; i++) {
|
||||
ui = x[i] - u;
|
||||
P += y[i] / w[i];
|
||||
Q += y[i] * ui / w[i];
|
||||
V += ui * ui / w[i];
|
||||
}
|
||||
|
||||
*b1 = Q / V;
|
||||
*b0 = (P / W) - (*b1) * u;
|
||||
|
||||
*s2 = 0.0;
|
||||
for (i=0; i<n; i++) {
|
||||
diff = y[i] - *b0 - *b1*x[i];
|
||||
*s2 += diff*diff / w[i];
|
||||
}
|
||||
|
||||
*s2 /= (double)(n-2);
|
||||
|
||||
*sb1 = sqrt(*s2 / V);
|
||||
aa = u * (*sb1);
|
||||
*sb0 = sqrt(*s2 / W + aa * aa);
|
||||
|
||||
*s2 *= (n / W); /* Giving weighted average of variances */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Get the coefficient to multiply the standard deviation by, to get a
|
||||
particular size of confidence interval (assuming a t-distribution) */
|
||||
|
||||
double
|
||||
RGR_GetTCoef(int dof)
|
||||
{
|
||||
/* Assuming now the 99.95% quantile */
|
||||
static double coefs[] =
|
||||
{ 636.6, 31.6, 12.92, 8.61, 6.869,
|
||||
5.959, 5.408, 5.041, 4.781, 4.587,
|
||||
4.437, 4.318, 4.221, 4.140, 4.073,
|
||||
4.015, 3.965, 3.922, 3.883, 3.850,
|
||||
3.819, 3.792, 3.768, 3.745, 3.725,
|
||||
3.707, 3.690, 3.674, 3.659, 3.646,
|
||||
3.633, 3.622, 3.611, 3.601, 3.591,
|
||||
3.582, 3.574, 3.566, 3.558, 3.551};
|
||||
|
||||
if (dof <= 40) {
|
||||
return coefs[dof-1];
|
||||
} else {
|
||||
return 3.5; /* Until I can be bothered to do something better */
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Structure used for holding results of each regression */
|
||||
|
||||
typedef struct {
|
||||
double variance;
|
||||
double slope_sd;
|
||||
double slope;
|
||||
double offset;
|
||||
double offset_sd;
|
||||
double K2; /* Variance / slope_var */
|
||||
int n; /* Number of points */
|
||||
int dof; /* Number of degrees of freedom */
|
||||
} RegressionResult;
|
||||
|
||||
/* ================================================== */
|
||||
/* Critical value for number of runs of residuals with same sign. 10%
|
||||
critical region for now */
|
||||
|
||||
static int critical_runs10[] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 6, 6, 7, 7,
|
||||
7, 8, 8, 9, 9, 10, 10, 10, 11, 11,
|
||||
12, 12, 13, 13, 14, 14, 14, 15, 15, 16,
|
||||
16, 17, 17, 18, 18, 18, 19, 19, 20, 20,
|
||||
|
||||
/* Note that 66 onwards are bogus - I haven't worked out the
|
||||
critical values */
|
||||
21, 21, 22, 22, 23, 23, 23, 24, 24, 25,
|
||||
25, 26, 26, 27, 27, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
n_runs_from_residuals(double *resid, int n)
|
||||
{
|
||||
int nruns;
|
||||
int i;
|
||||
|
||||
nruns = 1;
|
||||
for (i=1; i<n; i++) {
|
||||
if (((resid[i-1] < 0.0) && (resid[i] < 0.0)) ||
|
||||
((resid[i-1] > 0.0) && (resid[i] > 0.0))) {
|
||||
/* Nothing to do */
|
||||
} else {
|
||||
nruns++;
|
||||
}
|
||||
}
|
||||
|
||||
return nruns;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return a boolean indicating whether we had enough points for
|
||||
regression */
|
||||
|
||||
#define RESID_SIZE 1024
|
||||
#define MIN_SAMPLES_FOR_REGRESS 3
|
||||
|
||||
int
|
||||
RGR_FindBestRegression
|
||||
(double *x, /* independent variable */
|
||||
double *y, /* measured data */
|
||||
double *w, /* weightings (large => data
|
||||
less reliable) */
|
||||
|
||||
int n, /* number of data points */
|
||||
|
||||
/* And now the results */
|
||||
|
||||
double *b0, /* estimated y axis intercept */
|
||||
double *b1, /* estimated slope */
|
||||
double *s2, /* estimated variance of data points */
|
||||
|
||||
double *sb0, /* estimated standard deviation of
|
||||
intercept */
|
||||
double *sb1, /* estimated standard deviation of
|
||||
slope */
|
||||
|
||||
int *new_start, /* the new starting index to make the
|
||||
residuals pass the two tests */
|
||||
|
||||
int *n_runs, /* number of runs amongst the residuals */
|
||||
|
||||
int *dof /* degrees of freedom in statistics (needed
|
||||
to get confidence intervals later) */
|
||||
|
||||
)
|
||||
{
|
||||
double P, Q, U, V, W; /* total */
|
||||
double resid[RESID_SIZE];
|
||||
double ss;
|
||||
double a, b, u, ui, aa;
|
||||
|
||||
int start, nruns, npoints, npoints_left;
|
||||
int i;
|
||||
|
||||
if (n < MIN_SAMPLES_FOR_REGRESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
start = 0;
|
||||
do {
|
||||
|
||||
W = U = 0;
|
||||
for (i=start; i<n; i++) {
|
||||
U += x[i] / w[i];
|
||||
W += 1.0 / w[i];
|
||||
}
|
||||
|
||||
u = U / W;
|
||||
|
||||
P = Q = V = 0.0;
|
||||
for (i=start; i<n; i++) {
|
||||
ui = x[i] - u;
|
||||
P += y[i] / w[i];
|
||||
Q += y[i] * ui / w[i];
|
||||
V += ui * ui / w[i];
|
||||
}
|
||||
|
||||
npoints = n - start;
|
||||
b = Q / V;
|
||||
a = (P / W) - (b * u);
|
||||
|
||||
for (i=start; i<n; i++) {
|
||||
resid[i] = y[i] - a - b*x[i];
|
||||
}
|
||||
|
||||
/* Count number of runs */
|
||||
nruns = n_runs_from_residuals(resid + start, npoints);
|
||||
|
||||
npoints_left = n - start - 1;
|
||||
|
||||
if ((nruns > critical_runs10[npoints]) || (npoints_left < MIN_SAMPLES_FOR_REGRESS)) {
|
||||
break;
|
||||
} else {
|
||||
/* Try dropping one sample at a time until the runs test passes. */
|
||||
++start;
|
||||
}
|
||||
|
||||
} while (1);
|
||||
|
||||
/* Work out statistics from full dataset */
|
||||
*b1 = b;
|
||||
*b0 = a;
|
||||
|
||||
ss = 0.0;
|
||||
for (i=start; i<n; i++) {
|
||||
ss += resid[i]*resid[i] / w[i];
|
||||
}
|
||||
|
||||
npoints = n - start;
|
||||
ss /= (double)(npoints - 2);
|
||||
*sb1 = sqrt(ss / V);
|
||||
aa = u * (*sb1);
|
||||
*sb0 = sqrt((ss / W) + (aa * aa));
|
||||
*s2 = ss * (double) npoints / W;
|
||||
|
||||
*new_start = start;
|
||||
*dof = npoints - 2;
|
||||
*n_runs = nruns;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define EXCH(a,b) temp=(a); (a)=(b); (b)=temp
|
||||
|
||||
/* ================================================== */
|
||||
/* Find the index'th biggest element in the array x of n elements.
|
||||
flags is an array where a 1 indicates that the corresponding entry
|
||||
in x is known to be sorted into its correct position and a 0
|
||||
indicates that the corresponding entry is not sorted. However, if
|
||||
flags[m] = flags[n] = 1 with m<n, then x[m] must be <= x[n] and for
|
||||
all i with m<i<n, x[m] <= x[i] <= x[n]. In practice, this means
|
||||
flags[] has to be the result of a previous call to this routine
|
||||
with the same array x, and is used to remember which parts of the
|
||||
x[] array we have already sorted.
|
||||
|
||||
The approach used is a cut-down quicksort, where we only bother to
|
||||
keep sorting the partition that contains the index we are after.
|
||||
The approach comes from Numerical Recipes in C (ISBN
|
||||
0-521-43108-5). */
|
||||
|
||||
static double
|
||||
find_ordered_entry_with_flags(double *x, int n, int index, int *flags)
|
||||
{
|
||||
int u, v, l, r;
|
||||
double temp;
|
||||
double piv;
|
||||
int pivind;
|
||||
|
||||
if (index < 0) {
|
||||
CROAK("Negative index");
|
||||
}
|
||||
|
||||
/* If this bit of the array is already sorted, simple! */
|
||||
if (flags[index]) {
|
||||
return x[index];
|
||||
}
|
||||
|
||||
/* Find subrange to look at */
|
||||
u = v = index;
|
||||
while (u > 0 && !flags[u]) u--;
|
||||
if (flags[u]) u++;
|
||||
|
||||
while (v < (n-1) && !flags[v]) v++;
|
||||
if (flags[v]) v--;
|
||||
|
||||
do {
|
||||
if (v - u < 2) {
|
||||
if (x[v] < x[u]) {
|
||||
EXCH(x[v], x[u]);
|
||||
}
|
||||
flags[v] = flags[u] = 1;
|
||||
return x[index];
|
||||
} else {
|
||||
pivind = (u + v) >> 1;
|
||||
EXCH(x[u], x[pivind]);
|
||||
piv = x[u]; /* New value */
|
||||
l = u + 1;
|
||||
r = v;
|
||||
do {
|
||||
while (x[l] < piv) l++;
|
||||
while (x[r] > piv) r--;
|
||||
if (r <= l) break;
|
||||
EXCH(x[l], x[r]);
|
||||
l++;
|
||||
r--;
|
||||
} while (1);
|
||||
EXCH(x[u], x[r]);
|
||||
flags[r] = 1; /* Pivot now in correct place */
|
||||
if (index == r) {
|
||||
return x[r];
|
||||
} else if (index < r) {
|
||||
v = r - 1;
|
||||
} else if (index > r) {
|
||||
u = l;
|
||||
} else {
|
||||
CROAK("Impossible");
|
||||
}
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if 0
|
||||
/* Not used, but this is how it can be done */
|
||||
static double
|
||||
find_ordered_entry(double *x, int n, int index)
|
||||
{
|
||||
int flags[MAX_POINTS];
|
||||
|
||||
bzero(flags, n * sizeof(int));
|
||||
return find_ordered_entry_with_flags(x, n, index, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
/* Find the median entry of an array x[] with n elements. */
|
||||
|
||||
static double
|
||||
find_median(double *x, int n)
|
||||
{
|
||||
int k;
|
||||
int flags[MAX_POINTS];
|
||||
|
||||
memset(flags, 0, n*sizeof(int));
|
||||
k = n>>1;
|
||||
if (n&1) {
|
||||
return find_ordered_entry_with_flags(x, n, k, flags);
|
||||
} else {
|
||||
return 0.5 * (find_ordered_entry_with_flags(x, n, k, flags) +
|
||||
find_ordered_entry_with_flags(x, n, k-1, flags));
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function evaluates the equation
|
||||
|
||||
\sum_{i=0}^{n-1} x_i sign(y_i - a - b x_i)
|
||||
|
||||
and chooses the value of a that minimises the absolute value of the
|
||||
result. (See pp703-704 of Numerical Recipes in C). */
|
||||
|
||||
static void
|
||||
eval_robust_residual
|
||||
(double *x, /* The independent points */
|
||||
double *y, /* The dependent points */
|
||||
int n, /* Number of points */
|
||||
double b, /* Slope */
|
||||
double *aa, /* Intercept giving smallest absolute
|
||||
value for the above equation */
|
||||
double *rr /* Corresponding value of equation */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
double a, res, del;
|
||||
double d[MAX_POINTS];
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
d[i] = y[i] - b * x[i];
|
||||
}
|
||||
|
||||
a = find_median(d, n);
|
||||
|
||||
res = 0.0;
|
||||
for (i=0; i<n; i++) {
|
||||
del = y[i] - a - b * x[i];
|
||||
if (del > 0.0) {
|
||||
res += x[i];
|
||||
} else if (del < 0.0) {
|
||||
res -= x[i];
|
||||
}
|
||||
}
|
||||
|
||||
*aa = a;
|
||||
*rr = res;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine performs a 'robust' regression, i.e. one which has low
|
||||
susceptibility to outliers amongst the data. If one thinks of a
|
||||
normal (least squares) linear regression in 2D being analogous to
|
||||
the arithmetic mean in 1D, this algorithm in 2D is roughly
|
||||
analogous to the median in 1D. This algorithm seems to work quite
|
||||
well until the number of outliers is approximately half the number
|
||||
of data points.
|
||||
|
||||
The return value is a status indicating whether there were enough
|
||||
data points to run the routine or not. */
|
||||
|
||||
int
|
||||
RGR_FindBestRobustRegression
|
||||
(double *x, /* The independent axis points */
|
||||
double *y, /* The dependent axis points (which
|
||||
may contain outliers). */
|
||||
int n, /* The number of points */
|
||||
double tol, /* The tolerance required in
|
||||
determining the value of b1 */
|
||||
double *b0, /* The estimated Y-axis intercept */
|
||||
double *b1, /* The estimated slope */
|
||||
int *n_runs, /* The number of runs of residuals */
|
||||
int *best_start /* The best starting index */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int start;
|
||||
int n_points;
|
||||
double a, b;
|
||||
double P, U, V, W, X;
|
||||
double resid, resids[MAX_POINTS];
|
||||
double blo, bhi, bmid, rlo, rhi, rmid;
|
||||
double s2, sb, incr;
|
||||
double mx, dx, my, dy;
|
||||
int nruns = 0;
|
||||
|
||||
if (n < 2) {
|
||||
return 0;
|
||||
} else if (n == 2) {
|
||||
/* Just a straight line fit (we need this for the manual mode) */
|
||||
*b1 = (y[1] - y[0]) / (x[1] - x[0]);
|
||||
*b0 = y[0] - (*b1) * x[0];
|
||||
*n_runs = 0;
|
||||
*best_start = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* else at least 3 points, apply normal algorithm */
|
||||
|
||||
start = 0;
|
||||
|
||||
/* Loop to strip oldest points that cause the regression residuals
|
||||
to fail the number of runs test */
|
||||
do {
|
||||
|
||||
n_points = n - start;
|
||||
|
||||
/* Use standard least squares regression to get starting estimate */
|
||||
|
||||
P = U = 0.0;
|
||||
for (i=start; i<n; i++) {
|
||||
P += y[i];
|
||||
U += x[i];
|
||||
}
|
||||
|
||||
W = (double) n_points;
|
||||
|
||||
my = P/W;
|
||||
mx = U/W;
|
||||
|
||||
X = V = 0.0;
|
||||
for (i=start; i<n; i++) {
|
||||
dy = y[i] - my;
|
||||
dx = x[i] - mx;
|
||||
X += dy * dx;
|
||||
V += dx * dx;
|
||||
}
|
||||
|
||||
b = X / V;
|
||||
a = my - b*mx;
|
||||
|
||||
|
||||
#if 0
|
||||
printf("my=%20.12f mx=%20.12f a=%20.12f b=%20.12f\n", my, mx, a, b);
|
||||
#endif
|
||||
|
||||
s2 = 0.0;
|
||||
for (i=start; i<n; i++) {
|
||||
resid = y[i] - a - b * x[i];
|
||||
s2 += resid * resid;
|
||||
}
|
||||
|
||||
/* Need to expand range of b to get a root in the interval.
|
||||
Estimate standard deviation of b and expand range about b based
|
||||
on that. */
|
||||
sb = sqrt(s2 * W/V);
|
||||
if (sb > 0.0) {
|
||||
incr = 3.0 * sb;
|
||||
} else {
|
||||
incr = 3.0 * tol;
|
||||
}
|
||||
|
||||
blo = b;
|
||||
bhi = b;
|
||||
|
||||
do {
|
||||
blo -= incr;
|
||||
bhi += incr;
|
||||
|
||||
/* We don't want 'a' yet */
|
||||
eval_robust_residual(x + start, y + start, n_points, blo, &a, &rlo);
|
||||
eval_robust_residual(x + start, y + start, n_points, bhi, &a, &rhi);
|
||||
|
||||
} while (rlo * rhi > 0.0); /* fn vals have same sign, i.e. root not
|
||||
in interval. */
|
||||
|
||||
/* OK, so the root for b lies in (blo, bhi). Start bisecting */
|
||||
do {
|
||||
bmid = 0.5 * (blo + bhi);
|
||||
eval_robust_residual(x + start, y + start, n_points, bmid, &a, &rmid);
|
||||
if (rmid == 0.0) {
|
||||
break;
|
||||
} else if (rmid * rlo > 0.0) {
|
||||
blo = bmid;
|
||||
rlo = rmid;
|
||||
} else if (rmid * rhi > 0.0) {
|
||||
bhi = bmid;
|
||||
rhi = rmid;
|
||||
} else {
|
||||
CROAK("Impossible");
|
||||
}
|
||||
} while ((bhi - blo) > tol);
|
||||
|
||||
*b0 = a;
|
||||
*b1 = bmid;
|
||||
|
||||
/* Number of runs test, but not if we're already down to the
|
||||
minimum number of points */
|
||||
if (n_points == MIN_SAMPLES_FOR_REGRESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (i=start; i<n; i++) {
|
||||
resids[i] = y[i] - a - bmid * x[i];
|
||||
}
|
||||
|
||||
nruns = n_runs_from_residuals(resids + start, n_points);
|
||||
|
||||
if (nruns > critical_runs10[n_points]) {
|
||||
break;
|
||||
} else {
|
||||
start++;
|
||||
}
|
||||
|
||||
} while (1);
|
||||
|
||||
*n_runs = nruns;
|
||||
*best_start = start;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
108
regress.h
Normal file
108
regress.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/regress.h,v 1.13 2002/02/28 23:27:13 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for regression routine(s)
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_REGRESS_H
|
||||
#define GOT_REGRESS_H
|
||||
|
||||
extern void
|
||||
RGR_WeightedRegression
|
||||
(double *x, /* independent variable */
|
||||
double *y, /* measured data */
|
||||
double *w, /* weightings (large => data
|
||||
less reliable) */
|
||||
|
||||
int n, /* number of data points */
|
||||
|
||||
/* And now the results */
|
||||
|
||||
double *b0, /* estimated y axis intercept */
|
||||
double *b1, /* estimated slope */
|
||||
double *s2, /* estimated variance (weighted) of
|
||||
data points */
|
||||
|
||||
double *sb0, /* estimated standard deviation of
|
||||
intercept */
|
||||
double *sb1 /* estimated standard deviation of
|
||||
slope */
|
||||
|
||||
/* Could add correlation stuff later if required */
|
||||
);
|
||||
|
||||
/* Return the weighting to apply to the standard deviation to get a
|
||||
given size of confidence interval assuming a T distribution */
|
||||
|
||||
extern double RGR_GetTCoef(int dof);
|
||||
|
||||
/* Return a status indicating whether there were enough points to
|
||||
carry out the regression */
|
||||
|
||||
extern int
|
||||
RGR_FindBestRegression
|
||||
(double *x, /* independent variable */
|
||||
double *y, /* measured data */
|
||||
double *w, /* weightings (large => data
|
||||
less reliable) */
|
||||
|
||||
int n, /* number of data points */
|
||||
|
||||
/* And now the results */
|
||||
|
||||
double *b0, /* estimated y axis intercept */
|
||||
double *b1, /* estimated slope */
|
||||
double *s2, /* estimated variance of data points */
|
||||
|
||||
double *sb0, /* estimated standard deviation of
|
||||
intercept */
|
||||
double *sb1, /* estimated standard deviation of
|
||||
slope */
|
||||
|
||||
int *new_start, /* the new starting index to make the
|
||||
residuals pass the two tests */
|
||||
|
||||
int *n_runs, /* number of runs amongst the residuals */
|
||||
|
||||
int *dof /* degrees of freedom in statistics (needed
|
||||
to get confidence intervals later) */
|
||||
|
||||
);
|
||||
|
||||
int
|
||||
RGR_FindBestRobustRegression
|
||||
(double *x,
|
||||
double *y,
|
||||
int n,
|
||||
double tol,
|
||||
double *b0,
|
||||
double *b1,
|
||||
int *n_runs,
|
||||
int *best_start);
|
||||
|
||||
#endif /* GOT_REGRESS_H */
|
||||
121
reports.h
Normal file
121
reports.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/reports.h,v 1.17 2002/02/28 23:27:13 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Data structure definitions within the daemon for various reports that
|
||||
can be generated */
|
||||
|
||||
#ifndef GOT_REPORTS_H
|
||||
#define GOT_REPORTS_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#define REPORT_INVALID_OFFSET 0x80000000
|
||||
|
||||
typedef struct {
|
||||
unsigned long ip_addr;
|
||||
int stratum;
|
||||
int poll;
|
||||
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
|
||||
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_OTHER} state;
|
||||
|
||||
unsigned long latest_meas_ago; /* seconds */
|
||||
long orig_latest_meas; /* microseconds (us) */
|
||||
long latest_meas; /* us */
|
||||
unsigned long latest_meas_err; /* us */
|
||||
long est_offset; /* us */
|
||||
unsigned long est_offset_err; /* us */
|
||||
long resid_freq; /* ppm * 1000 */
|
||||
unsigned long resid_skew; /* ppm * 1000 */
|
||||
} RPT_SourceReport ;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ref_id;
|
||||
unsigned long stratum;
|
||||
struct timeval ref_time;
|
||||
struct timeval current_correction;
|
||||
double freq_ppm;
|
||||
double resid_freq_ppm;
|
||||
double skew_ppm;
|
||||
double root_delay;
|
||||
double root_dispersion;
|
||||
} RPT_TrackingReport;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ip_addr;
|
||||
unsigned long n_samples;
|
||||
unsigned long n_runs;
|
||||
unsigned long span_seconds;
|
||||
double resid_freq_ppm;
|
||||
double skew_ppm;
|
||||
double sd_us;
|
||||
} RPT_SourcestatsReport;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ref_time;
|
||||
unsigned short n_samples;
|
||||
unsigned short n_runs;
|
||||
unsigned long span_seconds;
|
||||
double rtc_seconds_fast;
|
||||
double rtc_gain_rate_ppm;
|
||||
} RPT_RTC_Report;
|
||||
|
||||
typedef struct {
|
||||
unsigned long client_hits;
|
||||
unsigned long peer_hits;
|
||||
unsigned long cmd_hits_auth;
|
||||
unsigned long cmd_hits_normal;
|
||||
unsigned long cmd_hits_bad;
|
||||
unsigned long last_ntp_hit_ago;
|
||||
unsigned long last_cmd_hit_ago;
|
||||
} RPT_ClientAccess_Report;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ip_addr;
|
||||
unsigned long client_hits;
|
||||
unsigned long peer_hits;
|
||||
unsigned long cmd_hits_auth;
|
||||
unsigned long cmd_hits_normal;
|
||||
unsigned long cmd_hits_bad;
|
||||
unsigned long last_ntp_hit_ago;
|
||||
unsigned long last_cmd_hit_ago;
|
||||
} RPT_ClientAccessByIndex_Report;
|
||||
|
||||
typedef struct {
|
||||
time_t when;
|
||||
double slewed_offset;
|
||||
double orig_offset;
|
||||
double residual;
|
||||
} RPT_ManualSamplesReport;
|
||||
|
||||
typedef struct {
|
||||
int online;
|
||||
int offline;
|
||||
int burst_online;
|
||||
int burst_offline;
|
||||
} RPT_ActivityReport;
|
||||
|
||||
#endif /* GOT_REPORTS_H */
|
||||
222
rtc.c
Normal file
222
rtc.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/rtc.c,v 1.13 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "rtc.h"
|
||||
#include "logging.h"
|
||||
#include "conf.h"
|
||||
|
||||
#if defined LINUX
|
||||
#include "rtc_linux.h"
|
||||
#endif /* defined LINUX */
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int driver_initialised = 0;
|
||||
|
||||
static struct {
|
||||
int (*init)(void);
|
||||
void (*fini)(void);
|
||||
void (*time_pre_init)(void);
|
||||
void (*time_init)(void (*after_hook)(void*), void *anything);
|
||||
void (*start_measurements)(void);
|
||||
int (*write_parameters)(void);
|
||||
int (*get_report)(RPT_RTC_Report *report);
|
||||
int (*trim)(void);
|
||||
void (*cycle_logfile)(void);
|
||||
} driver =
|
||||
{
|
||||
#if defined LINUX
|
||||
RTC_Linux_Initialise,
|
||||
RTC_Linux_Finalise,
|
||||
RTC_Linux_TimePreInit,
|
||||
RTC_Linux_TimeInit,
|
||||
RTC_Linux_StartMeasurements,
|
||||
RTC_Linux_WriteParameters,
|
||||
RTC_Linux_GetReport,
|
||||
RTC_Linux_Trim,
|
||||
RTC_Linux_CycleLogFile
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
RTC_Initialise(void)
|
||||
{
|
||||
char *file_name;
|
||||
int ok;
|
||||
|
||||
/* This is how we tell whether the user wants to load the RTC
|
||||
driver, if he is on a machine where it is an option. */
|
||||
file_name = CNF_GetRtcFile();
|
||||
|
||||
if (file_name) {
|
||||
if (driver.init) {
|
||||
if ((driver.init)()) {
|
||||
ok = 1;
|
||||
} else {
|
||||
ok = 0;
|
||||
}
|
||||
} else {
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
driver_initialised = 1;
|
||||
} else {
|
||||
driver_initialised = 0;
|
||||
LOG(LOGS_ERR, LOGF_Rtc, "Real time clock not supported on this operating system");
|
||||
}
|
||||
|
||||
} else {
|
||||
driver_initialised = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
RTC_Finalise(void)
|
||||
{
|
||||
if (driver.fini) {
|
||||
(driver.fini)();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Start the processing to get a single measurement from the real time
|
||||
clock, and use it to trim the system time, based on knowing the
|
||||
drift rate of the RTC and the error the last time we set it. The
|
||||
TimePreInit routine has already run, so we can be sure that the
|
||||
trim required is not *too* large.
|
||||
|
||||
We are called with a hook to a function to be called after the
|
||||
initialisation is complete. We also call this if we cannot do the
|
||||
initialisation. */
|
||||
|
||||
void
|
||||
RTC_TimeInit(void (*after_hook)(void *), void *anything)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
(driver.time_init)(after_hook, anything);
|
||||
} else {
|
||||
LOG(LOGS_ERR, LOGF_Rtc, "Can't initialise from real time clock, driver not loaded");
|
||||
(after_hook)(anything);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Do an initial read of the RTC and set the system time to it. This
|
||||
is analogous to what /sbin/clock -s -u would do on Linux. */
|
||||
|
||||
void
|
||||
RTC_TimePreInit(void)
|
||||
{
|
||||
if (driver.time_pre_init) {
|
||||
(driver.time_pre_init)();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Start the RTC measurement process */
|
||||
|
||||
void
|
||||
RTC_StartMeasurements(void)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
(driver.start_measurements)();
|
||||
}
|
||||
/* Benign if driver not present */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Write RTC information out to RTC file. Return 0 for success, 1 if
|
||||
RTC driver not running, or 2 if the file cannot be written. */
|
||||
|
||||
int
|
||||
RTC_WriteParameters(void)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
return (driver.write_parameters)();
|
||||
} else {
|
||||
return RTC_ST_NODRV;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
RTC_GetReport(RPT_RTC_Report *report)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
return (driver.get_report)(report);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
RTC_Trim(void)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
return (driver.trim)();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
RTC_CycleLogFile(void)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
(driver.cycle_logfile)();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
52
rtc.h
Normal file
52
rtc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/rtc.h,v 1.9 2002/02/28 23:27:13 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_RTC_H
|
||||
#define GOT_RTC_H
|
||||
|
||||
#include "reports.h"
|
||||
|
||||
extern void RTC_Initialise(void);
|
||||
extern void RTC_Finalise(void);
|
||||
extern void RTC_TimePreInit(void);
|
||||
extern void RTC_TimeInit(void (*after_hook)(void *), void *anything);
|
||||
extern void RTC_StartMeasurements(void);
|
||||
extern int RTC_GetReport(RPT_RTC_Report *report);
|
||||
|
||||
#define RTC_ST_OK 0
|
||||
#define RTC_ST_NODRV 1
|
||||
#define RTC_ST_BADFILE 2
|
||||
|
||||
extern int RTC_WriteParameters(void);
|
||||
|
||||
extern int RTC_Trim(void);
|
||||
|
||||
extern void RTC_CycleLogFile(void);
|
||||
|
||||
#endif /* GOT_RTC_H */
|
||||
1174
rtc_linux.c
Normal file
1174
rtc_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
53
rtc_linux.h
Normal file
53
rtc_linux.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/rtc_linux.h,v 1.13 2002/02/28 23:27:13 richard Exp $
|
||||
|
||||
======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
======================================================================
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _GOT_RTC_LINUX_H
|
||||
#define _GOT_RTC_LINUX_H
|
||||
|
||||
#include "reports.h"
|
||||
|
||||
#if defined LINUX
|
||||
|
||||
extern int RTC_Linux_Initialise(void);
|
||||
extern void RTC_Linux_Finalise(void);
|
||||
extern void RTC_Linux_TimePreInit(void);
|
||||
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
|
||||
extern void RTC_Linux_StartMeasurements(void);
|
||||
|
||||
/* 0=success, 1=no driver, 2=can't write file */
|
||||
extern int RTC_Linux_WriteParameters(void);
|
||||
|
||||
extern int RTC_Linux_GetReport(RPT_RTC_Report *report);
|
||||
extern int RTC_Linux_Trim(void);
|
||||
|
||||
extern void RTC_Linux_CycleLogFile(void);
|
||||
|
||||
#endif /* defined LINUX */
|
||||
|
||||
#endif /* _GOT_RTC_LINUX_H */
|
||||
601
sched.c
Normal file
601
sched.c
Normal file
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sched.c,v 1.16 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This file contains the scheduling loop and the timeout queue.
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sched.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Flag indicating that we are initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Variables to handle the capability to dispatch on particular file
|
||||
handles becoming readable */
|
||||
|
||||
/* Each bit set in this fd set corresponds to a read descriptor that
|
||||
we are watching and with which we have a handler associated in the
|
||||
file_handlers array */
|
||||
static fd_set read_fds;
|
||||
|
||||
/* This is the number of bits that we have set in read_fds */
|
||||
static unsigned int n_read_fds;
|
||||
|
||||
/* One more than the highest file descriptor that is registered */
|
||||
static unsigned int one_highest_fd;
|
||||
|
||||
/* This assumes that fd_set is implemented as a fixed size array of
|
||||
bits, possibly embedded inside a record. It might therefore
|
||||
somewhat non-portable. */
|
||||
|
||||
#define FD_SET_SIZE (sizeof(fd_set) * 8)
|
||||
|
||||
typedef struct {
|
||||
SCH_FileHandler handler;
|
||||
SCH_ArbitraryArgument arg;
|
||||
} FileHandlerEntry;
|
||||
|
||||
static FileHandlerEntry file_handlers[FD_SET_SIZE];
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Variables to handler the timer queue */
|
||||
|
||||
typedef struct _TimerQueueEntry
|
||||
{
|
||||
struct _TimerQueueEntry *next; /* Forward and back links in the list */
|
||||
struct _TimerQueueEntry *prev;
|
||||
struct timeval tv; /* Local system time at which the
|
||||
timeout is to expire. Clearly this
|
||||
must be in terms of what the
|
||||
operating system thinks of as
|
||||
system time, because it will be an
|
||||
argument to select(). Therefore,
|
||||
any fudges etc that our local time
|
||||
driver module would apply to time
|
||||
that we pass to clients etc doesn't
|
||||
apply to this. */
|
||||
SCH_TimeoutID id; /* ID to allow client to delete
|
||||
timeout */
|
||||
SCH_TimeoutClass class; /* The class that the epoch is in */
|
||||
SCH_TimeoutHandler handler; /* The handler routine to use */
|
||||
SCH_ArbitraryArgument arg; /* The argument to pass to the handler */
|
||||
|
||||
} TimerQueueEntry;
|
||||
|
||||
/* The timer queue. We only use the next and prev entries of this
|
||||
record, these chain to the real entries. */
|
||||
static TimerQueueEntry timer_queue;
|
||||
static unsigned long n_timer_queue_entries;
|
||||
static SCH_TimeoutID next_tqe_id;
|
||||
|
||||
/* Pointer to head of free list */
|
||||
static TimerQueueEntry *tqe_free_list = NULL;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int need_to_exit;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_slew(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_Initialise(void)
|
||||
{
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
n_read_fds = 0;
|
||||
|
||||
n_timer_queue_entries = 0;
|
||||
next_tqe_id = 0;
|
||||
|
||||
timer_queue.next = &timer_queue;
|
||||
timer_queue.prev = &timer_queue;
|
||||
|
||||
need_to_exit = 0;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||
|
||||
initialised = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_Finalise(void) {
|
||||
initialised = 0;
|
||||
return; /* Nothing to do for now */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_AddInputFileHandler
|
||||
(int fd, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
/* Don't want to allow the same fd to register a handler more than
|
||||
once without deleting a previous association - this suggests
|
||||
a bug somewhere else in the program. */
|
||||
if (FD_ISSET(fd, &read_fds)) {
|
||||
CROAK("File handler already registered");
|
||||
}
|
||||
|
||||
++n_read_fds;
|
||||
|
||||
file_handlers[fd].handler = handler;
|
||||
file_handlers[fd].arg = arg;
|
||||
|
||||
FD_SET(fd, &read_fds);
|
||||
|
||||
if ((fd + 1) > one_highest_fd) {
|
||||
one_highest_fd = fd + 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_RemoveInputFileHandler(int fd)
|
||||
{
|
||||
int fds_left, fd_to_check;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
/* Check that a handler was registered for the fd in question */
|
||||
if (!FD_ISSET(fd, &read_fds)) {
|
||||
CROAK("File handler not registered");
|
||||
}
|
||||
|
||||
--n_read_fds;
|
||||
|
||||
FD_CLR(fd, &read_fds);
|
||||
|
||||
/* Find new highest file descriptor */
|
||||
fds_left = n_read_fds;
|
||||
fd_to_check = 0;
|
||||
while (fds_left > 0) {
|
||||
if (FD_ISSET(fd_to_check, &read_fds)) {
|
||||
--fds_left;
|
||||
}
|
||||
++fd_to_check;
|
||||
}
|
||||
|
||||
one_highest_fd = fd_to_check;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define TQE_ALLOC_QUANTUM 32
|
||||
|
||||
static TimerQueueEntry *
|
||||
allocate_tqe(void)
|
||||
{
|
||||
TimerQueueEntry *new_block;
|
||||
TimerQueueEntry *result;
|
||||
int i;
|
||||
if (tqe_free_list == NULL) {
|
||||
new_block = MallocArray(TimerQueueEntry, TQE_ALLOC_QUANTUM);
|
||||
for (i=1; i<TQE_ALLOC_QUANTUM; i++) {
|
||||
new_block[i].next = &(new_block[i-1]);
|
||||
}
|
||||
new_block[0].next = NULL;
|
||||
tqe_free_list = &(new_block[TQE_ALLOC_QUANTUM - 1]);
|
||||
}
|
||||
|
||||
result = tqe_free_list;
|
||||
tqe_free_list = tqe_free_list->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
release_tqe(TimerQueueEntry *node)
|
||||
{
|
||||
node->next = tqe_free_list;
|
||||
tqe_free_list = node;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SCH_TimeoutID
|
||||
SCH_AddTimeout(struct timeval *tv, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
TimerQueueEntry *new_tqe;
|
||||
TimerQueueEntry *ptr;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
new_tqe = allocate_tqe();
|
||||
|
||||
new_tqe->id = next_tqe_id++;
|
||||
new_tqe->handler = handler;
|
||||
new_tqe->arg = arg;
|
||||
new_tqe->tv = *tv;
|
||||
new_tqe->class = SCH_ReservedTimeoutValue;
|
||||
|
||||
/* Now work out where to insert the new entry in the list */
|
||||
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
|
||||
if (UTI_CompareTimevals(&new_tqe->tv, &ptr->tv) == -1) {
|
||||
/* If the new entry comes before the current pointer location in
|
||||
the list, we want to insert the new entry just before ptr. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this stage, we want to insert the new entry immediately before
|
||||
the entry identified by 'ptr' */
|
||||
|
||||
new_tqe->next = ptr;
|
||||
new_tqe->prev = ptr->prev;
|
||||
ptr->prev->next = new_tqe;
|
||||
ptr->prev = new_tqe;
|
||||
|
||||
n_timer_queue_entries++;
|
||||
|
||||
return new_tqe->id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This queues a timeout to elapse at a given delta time relative to
|
||||
the current (raw) time */
|
||||
|
||||
SCH_TimeoutID
|
||||
SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
struct timeval now, then;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
UTI_AddDoubleToTimeval(&now, delay, &then);
|
||||
return SCH_AddTimeout(&then, handler, arg);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SCH_TimeoutID
|
||||
SCH_AddTimeoutInClass(double min_delay, double separation,
|
||||
SCH_TimeoutClass class,
|
||||
SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
TimerQueueEntry *new_tqe;
|
||||
TimerQueueEntry *ptr;
|
||||
struct timeval now;
|
||||
double diff;
|
||||
double new_min_delay;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
new_min_delay = min_delay;
|
||||
|
||||
/* Scan through list for entries in the same class and increase min_delay
|
||||
if necessary to keep at least the separation away */
|
||||
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
|
||||
if (ptr->class == class) {
|
||||
UTI_DiffTimevalsToDouble(&diff, &ptr->tv, &now);
|
||||
if (new_min_delay > diff) {
|
||||
if (new_min_delay - diff < separation) {
|
||||
new_min_delay = diff + separation;
|
||||
}
|
||||
}
|
||||
if (new_min_delay < diff) {
|
||||
if (diff - new_min_delay < separation) {
|
||||
new_min_delay = diff + separation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
|
||||
UTI_DiffTimevalsToDouble(&diff, &ptr->tv, &now);
|
||||
if (diff > new_min_delay) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have located the insertion point */
|
||||
new_tqe = allocate_tqe();
|
||||
|
||||
new_tqe->id = next_tqe_id++;
|
||||
new_tqe->handler = handler;
|
||||
new_tqe->arg = arg;
|
||||
UTI_AddDoubleToTimeval(&now, new_min_delay, &new_tqe->tv);
|
||||
new_tqe->class = class;
|
||||
|
||||
new_tqe->next = ptr;
|
||||
new_tqe->prev = ptr->prev;
|
||||
ptr->prev->next = new_tqe;
|
||||
ptr->prev = new_tqe;
|
||||
n_timer_queue_entries++;
|
||||
|
||||
return new_tqe->id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_RemoveTimeout(SCH_TimeoutID id)
|
||||
{
|
||||
TimerQueueEntry *ptr;
|
||||
int ok;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
|
||||
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
|
||||
|
||||
if (ptr->id == id) {
|
||||
/* Found the required entry */
|
||||
|
||||
/* Unlink from the queue */
|
||||
ptr->next->prev = ptr->prev;
|
||||
ptr->prev->next = ptr->next;
|
||||
|
||||
/* Decrement entry count */
|
||||
--n_timer_queue_entries;
|
||||
|
||||
/* Release memory back to the operating system */
|
||||
release_tqe(ptr);
|
||||
|
||||
ok = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ok);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* The current time (now) has to be passed in from the
|
||||
caller to avoid race conditions */
|
||||
|
||||
static int
|
||||
dispatch_timeouts(struct timeval *now) {
|
||||
TimerQueueEntry *ptr;
|
||||
int n_done = 0;
|
||||
|
||||
while ((n_timer_queue_entries > 0) &&
|
||||
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
|
||||
ptr = timer_queue.next;
|
||||
|
||||
/* Dispatch the handler */
|
||||
(ptr->handler)(ptr->arg);
|
||||
|
||||
/* Increment count of timeouts handled */
|
||||
++n_done;
|
||||
|
||||
/* Unlink entry from the queue */
|
||||
ptr->prev->next = ptr->next;
|
||||
ptr->next->prev = ptr->prev;
|
||||
|
||||
/* Decrement count of entries in queue */
|
||||
--n_timer_queue_entries;
|
||||
|
||||
/* Delete entry */
|
||||
release_tqe(ptr);
|
||||
}
|
||||
|
||||
return n_done;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* nfh is the number of bits set in fhs */
|
||||
|
||||
static void
|
||||
dispatch_filehandlers(int nfh, fd_set *fhs)
|
||||
{
|
||||
int fh = 0;
|
||||
|
||||
while (nfh > 0) {
|
||||
if (FD_ISSET(fh, fhs)) {
|
||||
|
||||
/* This descriptor can be read from, dispatch its handler */
|
||||
(file_handlers[fh].handler)(file_handlers[fh].arg);
|
||||
|
||||
/* Decrement number of readable files still to find */
|
||||
--nfh;
|
||||
}
|
||||
|
||||
++fh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_slew(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *anything)
|
||||
{
|
||||
TimerQueueEntry *ptr;
|
||||
struct timeval T1;
|
||||
|
||||
if (is_step_change) {
|
||||
/* We're not interested in anything else - it won't affect the
|
||||
functionality of timer event dispatching. If a step change
|
||||
occurs, just shift all the timeouts by the offset */
|
||||
|
||||
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
|
||||
UTI_AddDoubleToTimeval(&ptr->tv, -doffset, &T1);
|
||||
ptr->tv = T1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_MainLoop(void)
|
||||
{
|
||||
fd_set rd, wr, ex;
|
||||
int status;
|
||||
struct timeval tv, *ptv;
|
||||
struct timeval now;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
while (!need_to_exit) {
|
||||
|
||||
/* Copy current set of read file descriptors */
|
||||
memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
|
||||
|
||||
/* Blank the write and exception descriptors - we aren't very
|
||||
interested */
|
||||
FD_ZERO(&wr);
|
||||
FD_ZERO(&ex);
|
||||
|
||||
/* Try to dispatch any timeouts that have already gone by, and
|
||||
keep going until all are done. (The earlier ones may take so
|
||||
long to do that the later ones come around by the time they are
|
||||
completed). */
|
||||
|
||||
do {
|
||||
LCL_ReadRawTime(&now);
|
||||
} while (dispatch_timeouts(&now) > 0);
|
||||
|
||||
/* Check whether there is a timeout and set it up */
|
||||
if (n_timer_queue_entries > 0) {
|
||||
|
||||
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
|
||||
ptv = &tv;
|
||||
|
||||
} else {
|
||||
ptv = NULL;
|
||||
}
|
||||
|
||||
/* if there are no file descriptors being waited on and no
|
||||
timeout set, this is clearly ridiculous, so stop the run */
|
||||
|
||||
if (!ptv && (n_read_fds == 0)) {
|
||||
LOG_FATAL(LOGF_Scheduler, "No descriptors or timeout to wait for");
|
||||
}
|
||||
|
||||
status = select(one_highest_fd, &rd, &wr, &ex, ptv);
|
||||
|
||||
if (status < 0) {
|
||||
CROAK("Status < 0 after select");
|
||||
} else if (status > 0) {
|
||||
/* A file descriptor is ready to read */
|
||||
|
||||
dispatch_filehandlers(status, &rd);
|
||||
|
||||
} else {
|
||||
if (status != 0) {
|
||||
CROAK("Unexpected value from select");
|
||||
}
|
||||
|
||||
/* No descriptors readable, timeout must have elapsed.
|
||||
Therefore, tv must be non-null */
|
||||
if (!ptv) {
|
||||
CROAK("No descriptors or timeout?");
|
||||
}
|
||||
|
||||
/* There's nothing to do here, since the timeouts
|
||||
will be dispatched at the top of the next loop
|
||||
cycle */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_QuitProgram(void)
|
||||
{
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
need_to_exit = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
83
sched.h
Normal file
83
sched.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sched.h,v 1.10 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Exported header file for sched.c
|
||||
*/
|
||||
|
||||
#ifndef GOT_SCHED_H
|
||||
#define GOT_SCHED_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
typedef unsigned long SCH_TimeoutID;
|
||||
|
||||
typedef unsigned long SCH_TimeoutClass;
|
||||
static const SCH_TimeoutClass SCH_ReservedTimeoutValue = 0;
|
||||
static const SCH_TimeoutClass SCH_NtpSamplingClass = 1;
|
||||
static const SCH_TimeoutClass SCH_NtpBroadcastClass = 2;
|
||||
|
||||
typedef void* SCH_ArbitraryArgument;
|
||||
typedef void (*SCH_FileHandler)(SCH_ArbitraryArgument);
|
||||
typedef void (*SCH_TimeoutHandler)(SCH_ArbitraryArgument);
|
||||
|
||||
/* Exported functions */
|
||||
|
||||
/* Initialisation function for the module */
|
||||
extern void SCH_Initialise(void);
|
||||
|
||||
/* Finalisation function for the module */
|
||||
extern void SCH_Finalise(void);
|
||||
|
||||
/* Register a handler for when select goes true on a file descriptor */
|
||||
extern void SCH_AddInputFileHandler
|
||||
(int fd, /* The file descriptor */
|
||||
SCH_FileHandler, /* The handler routine */
|
||||
SCH_ArbitraryArgument /* An arbitrary passthrough argument to the handler */
|
||||
);
|
||||
extern void SCH_RemoveInputFileHandler(int fd);
|
||||
|
||||
/* This queues a timeout to elapse at a given (raw) local time */
|
||||
extern SCH_TimeoutID SCH_AddTimeout(struct timeval *tv, SCH_TimeoutHandler, SCH_ArbitraryArgument);
|
||||
|
||||
/* This queues a timeout to elapse at a given delta time relative to the current (raw) time */
|
||||
extern SCH_TimeoutID SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler, SCH_ArbitraryArgument);
|
||||
|
||||
/* This queues a timeout in a particular class, ensuring that the
|
||||
expiry time is at least a given separation away from any other
|
||||
timeout in the same class */
|
||||
extern SCH_TimeoutID SCH_AddTimeoutInClass(double min_delay, double separation,
|
||||
SCH_TimeoutClass class,
|
||||
SCH_TimeoutHandler handler, SCH_ArbitraryArgument);
|
||||
|
||||
/* The next one probably ought to return a status code */
|
||||
extern void SCH_RemoveTimeout(SCH_TimeoutID);
|
||||
|
||||
extern void SCH_MainLoop(void);
|
||||
|
||||
extern void SCH_QuitProgram(void);
|
||||
|
||||
#endif /* GOT_SCHED_H */
|
||||
938
sources.c
Normal file
938
sources.c
Normal file
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sources.c,v 1.31 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
The routines in this file manage the complete pool of sources that
|
||||
we might be synchronizing to. This includes NTP sources and others
|
||||
(e.g. local reference clocks, eyeball + wristwatch etc).
|
||||
|
||||
*/
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sources.h"
|
||||
#include "sourcestats.h"
|
||||
#include "memory.h"
|
||||
#include "ntp.h" /* For NTP_Leap */
|
||||
#include "local.h"
|
||||
#include "reference.h"
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "reports.h"
|
||||
#include "nameserv.h"
|
||||
#include "mkdirpp.h"
|
||||
|
||||
/* ================================================== */
|
||||
/* Flag indicating that we are initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
/* Structure used to hold info for selecting between sources */
|
||||
struct SelectInfo {
|
||||
int stratum;
|
||||
int select_ok;
|
||||
double variance;
|
||||
double root_delay;
|
||||
double root_dispersion;
|
||||
double root_distance;
|
||||
double best_offset;
|
||||
double lo_limit;
|
||||
double hi_limit;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
/* This enum contains the flag values that are used to label
|
||||
each source */
|
||||
typedef enum {
|
||||
SRC_OK, /* OK so far */
|
||||
SRC_UNREACHABLE, /* Source is not reachable */
|
||||
SRC_BAD_STATS, /* Stats driver could not supply valid
|
||||
data */
|
||||
SRC_FALSETICKER, /* Source is found to be a falseticker */
|
||||
SRC_JITTERY, /* Source scatter worse than other's dispersion */
|
||||
SRC_SELECTABLE, /* Source is acceptable candidate */
|
||||
SRC_SYNC /* Current synchronisation source */
|
||||
} SRC_Status;
|
||||
|
||||
/* ================================================== */
|
||||
/* Define the instance structure used to hold information about each
|
||||
source */
|
||||
struct SRC_Instance_Record {
|
||||
SST_Stats stats;
|
||||
NTP_Leap leap_status; /* Leap status */
|
||||
int index; /* Index back into the array of source */
|
||||
unsigned long ref_id; /* The reference ID of this source
|
||||
(i.e. its IP address, NOT the
|
||||
reference _it_ is sync'd to) */
|
||||
|
||||
/* Flag indicating that we are receiving packets with valid headers
|
||||
from this source and can use it as a reference */
|
||||
int reachable;
|
||||
|
||||
/* Flag indicating the status of the source */
|
||||
SRC_Status status;
|
||||
|
||||
struct SelectInfo sel_info;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
/* Structure used to build the sort list for finding falsetickers */
|
||||
struct Sort_Element {
|
||||
int index;
|
||||
double offset;
|
||||
enum {LOW=-1, CENTRE=0, HIGH=1} tag;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
/* Table of sources */
|
||||
static struct SRC_Instance_Record **sources;
|
||||
static struct Sort_Element *sort_list;
|
||||
static int *sel_sources;
|
||||
static int n_sources; /* Number of sources currently in the table */
|
||||
static int max_n_sources; /* Capacity of the table */
|
||||
|
||||
#define INVALID_SOURCE (-1)
|
||||
static int selected_source_index; /* Which source index is currently
|
||||
selected (set to INVALID_SOURCE
|
||||
if no current valid reference) */
|
||||
|
||||
/* ================================================== */
|
||||
/* Forward prototype */
|
||||
|
||||
static void
|
||||
slew_sources(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
|
||||
double doffset, int is_step_change, void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation function */
|
||||
void SRC_Initialise(void) {
|
||||
sources = NULL;
|
||||
sort_list = NULL;
|
||||
n_sources = 0;
|
||||
max_n_sources = 0;
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
initialised = 1;
|
||||
|
||||
LCL_AddParameterChangeHandler(slew_sources, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Finalisation function */
|
||||
void SRC_Finalise(void)
|
||||
{
|
||||
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
|
||||
initialised = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
SRC_Instance SRC_CreateNewInstance(unsigned long ref_id)
|
||||
{
|
||||
SRC_Instance result;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
result = MallocNew(struct SRC_Instance_Record);
|
||||
result->stats = SST_CreateInstance(ref_id);
|
||||
|
||||
if (n_sources == max_n_sources) {
|
||||
/* Reallocate memory */
|
||||
max_n_sources += 32;
|
||||
if (sources) {
|
||||
sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
|
||||
sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
|
||||
sel_sources = ReallocArray(int, max_n_sources, sel_sources);
|
||||
} else {
|
||||
sources = MallocArray(struct SRC_Instance_Record *, max_n_sources);
|
||||
sort_list = MallocArray(struct Sort_Element, 3*max_n_sources);
|
||||
sel_sources = MallocArray(int, max_n_sources);
|
||||
}
|
||||
}
|
||||
|
||||
sources[n_sources] = result;
|
||||
result->index = n_sources;
|
||||
result->leap_status = LEAP_Normal;
|
||||
result->ref_id = ref_id;
|
||||
result->reachable = 0;
|
||||
result->status = SRC_BAD_STATS;
|
||||
|
||||
n_sources++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Function to get rid of a source when it is being unconfigured.
|
||||
This may cause the current reference source to be reselected, if this
|
||||
was the reference source or contributed significantly to a
|
||||
falseticker decision. */
|
||||
|
||||
void SRC_DestroyInstance(SRC_Instance instance)
|
||||
{
|
||||
int dead_index, i;
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
if (instance->index == selected_source_index) {
|
||||
instance->reachable = 0;
|
||||
SRC_SelectSource(0);
|
||||
}
|
||||
|
||||
SST_DeleteInstance(instance->stats);
|
||||
dead_index = instance->index;
|
||||
for (i=dead_index; i<n_sources-1; i++) {
|
||||
sources[i] = sources[i+1];
|
||||
sources[i]->index = i;
|
||||
}
|
||||
--n_sources;
|
||||
Free(instance);
|
||||
|
||||
if (selected_source_index > dead_index) {
|
||||
--selected_source_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Function to get the range of frequencies, relative to the given
|
||||
source, that we believe the local clock lies within. The return
|
||||
values are in terms of the number of seconds fast (+ve) or slow
|
||||
(-ve) relative to the source that the local clock becomes after a
|
||||
given amount of local time has elapsed.
|
||||
|
||||
Suppose the initial offset relative to the source is U (fast +ve,
|
||||
slow -ve) and a time interval T elapses measured in terms of the
|
||||
local clock. Then the error relative to the source at the end of
|
||||
the interval should lie in the interval [U+T*lo, U+T*hi]. */
|
||||
|
||||
void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
|
||||
{
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
SST_GetFrequencyRange(instance->stats, lo, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This function is called by one of the source drivers when it has
|
||||
a new sample that is to be accumulated.
|
||||
|
||||
This function causes the frequency estimation to be re-run for the
|
||||
designated source, and the clock selection procedure to be re-run
|
||||
afterwards.
|
||||
|
||||
Parameters are described in sources.h
|
||||
|
||||
*/
|
||||
|
||||
void SRC_AccumulateSample
|
||||
(SRC_Instance inst,
|
||||
struct timeval *sample_time,
|
||||
double offset,
|
||||
double peer_delay,
|
||||
double peer_dispersion,
|
||||
double root_delay,
|
||||
double root_dispersion,
|
||||
int stratum,
|
||||
NTP_Leap leap_status)
|
||||
{
|
||||
|
||||
if (!initialised) {
|
||||
CROAK("Should be initialised");
|
||||
}
|
||||
|
||||
inst->leap_status = leap_status;
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Sources, "ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
|
||||
UTI_IPToDottedQuad(inst->ref_id), UTI_TimevalToString(sample_time), -offset, root_delay, root_dispersion, stratum);
|
||||
#endif
|
||||
|
||||
/* WE HAVE TO NEGATE OFFSET IN THIS CALL, IT IS HERE THAT THE SENSE OF OFFSET
|
||||
IS FLIPPED */
|
||||
SST_AccumulateSample(inst->stats, sample_time, -offset, peer_delay, peer_dispersion, root_delay, root_dispersion, stratum);
|
||||
SST_DoNewRegression(inst->stats);
|
||||
/* And redo clock selection */
|
||||
SRC_SelectSource(inst->ref_id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SRC_SetReachable(SRC_Instance inst)
|
||||
{
|
||||
inst->reachable = 1;
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Sources, "%s", UTI_IPToDottedQuad(inst->ref_id));
|
||||
#endif
|
||||
|
||||
/* Don't do selection at this point, though - that will come about
|
||||
in due course when we get some useful data from the source */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SRC_UnsetReachable(SRC_Instance inst)
|
||||
{
|
||||
inst->reachable = 0;
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_Sources, "%s%s", UTI_IPToDottedQuad(inst->ref_id),
|
||||
(inst->index == selected_source_index) ? "(REF)":"");
|
||||
#endif
|
||||
|
||||
/* If this was the previous reference source, we have to reselect! */
|
||||
|
||||
if (inst->index == selected_source_index) {
|
||||
SRC_SelectSource(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
compare_sort_elements(const void *a, const void *b)
|
||||
{
|
||||
const struct Sort_Element *u = (const struct Sort_Element *) a;
|
||||
const struct Sort_Element *v = (const struct Sort_Element *) b;
|
||||
|
||||
if (u->offset < v->offset) {
|
||||
return -1;
|
||||
} else if (u->offset > v->offset) {
|
||||
return +1;
|
||||
} else if (u->tag < v->tag) {
|
||||
return -1;
|
||||
} else if (u->tag > v->tag) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function selects the current reference from amongst the pool
|
||||
of sources we are holding.
|
||||
|
||||
Updates are only made to the local reference if match_addr is zero or is
|
||||
equal to the selected reference source address */
|
||||
|
||||
void
|
||||
SRC_SelectSource(unsigned long match_addr)
|
||||
{
|
||||
int i, j, index;
|
||||
struct timeval now;
|
||||
double local_clock_err;
|
||||
int src_select_ok;
|
||||
double src_offset, src_offset_sd, src_frequency, src_skew;
|
||||
double src_accrued_dispersion;
|
||||
int n_endpoints, j1, j2;
|
||||
double best_lo, best_hi;
|
||||
int depth, best_depth;
|
||||
int n_sel_sources;
|
||||
double distance, min_distance;
|
||||
int stratum, min_stratum;
|
||||
int min_distance_index;
|
||||
struct SelectInfo *si;
|
||||
double total_root_dispersion;
|
||||
int n_reachable_sources;
|
||||
|
||||
NTP_Leap leap_status = LEAP_Normal;
|
||||
|
||||
if (n_sources == 0) {
|
||||
/* In this case, we clearly cannot synchronise to anything */
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no sources");
|
||||
}
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
REF_SetUnsynchronised();
|
||||
return;
|
||||
}
|
||||
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
|
||||
/* Step 1 - build intervals about each source */
|
||||
n_endpoints = 0;
|
||||
n_reachable_sources = 0;
|
||||
for (i=0; i<n_sources; i++) {
|
||||
|
||||
if (sources[i]->reachable) {
|
||||
|
||||
++n_reachable_sources;
|
||||
|
||||
si = &(sources[i]->sel_info);
|
||||
SST_GetSelectionData(sources[i]->stats, &now,
|
||||
&(si->stratum),
|
||||
&(si->best_offset),
|
||||
&(si->root_delay),
|
||||
&(si->root_dispersion),
|
||||
&(si->variance),
|
||||
&(si->select_ok));
|
||||
|
||||
/* Eventually this might be a flag indicating whether the get
|
||||
selection data call was successful. For now it always is. */
|
||||
src_select_ok = 1;
|
||||
|
||||
si->root_distance = si->root_dispersion + 0.5 * fabs(si->root_delay);
|
||||
si->lo_limit = si->best_offset - si->root_distance;
|
||||
si->hi_limit = si->best_offset + si->root_distance;
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "%s off=%f dist=%f lo=%f hi=%f",
|
||||
UTI_IPToDottedQuad(sources[i]->ref_id),
|
||||
si->best_offset, si->root_distance,
|
||||
si->lo_limit, si->hi_limit);
|
||||
#endif
|
||||
|
||||
if (src_select_ok) {
|
||||
|
||||
sources[i]->status = SRC_OK; /* For now */
|
||||
|
||||
/* Otherwise it will be hard to pick this one later! However,
|
||||
this test might be too strict, we might want to dump it */
|
||||
j1 = n_endpoints;
|
||||
j2 = j1 + 1;
|
||||
|
||||
sort_list[j1].index = i;
|
||||
sort_list[j1].offset = si->lo_limit;
|
||||
sort_list[j1].tag = LOW;
|
||||
|
||||
sort_list[j2].index = i;
|
||||
sort_list[j2].offset = si->hi_limit;
|
||||
sort_list[j2].tag = HIGH;
|
||||
|
||||
n_endpoints += 2;
|
||||
|
||||
} else {
|
||||
sources[i]->status = SRC_BAD_STATS;
|
||||
}
|
||||
} else {
|
||||
/* If the source is not reachable, there is no way we will pick
|
||||
it. */
|
||||
sources[i]->status = SRC_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "n_endpoints=%d", n_endpoints);
|
||||
#endif
|
||||
|
||||
/* Now sort the endpoint list */
|
||||
if (n_endpoints > 0) {
|
||||
|
||||
/* Sort the list into order */
|
||||
qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
|
||||
|
||||
/* Now search for the interval which is contained in the most
|
||||
individual source intervals. Any source which overlaps this
|
||||
will be a candidate.
|
||||
|
||||
If we get a case like
|
||||
|
||||
<----------------------->
|
||||
<-->
|
||||
<-->
|
||||
<===========>
|
||||
|
||||
we will build the interval as shown with '=', whereas with an extra source we get
|
||||
<----------------------->
|
||||
<------->
|
||||
<-->
|
||||
<-->
|
||||
<==>
|
||||
|
||||
The first case is just bad luck - we need extra sources to
|
||||
detect the falseticker, so just make an arbitrary choice based
|
||||
on stratum & stability etc.
|
||||
*/
|
||||
|
||||
depth = best_depth = 0;
|
||||
best_lo = best_hi = 0.0;
|
||||
|
||||
for (i=0; i<n_endpoints; i++) {
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "i=%d t=%f tag=%d addr=%s", i, sort_list[i].offset, sort_list[i].tag,
|
||||
UTI_IPToDottedQuad(sources[sort_list[i].index]->ref_id));
|
||||
#endif
|
||||
switch(sort_list[i].tag) {
|
||||
case LOW:
|
||||
depth++;
|
||||
if (depth > best_depth) {
|
||||
best_depth = depth;
|
||||
best_lo = sort_list[i].offset;
|
||||
}
|
||||
break;
|
||||
|
||||
case CENTRE:
|
||||
CROAK("CENTRE cannot occur");
|
||||
break;
|
||||
|
||||
case HIGH:
|
||||
if (depth == best_depth) {
|
||||
best_hi = sort_list[i].offset;
|
||||
}
|
||||
depth--;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "best_depth=%d best_lo=%f best_hi=%f",
|
||||
best_depth, best_lo, best_hi);
|
||||
#endif
|
||||
|
||||
if (best_depth <= n_reachable_sources/2) {
|
||||
/* Could not even get half the reachable sources to agree -
|
||||
clearly we can't synchronise.
|
||||
|
||||
srcs #to agree
|
||||
1 1
|
||||
2 2
|
||||
3 2
|
||||
4 3 etc
|
||||
|
||||
*/
|
||||
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no majority");
|
||||
}
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
REF_SetUnsynchronised();
|
||||
|
||||
/* .. and mark all sources as falsetickers (so they appear thus
|
||||
on the outputs from the command client) */
|
||||
|
||||
for (i=0; i<n_sources; i++) {
|
||||
sources[i]->status = SRC_FALSETICKER;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* We have our interval, now work out which source are in it,
|
||||
i.e. build list of admissible sources. */
|
||||
|
||||
n_sel_sources = 0;
|
||||
for (i=0; i<n_sources; i++) {
|
||||
if (sources[i]->status == SRC_OK) {
|
||||
/* This should be the same condition to get into the endpoint
|
||||
list */
|
||||
/* Check if source's interval contains the best interval, or
|
||||
is wholly contained within it */
|
||||
if (((sources[i]->sel_info.lo_limit <= best_lo) &&
|
||||
(sources[i]->sel_info.hi_limit >= best_hi)) ||
|
||||
((sources[i]->sel_info.lo_limit >= best_lo) &&
|
||||
(sources[i]->sel_info.hi_limit <= best_hi))) {
|
||||
|
||||
sel_sources[n_sel_sources++] = i;
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is valid", i, UTI_IPToDottedQuad(sources[i]->ref_id));
|
||||
#endif
|
||||
} else {
|
||||
sources[i]->status = SRC_FALSETICKER;
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is a falseticker", i, UTI_IPToDottedQuad(sources[i]->ref_id));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We now have a list of indices for the sources which pass the
|
||||
false-ticker test. Now go on to reject those whose variance is
|
||||
greater than the minimum distance of any other */
|
||||
|
||||
/* Find minimum distance */
|
||||
index = sel_sources[0];
|
||||
min_distance = sources[index]->sel_info.root_distance;
|
||||
for (i=1; i<n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
distance = sources[index]->sel_info.root_distance;
|
||||
if (distance < min_distance) {
|
||||
min_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "min_distance=%f", min_distance);
|
||||
#endif
|
||||
|
||||
/* Now go through and prune any sources that have excessive
|
||||
variance */
|
||||
for (i=0; i<n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (sources[index]->sel_info.variance > min_distance) {
|
||||
sel_sources[i] = INVALID_SOURCE;
|
||||
sources[index]->status = SRC_JITTERY;
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s has too much variance", i, UTI_IPToDottedQuad(sources[i]->ref_id));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Now crunch the list and mark all sources as selectable */
|
||||
for (i=j=0; i<n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (index != INVALID_SOURCE) {
|
||||
sources[index]->status = SRC_SELECTABLE;
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
index++;
|
||||
}
|
||||
}
|
||||
n_sel_sources = j;
|
||||
|
||||
/* Now find minimum stratum. If none are left now,
|
||||
tough. RFC1305 is not so harsh on pruning sources due to
|
||||
excess variance, which prevents this from happening */
|
||||
|
||||
if (n_sel_sources > 0) {
|
||||
index = sel_sources[0];
|
||||
min_stratum = sources[index]->sel_info.stratum;
|
||||
for (i=1; i<n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
stratum = sources[index]->sel_info.stratum;
|
||||
if (stratum < min_stratum) min_stratum = stratum;
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "min_stratum=%d", min_stratum);
|
||||
#endif
|
||||
|
||||
/* Does the current source have this stratum and is it still a
|
||||
survivor? */
|
||||
|
||||
if ((selected_source_index == INVALID_SOURCE) ||
|
||||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
|
||||
(sources[selected_source_index]->sel_info.stratum > min_stratum)) {
|
||||
|
||||
/* We have to elect a new synchronisation source */
|
||||
min_distance_index = INVALID_SOURCE;
|
||||
for (i=0; i<n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (sources[index]->sel_info.stratum == min_stratum) {
|
||||
if ((min_distance_index == INVALID_SOURCE) ||
|
||||
(sources[index]->sel_info.root_distance < min_distance)) {
|
||||
min_distance = sources[index]->sel_info.root_distance;
|
||||
min_distance_index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selected_source_index = min_distance_index;
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Selected source %s",
|
||||
UTI_IPToDottedQuad(sources[selected_source_index]->ref_id));
|
||||
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "new_sel_index=%d", min_distance_index);
|
||||
#endif
|
||||
} else {
|
||||
/* We retain the existing sync source, see p40 of RFC1305b.ps */
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_Sources, "existing reference retained", min_distance_index);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
sources[selected_source_index]->status = SRC_SYNC;
|
||||
|
||||
/* Now just use the statistics of the selected source for
|
||||
trimming the local clock */
|
||||
|
||||
LCL_ReadCookedTime(&now, &local_clock_err);
|
||||
|
||||
SST_GetTrackingData(sources[selected_source_index]->stats, &now,
|
||||
&src_offset, &src_offset_sd,
|
||||
&src_accrued_dispersion,
|
||||
&src_frequency, &src_skew);
|
||||
|
||||
total_root_dispersion = (src_accrued_dispersion +
|
||||
sources[selected_source_index]->sel_info.root_dispersion);
|
||||
|
||||
if ((match_addr == 0) ||
|
||||
(match_addr == sources[selected_source_index]->ref_id)) {
|
||||
|
||||
REF_SetReference(min_stratum, leap_status,
|
||||
sources[selected_source_index]->ref_id,
|
||||
&now,
|
||||
src_offset,
|
||||
src_frequency,
|
||||
src_skew,
|
||||
sources[selected_source_index]->sel_info.root_delay,
|
||||
total_root_dispersion);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no selectable sources");
|
||||
}
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
REF_SetUnsynchronised();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
/* No sources provided valid endpoints */
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
LOG(LOGS_INFO, LOGF_Sources, "Can't synchronise: no reachable sources");
|
||||
}
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
REF_SetUnsynchronised();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
SRC_PredictOffset(SRC_Instance inst, struct timeval *when)
|
||||
{
|
||||
return SST_PredictOffset(inst->stats, when);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
SRC_MinRoundTripDelay(SRC_Instance inst)
|
||||
{
|
||||
return SST_MinRoundTripDelay(inst->stats);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine is registered as a callback with the local clock
|
||||
module, to be called whenever the local clock changes frequency or
|
||||
is slewed. It runs through all the existing source statistics, and
|
||||
adjusts them to make them look as though they were sampled under
|
||||
the new regime. */
|
||||
|
||||
static void
|
||||
slew_sources(struct timeval *raw,
|
||||
struct timeval *cooked,
|
||||
double dfreq,
|
||||
double afreq,
|
||||
double doffset,
|
||||
int is_step_change,
|
||||
void *anything)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<n_sources; i++) {
|
||||
SST_SlewSamples(sources[i]->stats, cooked, dfreq, doffset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This is called to dump out the source measurement registers */
|
||||
|
||||
void
|
||||
SRC_DumpSources(void)
|
||||
{
|
||||
FILE *out;
|
||||
int direc_len;
|
||||
char *filename;
|
||||
unsigned int a, b, c, d;
|
||||
int i;
|
||||
char *direc;
|
||||
|
||||
direc = CNF_GetDumpDir();
|
||||
direc_len = strlen(direc);
|
||||
filename = MallocArray(char, direc_len+24); /* a bit of slack */
|
||||
if (mkdir_and_parents(direc)) {
|
||||
for (i=0; i<n_sources; i++) {
|
||||
a = (sources[i]->ref_id) >> 24;
|
||||
b = ((sources[i]->ref_id) >> 16) & 0xff;
|
||||
c = ((sources[i]->ref_id) >> 8) & 0xff;
|
||||
d = ((sources[i]->ref_id)) & 0xff;
|
||||
|
||||
sprintf(filename, "%s/%d.%d.%d.%d.dat", direc, a, b, c, d);
|
||||
out = fopen(filename, "w");
|
||||
if (!out) {
|
||||
LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file %s", filename);
|
||||
} else {
|
||||
SST_SaveToFile(sources[i]->stats, out);
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_ERR, LOGF_Sources, "Could not create directory %s", direc);
|
||||
}
|
||||
Free(filename);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SRC_ReloadSources(void)
|
||||
{
|
||||
FILE *in;
|
||||
char *filename;
|
||||
unsigned int a, b, c, d;
|
||||
int i;
|
||||
char *dumpdir;
|
||||
int dumpdirlen;
|
||||
|
||||
for (i=0; i<n_sources; i++) {
|
||||
a = (sources[i]->ref_id) >> 24;
|
||||
b = ((sources[i]->ref_id) >> 16) & 0xff;
|
||||
c = ((sources[i]->ref_id) >> 8) & 0xff;
|
||||
d = ((sources[i]->ref_id)) & 0xff;
|
||||
|
||||
dumpdir = CNF_GetDumpDir();
|
||||
dumpdirlen = strlen(dumpdir);
|
||||
filename = MallocArray(char, dumpdirlen+24);
|
||||
sprintf(filename, "%s/%d.%d.%d.%d.dat", dumpdir, a, b, c, d);
|
||||
in = fopen(filename, "r");
|
||||
if (!in) {
|
||||
LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file %s", filename);
|
||||
} else {
|
||||
if (SST_LoadFromFile(sources[i]->stats, in)) {
|
||||
/* We might want to use SST_DoUpdateRegression here, but we
|
||||
need to check it has the same functionality */
|
||||
SST_DoNewRegression(sources[i]->stats);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_Sources, "Problem loading from file %s", filename);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
Free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SRC_IsSyncPeer(SRC_Instance inst)
|
||||
{
|
||||
if (inst->index == selected_source_index) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SRC_ReadNumberOfSources(void)
|
||||
{
|
||||
return n_sources;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
|
||||
{
|
||||
SRC_Instance src;
|
||||
if ((index >= n_sources) || (index < 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
src = sources[index];
|
||||
report->ip_addr = src->ref_id;
|
||||
switch (src->status) {
|
||||
case SRC_SYNC:
|
||||
report->state = RPT_SYNC;
|
||||
break;
|
||||
case SRC_JITTERY:
|
||||
report->state = RPT_JITTERY;
|
||||
break;
|
||||
case SRC_UNREACHABLE:
|
||||
report->state = RPT_UNREACH;
|
||||
break;
|
||||
case SRC_FALSETICKER:
|
||||
report->state = RPT_FALSETICKER;
|
||||
break;
|
||||
default:
|
||||
report->state = RPT_OTHER;
|
||||
break;
|
||||
}
|
||||
/* Call stats module to fill out estimates */
|
||||
SST_DoSourceReport(src->stats, report, now);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report)
|
||||
{
|
||||
SRC_Instance src;
|
||||
|
||||
if ((index >= n_sources) || (index < 0)) {
|
||||
return 0;
|
||||
} else {
|
||||
src = sources[index];
|
||||
report->ip_addr = src->ref_id;
|
||||
SST_DoSourcestatsReport(src->stats, report);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst)
|
||||
{
|
||||
SRC_Skew_Direction result = SRC_Skew_Nochange;
|
||||
|
||||
switch (SST_LastSkewChange(inst->stats)) {
|
||||
case SST_Skew_Decrease:
|
||||
result = SRC_Skew_Decrease;
|
||||
break;
|
||||
case SST_Skew_Nochange:
|
||||
result = SRC_Skew_Nochange;
|
||||
break;
|
||||
case SST_Skew_Increase:
|
||||
result = SRC_Skew_Increase;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
155
sources.h
Normal file
155
sources.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sources.h,v 1.15 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header for the module that manages the collection of all
|
||||
sources that we are making measurements from. This include all NTP
|
||||
servers & peers, locally connected reference sources, eye/wristwatch
|
||||
drivers etc */
|
||||
|
||||
#ifndef GOT_SOURCES_H
|
||||
#define GOT_SOURCES_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* This datatype is used to hold information about sources. The
|
||||
instance must be passed when calling many of the interface
|
||||
functions */
|
||||
|
||||
typedef struct SRC_Instance_Record *SRC_Instance;
|
||||
|
||||
/* Initialisation function */
|
||||
extern void SRC_Initialise(void);
|
||||
|
||||
/* Finalisation function */
|
||||
extern void SRC_Finalise(void);
|
||||
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id);
|
||||
|
||||
/* Function to get rid of a source when it is being unconfigured.
|
||||
This may cause the current reference source to be reselected, if this
|
||||
was the reference source or contributed significantly to a
|
||||
falseticker decision. */
|
||||
|
||||
extern void SRC_DestroyInstance(SRC_Instance instance);
|
||||
|
||||
|
||||
/* Function to get the range of frequencies, relative to the given
|
||||
source, that we believe the local clock lies within. The return
|
||||
values are in terms of the number of seconds fast (+ve) or slow
|
||||
(-ve) relative to the source that the local clock becomes after a
|
||||
given amount of local time has elapsed.
|
||||
|
||||
Suppose the initial offset relative to the source is U (fast +ve,
|
||||
slow -ve) and a time interval T elapses measured in terms of the
|
||||
local clock. Then the error relative to the source at the end of
|
||||
the interval should lie in the interval [U+T*lo, U+T*hi]. */
|
||||
|
||||
extern void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi);
|
||||
|
||||
/* This function is called by one of the source drivers when it has
|
||||
a new sample that is to be accumulated.
|
||||
|
||||
This function causes the frequency estimation to be re-run for the
|
||||
designated source, and the clock selection procedure to be re-run
|
||||
afterwards.
|
||||
|
||||
sample_time is the local time at which the sample is to be
|
||||
considered to have been made, in terms of doing a regression fit of
|
||||
offset against local time.
|
||||
|
||||
offset is the offset at the time, in seconds. Positive indicates
|
||||
that the local clock is SLOW relative to the source, negative
|
||||
indicates that the local clock is FAST relative to it.
|
||||
|
||||
root_delay and root_dispersion are in seconds, and are as per
|
||||
RFC1305. root_dispersion only includes the peer's root dispersion
|
||||
+ local sampling precision + skew dispersion accrued during the
|
||||
measurement. It is the job of the source statistics algorithms +
|
||||
track.c to add on the extra dispersion due to the residual standard
|
||||
deviation of the offsets from this source after regression, to form
|
||||
the root_dispersion field in the packets transmitted to clients or
|
||||
peers.
|
||||
|
||||
stratum is the stratum of the source that supplied the sample.
|
||||
|
||||
*/
|
||||
|
||||
extern void SRC_AccumulateSample(SRC_Instance instance, struct timeval *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum, NTP_Leap leap_status);
|
||||
|
||||
/* This routine indicates that packets with valid headers are being
|
||||
received from the designated source */
|
||||
extern void SRC_SetReachable(SRC_Instance instance);
|
||||
|
||||
/* This routine indicates that we are no longer receiving packets with
|
||||
valid headers from the designated source */
|
||||
extern void SRC_UnsetReachable(SRC_Instance instance);
|
||||
|
||||
/* This routine is used to select the best source from amongst those
|
||||
we currently have valid data on, and use it as the tracking base
|
||||
for the local time. If match_addr is zero it means we must start
|
||||
tracking the (newly) selected reference unconditionally, otherwise
|
||||
it is equal to the address we should track if it turns out to be
|
||||
the best reference. (This avoids updating the frequency tracking
|
||||
for every sample from other sources - only the ones from the
|
||||
selected reference make a difference) */
|
||||
extern void SRC_SelectSource(unsigned long match_addr);
|
||||
|
||||
/* Predict the offset of the local clock relative to a given source at
|
||||
a given local cooked time. Positive indicates local clock is FAST
|
||||
relative to reference. */
|
||||
extern double SRC_PredictOffset(SRC_Instance inst, struct timeval *when);
|
||||
|
||||
/* Return the minimum peer delay amongst the previous samples
|
||||
currently held in the register */
|
||||
extern double SRC_MinRoundTripDelay(SRC_Instance inst);
|
||||
|
||||
extern void SRC_DumpSources(void);
|
||||
|
||||
extern void SRC_ReloadSources(void);
|
||||
|
||||
extern int SRC_IsSyncPeer(SRC_Instance inst);
|
||||
extern int SRC_ReadNumberOfSources(void);
|
||||
extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now);
|
||||
|
||||
extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report);
|
||||
|
||||
typedef enum {
|
||||
SRC_Skew_Decrease,
|
||||
SRC_Skew_Nochange,
|
||||
SRC_Skew_Increase
|
||||
} SRC_Skew_Direction;
|
||||
|
||||
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
|
||||
|
||||
#endif /* GOT_SOURCES_H */
|
||||
|
||||
931
sourcestats.c
Normal file
931
sourcestats.c
Normal file
@@ -0,0 +1,931 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sourcestats.c,v 1.39 2003/03/24 23:35:43 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This file contains the routines that do the statistical
|
||||
analysis on the samples obtained from the sources,
|
||||
to determined frequencies and error bounds. */
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sourcestats.h"
|
||||
#include "memory.h"
|
||||
#include "regress.h"
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "local.h"
|
||||
#include "mkdirpp.h"
|
||||
|
||||
/* ================================================== */
|
||||
/* Define the maxumum number of samples that we want
|
||||
to store per source */
|
||||
#define MAX_SAMPLES 64
|
||||
|
||||
/* This is the assumed worst case bound on an unknown frequency,
|
||||
2000ppm, which would be pretty bad */
|
||||
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
|
||||
|
||||
/* Day number of 1 Jan 1970 */
|
||||
#define MJD_1970 40587
|
||||
|
||||
/* ================================================== */
|
||||
/* File to which statistics are logged, NULL if none */
|
||||
static FILE *logfile = NULL;
|
||||
static char *logfilename = NULL;
|
||||
static unsigned long logwrites = 0;
|
||||
|
||||
#define STATISTICS_LOG "statistics.log"
|
||||
|
||||
/* ================================================== */
|
||||
/* This data structure is used to hold the history of data from the
|
||||
source */
|
||||
|
||||
struct SST_Stats_Record {
|
||||
|
||||
/* Reference ID of source, used for logging to statistics log */
|
||||
unsigned long refid;
|
||||
|
||||
/* Number of samples currently stored. sample[n_samples-1] is the
|
||||
newest. The samples are expected to be sorted in order, but that
|
||||
probably doesn't matter. */
|
||||
int n_samples;
|
||||
|
||||
/* The index in the registers of the best individual sample that we
|
||||
are holding, in terms of the minimum root distance at the present
|
||||
time */
|
||||
int best_single_sample;
|
||||
|
||||
/* This is the estimated offset (+ve => local fast) at a particular time */
|
||||
double estimated_offset;
|
||||
double estimated_offset_sd;
|
||||
struct timeval offset_time;
|
||||
|
||||
/* Number of runs of the same sign amongst the residuals */
|
||||
int nruns;
|
||||
|
||||
/* This value contains the estimated frequency. This is the number
|
||||
of seconds that the local clock gains relative to the reference
|
||||
source per unit local time. (Positive => local clock fast,
|
||||
negative => local clock slow) */
|
||||
double estimated_frequency;
|
||||
|
||||
/* This is the assumed worst case bounds on the estimated frequency.
|
||||
We assume that the true frequency lies within +/- half this much
|
||||
about estimated_frequency */
|
||||
double skew;
|
||||
|
||||
/* This is the direction the skew went in at the last sample */
|
||||
SST_Skew_Direction skew_dirn;
|
||||
|
||||
/* This is the estimated residual variance of the data points */
|
||||
double variance;
|
||||
|
||||
/* This array contains the sample epochs, in terms of the local
|
||||
clock. */
|
||||
struct timeval sample_times[MAX_SAMPLES];
|
||||
|
||||
/* This is an array of offsets, in seconds, corresponding to the
|
||||
sample times. In this module, we use the convention that
|
||||
positive means the local clock is FAST of the source and negative
|
||||
means it is SLOW. This is contrary to the convention in the NTP
|
||||
stuff; that part of the code is written to correspond with
|
||||
RFC1305 conventions. */
|
||||
double offsets[MAX_SAMPLES];
|
||||
|
||||
/* This is an array of the offsets as originally measured. Local
|
||||
clock fast of real time is indicated by positive values. This
|
||||
array is not slewed to adjust the readings when we apply
|
||||
adjustments to the local clock, as is done for the array
|
||||
'offset'. */
|
||||
double orig_offsets[MAX_SAMPLES];
|
||||
|
||||
/* This is an array of peer delays, in seconds, being the roundtrip
|
||||
measurement delay to the peer */
|
||||
double peer_delays[MAX_SAMPLES];
|
||||
|
||||
/* This is an array of peer dispersions, being the skew and local
|
||||
precision dispersion terms from sampling the peer */
|
||||
double peer_dispersions[MAX_SAMPLES];
|
||||
|
||||
/* This array contains the root delays of each sample, in seconds */
|
||||
double root_delays[MAX_SAMPLES];
|
||||
|
||||
/* This array contains the root dispersions of each sample at the
|
||||
time of the measurements */
|
||||
double root_dispersions[MAX_SAMPLES];
|
||||
|
||||
/* This array contains the weights to be used in the regression
|
||||
analysis for each of the samples. */
|
||||
double weights[MAX_SAMPLES];
|
||||
|
||||
/* This array contains the strata that were associated with the sources
|
||||
at the times the samples were generated */
|
||||
int strata[MAX_SAMPLES];
|
||||
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_Initialise(void)
|
||||
{
|
||||
char *direc;
|
||||
|
||||
if (CNF_GetLogStatistics()) {
|
||||
direc = CNF_GetLogDir();
|
||||
if (!mkdir_and_parents(direc)) {
|
||||
LOG(LOGS_ERR, LOGF_SourceStats, "Could not create directory %s", direc);
|
||||
logfile = NULL;
|
||||
} else {
|
||||
logfilename = MallocArray(char, 2 + strlen(direc) + strlen(STATISTICS_LOG));
|
||||
strcpy(logfilename, direc);
|
||||
strcat(logfilename, "/");
|
||||
strcat(logfilename, STATISTICS_LOG);
|
||||
logfile = fopen(logfilename, "a");
|
||||
if (!logfile) {
|
||||
LOG(LOGS_WARN, LOGF_SourceStats, "Couldn't open logfile %s for update", logfilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_Finalise(void)
|
||||
{
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
|
||||
SST_Stats
|
||||
SST_CreateInstance(unsigned long refid)
|
||||
{
|
||||
SST_Stats inst;
|
||||
inst = MallocNew(struct SST_Stats_Record);
|
||||
inst->refid = refid;
|
||||
inst->n_samples = 0;
|
||||
inst->estimated_frequency = 0;
|
||||
inst->skew = 2000.0e-6;
|
||||
inst->skew_dirn = SST_Skew_Nochange;
|
||||
inst->estimated_offset = 0.0;
|
||||
inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */
|
||||
inst->variance = 16.0;
|
||||
inst->nruns = 0;
|
||||
return inst;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function deletes an instance of the statistics handler. */
|
||||
|
||||
void
|
||||
SST_DeleteInstance(SST_Stats inst)
|
||||
{
|
||||
Free(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
move_stats_entry(SST_Stats inst, int src, int dest)
|
||||
{
|
||||
inst->sample_times[dest] = inst->sample_times[src];
|
||||
inst->offsets[dest] = inst->offsets[src];
|
||||
inst->orig_offsets[dest] = inst->orig_offsets[src];
|
||||
inst->peer_delays[dest] = inst->peer_delays[src];
|
||||
inst->peer_dispersions[dest] = inst->peer_dispersions[src];
|
||||
inst->root_delays[dest] = inst->root_delays[src];
|
||||
inst->root_dispersions[dest] = inst->root_dispersions[src];
|
||||
inst->weights[dest] = inst->weights[src];
|
||||
inst->strata[dest] = inst->strata[src];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function is called to prune the register down when it is full.
|
||||
For now, just discard the oldest sample. */
|
||||
|
||||
static void
|
||||
prune_register(SST_Stats inst, int new_oldest, int *bad_points)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (!(new_oldest < inst->n_samples)) {
|
||||
CROAK("new_oldest should be < n_samples");
|
||||
}
|
||||
|
||||
for (i=0, j=new_oldest; j<inst->n_samples; j++) {
|
||||
if (!bad_points || !bad_points[j]) {
|
||||
if (j != i) {
|
||||
move_stats_entry(inst, j, i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
inst->n_samples = i;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
|
||||
double offset,
|
||||
double peer_delay, double peer_dispersion,
|
||||
double root_delay, double root_dispersion,
|
||||
int stratum)
|
||||
{
|
||||
int n;
|
||||
#if 0
|
||||
double root_distance;
|
||||
#endif
|
||||
|
||||
if (inst->n_samples == MAX_SAMPLES) {
|
||||
prune_register(inst, 1, NULL);
|
||||
}
|
||||
|
||||
n = inst->n_samples;
|
||||
|
||||
inst->sample_times[n] = *sample_time;
|
||||
inst->offsets[n] = offset;
|
||||
inst->orig_offsets[n] = offset;
|
||||
inst->peer_delays[n] = peer_delay;
|
||||
inst->peer_dispersions[n] = peer_dispersion;
|
||||
inst->root_delays[n] = root_delay;
|
||||
inst->root_dispersions[n] = root_dispersion;
|
||||
|
||||
#if 0
|
||||
/* The weight is worked out when we run the regression algorithm */
|
||||
root_distance = root_dispersion + 0.5 * fabs(root_delay);
|
||||
|
||||
/* For now, this is the formula for the weight functions */
|
||||
inst->weights[n] = root_distance * root_distance;
|
||||
#endif
|
||||
|
||||
inst->strata[n] = stratum;
|
||||
|
||||
++inst->n_samples;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function is used by both the regression routines to find the
|
||||
time interval between each historical sample and the most recent
|
||||
one */
|
||||
|
||||
static void
|
||||
convert_to_intervals(SST_Stats inst, double *times_back)
|
||||
{
|
||||
struct timeval *newest_tv;
|
||||
int i;
|
||||
|
||||
newest_tv = &(inst->sample_times[inst->n_samples - 1]);
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
/* The entries in times_back[] should end up negative */
|
||||
UTI_DiffTimevalsToDouble(&(times_back[i]), &(inst->sample_times[i]), newest_tv);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
find_best_sample_index(SST_Stats inst, double *times_back)
|
||||
{
|
||||
/* With the value of skew that has been computed, see which of the
|
||||
samples offers the tightest bound on root distance */
|
||||
|
||||
double root_distance, best_root_distance;
|
||||
double elapsed;
|
||||
int i, n, best_index;
|
||||
|
||||
n = inst->n_samples - 1;
|
||||
best_root_distance = inst->root_dispersions[n] + 0.5 * fabs(inst->root_delays[n]);
|
||||
best_index = n;
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d brd=%f", n, best_root_distance);
|
||||
#endif
|
||||
for (i=0; i<n; i++) {
|
||||
elapsed = -times_back[i];
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d i=%d latest=[%s] doing=[%s] elapsed=%f", n, i,
|
||||
UTI_TimevalToString(&(inst->sample_times[n])),
|
||||
UTI_TimevalToString(&(inst->sample_times[i])),
|
||||
elapsed);
|
||||
#endif
|
||||
|
||||
/* Because the loop does not consider the most recent sample, this assertion must hold */
|
||||
if (elapsed <= 0.0) {
|
||||
LOG(LOGS_ERR, LOGF_SourceStats, "Elapsed<0! n=%d i=%d latest=[%s] doing=[%s] elapsed=%f",
|
||||
n, i,
|
||||
UTI_TimevalToString(&(inst->sample_times[n])),
|
||||
UTI_TimevalToString(&(inst->sample_times[i])),
|
||||
elapsed);
|
||||
|
||||
elapsed = fabs(elapsed);
|
||||
}
|
||||
|
||||
root_distance = inst->root_dispersions[i] + elapsed * inst->skew + 0.5 * fabs(inst->root_delays[i]);
|
||||
if (root_distance < best_root_distance) {
|
||||
best_root_distance = root_distance;
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
inst->best_single_sample = best_index;
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d best_index=%d", n, best_index);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This defines the assumed ratio between the standard deviation of
|
||||
the samples and the peer distance as measured from the round trip
|
||||
time. E.g. a value of 4 means that we think the standard deviation
|
||||
is a quarter of the peer distance */
|
||||
|
||||
#define SD_TO_DIST_RATIO 8.0
|
||||
|
||||
/* ================================================== */
|
||||
/* This function runs the linear regression operation on the data. It
|
||||
finds the set of most recent samples that give the tightest
|
||||
confidence interval for the frequency, and truncates the register
|
||||
down to that number of samples */
|
||||
|
||||
void
|
||||
SST_DoNewRegression(SST_Stats inst)
|
||||
{
|
||||
double times_back[MAX_SAMPLES];
|
||||
double peer_distances[MAX_SAMPLES];
|
||||
|
||||
int bad_points[MAX_SAMPLES];
|
||||
int degrees_of_freedom;
|
||||
int best_start;
|
||||
double est_intercept, est_slope, est_var, est_intercept_sd, est_slope_sd;
|
||||
int i, nruns;
|
||||
double min_distance;
|
||||
double sd_weight;
|
||||
double old_skew, old_freq, stress;
|
||||
|
||||
int regression_ok;
|
||||
|
||||
convert_to_intervals(inst, times_back);
|
||||
|
||||
if (inst->n_samples > 0) {
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
peer_distances[i] = 0.5 * fabs(inst->peer_delays[i]) + inst->peer_dispersions[i];
|
||||
}
|
||||
|
||||
min_distance = peer_distances[0];
|
||||
for (i=1; i<inst->n_samples; i++) {
|
||||
if (peer_distances[i] < min_distance) {
|
||||
min_distance = peer_distances[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* And now, work out the weight vector */
|
||||
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / min_distance;
|
||||
inst->weights[i] = sd_weight * sd_weight;
|
||||
}
|
||||
}
|
||||
|
||||
regression_ok = RGR_FindBestRegression(times_back, inst->offsets, inst->weights,
|
||||
inst->n_samples,
|
||||
&est_intercept, &est_slope, &est_var,
|
||||
&est_intercept_sd, &est_slope_sd,
|
||||
&best_start, &nruns, °rees_of_freedom);
|
||||
|
||||
/* This is a legacy of when the regression routine found outliers
|
||||
for us. We don't use it anymore. */
|
||||
memset((void *) bad_points, 0, MAX_SAMPLES * sizeof(int));
|
||||
|
||||
if (regression_ok) {
|
||||
|
||||
old_skew = inst->skew;
|
||||
old_freq = inst->estimated_frequency;
|
||||
|
||||
inst->estimated_frequency = est_slope;
|
||||
inst->skew = est_slope_sd * RGR_GetTCoef(degrees_of_freedom);
|
||||
inst->estimated_offset = est_intercept;
|
||||
inst->offset_time = inst->sample_times[inst->n_samples - 1];
|
||||
inst->estimated_offset_sd = est_intercept_sd;
|
||||
inst->variance = est_var;
|
||||
inst->nruns = nruns;
|
||||
|
||||
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
|
||||
|
||||
if (best_start > 0) {
|
||||
/* If we are throwing old data away, retain the current
|
||||
assumptions about the skew */
|
||||
inst->skew_dirn = SST_Skew_Nochange;
|
||||
} else {
|
||||
if (inst->skew < old_skew) {
|
||||
inst->skew_dirn = SST_Skew_Decrease;
|
||||
} else {
|
||||
inst->skew_dirn = SST_Skew_Increase;
|
||||
}
|
||||
}
|
||||
|
||||
if (logfile) {
|
||||
|
||||
if (((logwrites++) % 32) == 0) {
|
||||
fprintf(logfile,
|
||||
"==============================================================================================================\n"
|
||||
" Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr\n"
|
||||
"==============================================================================================================\n");
|
||||
}
|
||||
|
||||
|
||||
fprintf(logfile, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d\n",
|
||||
UTI_TimeToLogForm(inst->offset_time.tv_sec),
|
||||
UTI_IPToDottedQuad(inst->refid),
|
||||
sqrt(inst->variance),
|
||||
inst->estimated_offset,
|
||||
inst->estimated_offset_sd,
|
||||
inst->estimated_frequency,
|
||||
inst->skew,
|
||||
stress,
|
||||
inst->n_samples,
|
||||
best_start, nruns);
|
||||
|
||||
fflush(logfile);
|
||||
}
|
||||
|
||||
prune_register(inst, best_start, bad_points);
|
||||
|
||||
} else {
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "too few points (%d) for regression", inst->n_samples);
|
||||
#endif
|
||||
inst->estimated_frequency = 0.0;
|
||||
inst->skew = WORST_CASE_FREQ_BOUND;
|
||||
}
|
||||
|
||||
find_best_sample_index(inst, times_back);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function does a simple regression on what is in the register,
|
||||
without trying to optimise the error bounds on the frequency by
|
||||
deleting old samples */
|
||||
|
||||
void
|
||||
SST_DoUpdateRegression(SST_Stats inst)
|
||||
{
|
||||
double times_back[MAX_SAMPLES];
|
||||
double freq_error_bound;
|
||||
double est_intercept, est_slope, est_var_base, est_intercept_sd, est_slope_sd;
|
||||
|
||||
convert_to_intervals(inst, times_back);
|
||||
|
||||
if (inst->n_samples >= 3) { /* Otherwise, we're wasting our time - we
|
||||
can't do a useful linear regression
|
||||
with less than 3 points */
|
||||
|
||||
RGR_WeightedRegression(times_back, inst->offsets, inst->weights,
|
||||
inst->n_samples,
|
||||
&est_intercept, &est_slope, &est_var_base,
|
||||
&est_intercept_sd, &est_slope_sd);
|
||||
|
||||
freq_error_bound = est_slope_sd * RGR_GetTCoef(inst->n_samples - 2);
|
||||
|
||||
inst->estimated_frequency = est_slope;
|
||||
inst->skew = freq_error_bound;
|
||||
|
||||
} else {
|
||||
inst->estimated_frequency = 0.0;
|
||||
inst->skew = WORST_CASE_FREQ_BOUND;
|
||||
}
|
||||
|
||||
find_best_sample_index(inst, times_back);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_GetReferenceData(SST_Stats inst, struct timeval *now,
|
||||
int *stratum, double *offset,
|
||||
double *root_delay, double *root_dispersion,
|
||||
double *frequency, double *skew)
|
||||
{
|
||||
|
||||
double elapsed;
|
||||
int n;
|
||||
|
||||
*frequency = inst->estimated_frequency;
|
||||
*skew = inst->skew;
|
||||
|
||||
n = inst->best_single_sample;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->sample_times[n]));
|
||||
*root_delay = inst->root_delays[n];
|
||||
*root_dispersion = inst->root_dispersions[n] + elapsed * inst->skew;
|
||||
*offset = inst->offsets[n] + elapsed * inst->estimated_frequency;
|
||||
*stratum = inst->strata[n];
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f skew=%f del=%f disp=%f ofs=%f str=%d",
|
||||
n, *frequency, *skew, *root_delay, *root_dispersion, *offset, *stratum);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return the assumed worst case range of values that this source's
|
||||
frequency lies within. Frequency is defined as the amount of time
|
||||
the local clock gains relative to the source per unit local clock
|
||||
time. */
|
||||
void
|
||||
SST_GetFrequencyRange(SST_Stats inst,
|
||||
double *lo, double *hi)
|
||||
{
|
||||
double freq, skew;
|
||||
freq = inst->estimated_frequency;
|
||||
skew = inst->skew;
|
||||
*lo = freq - skew;
|
||||
*hi = freq + skew;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_GetSelectionData(SST_Stats inst, struct timeval *now,
|
||||
int *stratum,
|
||||
double *best_offset, double *best_root_delay,
|
||||
double *best_root_dispersion,
|
||||
double *variance, int *average_ok)
|
||||
{
|
||||
double average_offset;
|
||||
double sample_elapsed;
|
||||
double elapsed;
|
||||
int n;
|
||||
double peer_distance;
|
||||
|
||||
n = inst->best_single_sample;
|
||||
*stratum = inst->strata[n];
|
||||
*variance = inst->variance;
|
||||
|
||||
peer_distance = inst->peer_dispersions[n] + 0.5 * fabs(inst->peer_delays[n]);
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &(inst->offset_time));
|
||||
|
||||
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &(inst->sample_times[n]));
|
||||
*best_offset = inst->offsets[n] + sample_elapsed * inst->estimated_frequency;
|
||||
*best_root_delay = inst->root_delays[n];
|
||||
*best_root_dispersion = inst->root_dispersions[n] + sample_elapsed * inst->skew;
|
||||
|
||||
average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed;
|
||||
if (fabs(average_offset - *best_offset) <= peer_distance) {
|
||||
*average_ok = 1;
|
||||
} else {
|
||||
*average_ok = 0;
|
||||
}
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d off=%f del=%f dis=%f var=%f pdist=%f avoff=%f avok=%d",
|
||||
n, *best_offset, *best_root_delay, *best_root_dispersion, *variance,
|
||||
peer_distance, average_offset, *average_ok);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_GetTrackingData(SST_Stats inst, struct timeval *now,
|
||||
double *average_offset, double *offset_sd,
|
||||
double *accrued_dispersion,
|
||||
double *frequency, double *skew)
|
||||
{
|
||||
int n;
|
||||
double peer_distance;
|
||||
double elapsed_offset, elapsed_sample;
|
||||
|
||||
n = inst->best_single_sample;
|
||||
|
||||
*frequency = inst->estimated_frequency;
|
||||
*skew = inst->skew;
|
||||
|
||||
peer_distance = inst->peer_dispersions[n] + 0.5 * fabs(inst->peer_delays[n]);
|
||||
UTI_DiffTimevalsToDouble(&elapsed_offset, now, &(inst->offset_time));
|
||||
*average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed_offset;
|
||||
*offset_sd = inst->estimated_offset_sd + elapsed_offset * inst->skew;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed_sample, now, &(inst->sample_times[n]));
|
||||
*accrued_dispersion = inst->skew * elapsed_sample;
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "n=%d freq=%f (%.3fppm) skew=%f (%.3fppm) pdist=%f avoff=%f offsd=%f accrdis=%f",
|
||||
n, *frequency, 1.0e6* *frequency, *skew, 1.0e6* *skew, peer_distance, *average_offset, *offset_sd, *accrued_dispersion);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffset)
|
||||
{
|
||||
int n, i;
|
||||
double elapsed;
|
||||
double delta_time;
|
||||
struct timeval *sample, prev;
|
||||
double prev_offset, prev_freq;
|
||||
|
||||
n = inst->n_samples;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
sample = &(inst->sample_times[i]);
|
||||
prev = *sample;
|
||||
#if 0
|
||||
UTI_AdjustTimeval(sample, when, sample, dfreq, doffset);
|
||||
/* Can't easily use this because we need to slew offset */
|
||||
#endif
|
||||
UTI_DiffTimevalsToDouble(&elapsed, when, sample);
|
||||
delta_time = elapsed * dfreq - doffset;
|
||||
UTI_AddDoubleToTimeval(sample, delta_time, sample);
|
||||
prev_offset = inst->offsets[i];
|
||||
inst->offsets[i] += delta_time;
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "i=%d old_st=[%s] new_st=[%s] old_off=%f new_off=%f",
|
||||
i, UTI_TimevalToString(&prev), UTI_TimevalToString(sample),
|
||||
prev_offset, inst->offsets[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Do a half-baked update to the regression estimates */
|
||||
UTI_DiffTimevalsToDouble(&elapsed, when, &(inst->offset_time));
|
||||
prev = inst->offset_time;
|
||||
delta_time = elapsed * dfreq - doffset;
|
||||
UTI_AddDoubleToTimeval(&(inst->offset_time), delta_time, &(inst->offset_time));
|
||||
prev_offset = inst->estimated_offset;
|
||||
prev_freq = inst->estimated_frequency;
|
||||
inst->estimated_offset += delta_time;
|
||||
inst->estimated_frequency -= dfreq;
|
||||
|
||||
#ifdef TRACEON
|
||||
LOG(LOGS_INFO, LOGF_SourceStats, "old_off_time=[%s] new=[%s] old_off=%f new_off=%f old_freq=%.3fppm new_freq=%.3fppm",
|
||||
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
|
||||
prev_offset, inst->estimated_offset,
|
||||
1.0e6*prev_freq, 1.0e6*inst->estimated_frequency);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
SST_PredictOffset(SST_Stats inst, struct timeval *when)
|
||||
{
|
||||
double elapsed;
|
||||
|
||||
if (inst->n_samples < 3) {
|
||||
/* We don't have any useful statistics, and presumably the poll
|
||||
interval is minimal. We can't do any useful prediction other
|
||||
than use the latest sample */
|
||||
return inst->offsets[inst->n_samples - 1];
|
||||
} else {
|
||||
UTI_DiffTimevalsToDouble(&elapsed, when, &inst->offset_time);
|
||||
return inst->estimated_offset + elapsed * inst->estimated_frequency;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
SST_MinRoundTripDelay(SST_Stats inst)
|
||||
{
|
||||
double min_delay, delay;
|
||||
int i;
|
||||
|
||||
if (inst->n_samples == 0) {
|
||||
return DBL_MAX;
|
||||
} else {
|
||||
min_delay = fabs(inst->peer_delays[0]);
|
||||
for (i=1; i<inst->n_samples; i++) {
|
||||
delay = fabs(inst->peer_delays[i]);
|
||||
if (delay < min_delay) {
|
||||
min_delay = delay;
|
||||
}
|
||||
}
|
||||
return min_delay;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This is used to save the register to a file, so that we can reload
|
||||
it after restarting the daemon */
|
||||
|
||||
void
|
||||
SST_SaveToFile(SST_Stats inst, FILE *out)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(out, "%d\n", inst->n_samples);
|
||||
|
||||
for(i=0; i<inst->n_samples; i++) {
|
||||
|
||||
fprintf(out, "%08lx %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
|
||||
(unsigned long) inst->sample_times[i].tv_sec,
|
||||
(unsigned long) inst->sample_times[i].tv_usec,
|
||||
inst->offsets[i],
|
||||
inst->orig_offsets[i],
|
||||
inst->peer_delays[i],
|
||||
inst->peer_dispersions[i],
|
||||
inst->root_delays[i],
|
||||
inst->root_dispersions[i],
|
||||
inst->weights[i],
|
||||
inst->strata[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This is used to reload samples from a file */
|
||||
|
||||
int
|
||||
SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
{
|
||||
int i, line_number;
|
||||
char line[1024];
|
||||
unsigned long sec, usec;
|
||||
|
||||
if (fgets(line, sizeof(line), in) &&
|
||||
(sscanf(line, "%d", &inst->n_samples) == 1)) {
|
||||
|
||||
line_number = 2;
|
||||
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
if (!fgets(line, sizeof(line), in) ||
|
||||
(sscanf(line, "%lx%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
|
||||
&(sec), &(usec),
|
||||
&(inst->offsets[i]),
|
||||
&(inst->orig_offsets[i]),
|
||||
&(inst->peer_delays[i]),
|
||||
&(inst->peer_dispersions[i]),
|
||||
&(inst->root_delays[i]),
|
||||
&(inst->root_dispersions[i]),
|
||||
&(inst->weights[i]),
|
||||
&(inst->strata[i])) != 10)) {
|
||||
|
||||
/* This is the branch taken if the read FAILED */
|
||||
|
||||
LOG(LOGS_WARN, LOGF_SourceStats, "Failed to read data from line %d of dump file", line_number);
|
||||
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
/* This is the branch taken if the read is SUCCESSFUL */
|
||||
inst->sample_times[i].tv_sec = sec;
|
||||
inst->sample_times[i].tv_usec = usec;
|
||||
|
||||
line_number++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_SourceStats, "Could not read number of samples from dump file");
|
||||
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timeval *now)
|
||||
{
|
||||
int n, nb;
|
||||
double est_offset, est_err, elapsed, sample_elapsed;
|
||||
struct timeval ago;
|
||||
|
||||
if (inst->n_samples > 0) {
|
||||
n = inst->n_samples - 1;
|
||||
report->orig_latest_meas = (long)(0.5 + 1.0e6 * inst->orig_offsets[n]);
|
||||
report->latest_meas = (long)(0.5 + 1.0e6 * inst->offsets[n]);
|
||||
report->latest_meas_err = (unsigned long)(0.5 + 1.0e6 * (0.5*inst->root_delays[n] + inst->root_dispersions[n]));
|
||||
report->stratum = inst->strata[n];
|
||||
|
||||
UTI_DiffTimevals(&ago, now, &inst->sample_times[n]);
|
||||
report->latest_meas_ago = ago.tv_sec;
|
||||
|
||||
if (inst->n_samples > 3) {
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &inst->offset_time);
|
||||
nb = inst->best_single_sample;
|
||||
UTI_DiffTimevalsToDouble(&sample_elapsed, now, &(inst->sample_times[nb]));
|
||||
est_offset = inst->estimated_offset + elapsed * inst->estimated_frequency;
|
||||
est_err = (inst->estimated_offset_sd +
|
||||
sample_elapsed * inst->skew +
|
||||
(0.5*inst->root_delays[nb] + inst->root_dispersions[nb]));
|
||||
report->est_offset = (long)(0.5 + 1.0e6 * est_offset);
|
||||
report->est_offset_err = (unsigned long) (0.5 + 1.0e6 * est_err);
|
||||
report->resid_freq = (long) (0.5 * 1.0e9 * inst->estimated_frequency);
|
||||
report->resid_skew = (unsigned long) (0.5 + 1.0e9 * inst->skew);
|
||||
} else {
|
||||
report->est_offset = report->latest_meas;
|
||||
report->est_offset_err = report->latest_meas_err;
|
||||
report->resid_freq = 0;
|
||||
report->resid_skew = 0;
|
||||
}
|
||||
} else {
|
||||
report->orig_latest_meas = 0;
|
||||
report->latest_meas = 0;
|
||||
report->latest_meas_err = 0;
|
||||
report->stratum = 0;
|
||||
report->est_offset = 0;
|
||||
report->est_offset_err = 0;
|
||||
report->resid_freq = 0;
|
||||
report->resid_skew = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
SST_Skew_Direction SST_LastSkewChange(SST_Stats inst)
|
||||
{
|
||||
return inst->skew_dirn;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report)
|
||||
{
|
||||
double dspan;
|
||||
int n;
|
||||
|
||||
report->n_samples = inst->n_samples;
|
||||
report->n_runs = inst->nruns;
|
||||
|
||||
if (inst->n_samples > 1) {
|
||||
n = inst->n_samples - 1;
|
||||
UTI_DiffTimevalsToDouble(&dspan, &inst->sample_times[n], &inst->sample_times[0]);
|
||||
report->span_seconds = (unsigned long) (dspan + 0.5);
|
||||
} else {
|
||||
report->span_seconds = 0;
|
||||
}
|
||||
|
||||
report->resid_freq_ppm = 1.0e6 * inst->estimated_frequency;
|
||||
report->skew_ppm = 1.0e6 * inst->skew;
|
||||
report->sd_us = 1.0e6 * sqrt(inst->variance);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_CycleLogFile(void)
|
||||
{
|
||||
if (logfile && logfilename) {
|
||||
fclose(logfile);
|
||||
logfile = fopen(logfilename, "a");
|
||||
if (!logfile) {
|
||||
LOG(LOGS_WARN, LOGF_SourceStats, "Could not reopen logfile %s", logfilename);
|
||||
}
|
||||
logwrites = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
156
sourcestats.h
Normal file
156
sourcestats.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sourcestats.h,v 1.13 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for module that deals with the measurements and statistics of
|
||||
each of the sources. */
|
||||
|
||||
#ifndef GOT_SOURCESTATS_H
|
||||
#define GOT_SOURCESTATS_H
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "reports.h"
|
||||
|
||||
typedef struct SST_Stats_Record *SST_Stats;
|
||||
|
||||
/* Init and fini functions */
|
||||
extern void SST_Initialise(void);
|
||||
extern void SST_Finalise(void);
|
||||
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
extern SST_Stats SST_CreateInstance(unsigned long refid);
|
||||
|
||||
/* This function deletes an instance of the statistics handler. */
|
||||
extern void SST_DeleteInstance(SST_Stats inst);
|
||||
|
||||
/* This function accumulates a single sample into the statistics handler
|
||||
|
||||
sample_time is the epoch at which the sample is to be considered to
|
||||
have been made.
|
||||
|
||||
offset is the offset of the local clock relative to the source in
|
||||
seconds. Positive indicates that the local clock if FAST (contrary
|
||||
to the NTP parts of the software)
|
||||
|
||||
root_distance is the Lambda+Delta/2 term in RFC1305, but excluding
|
||||
the extra dispersion due to the residual standard deviation after
|
||||
we have done the regression fit.
|
||||
|
||||
stratum is the stratum of the source from which the sample came.
|
||||
*/
|
||||
|
||||
extern void SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time, double offset, double peer_delay, double peer_dispersion, double root_delay, double root_dispersion, int stratum);
|
||||
|
||||
/* This function runs the linear regression operation on the data. It
|
||||
finds the set of most recent samples that give the tightest
|
||||
confidence interval for the frequency, and truncates the register
|
||||
down to that number of samples. */
|
||||
extern void SST_DoNewRegression(SST_Stats inst);
|
||||
|
||||
/* This function does a simple regression on what is in the register,
|
||||
without trying to optimise the error bounds on the frequency by
|
||||
deleting old samples */
|
||||
extern void SST_DoUpdateRegression(SST_Stats inst);
|
||||
|
||||
/* Return the assumed worst case range of values that this source's
|
||||
frequency lies within. Frequency is defined as the amount of time
|
||||
the local clock gains relative to the source per unit local clock
|
||||
time. */
|
||||
extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
|
||||
|
||||
/* Get data needed for selection */
|
||||
extern void
|
||||
SST_GetSelectionData(SST_Stats inst, struct timeval *now,
|
||||
int *stratum,
|
||||
double *best_offset, double *best_root_delay,
|
||||
double *best_root_dispersion,
|
||||
double *variance,
|
||||
int *average_ok);
|
||||
|
||||
/* Get data needed when setting up tracking on this source */
|
||||
extern void
|
||||
SST_GetTrackingData(SST_Stats inst, struct timeval *now,
|
||||
double *average_offset, double *offset_sd,
|
||||
double *accrued_dispersion,
|
||||
double *frequency, double *skew);
|
||||
|
||||
/* Get parameters for using this source as the reference */
|
||||
extern void
|
||||
SST_GetReferenceData(SST_Stats inst, struct timeval *now,
|
||||
int *stratum, double *offset,
|
||||
double *root_delay, double *root_dispersion,
|
||||
double *frequency, double *skew);
|
||||
|
||||
|
||||
|
||||
/* This routine is called when the local machine clock parameters are
|
||||
changed. It adjusts all existing samples that we are holding for
|
||||
each peer so that it looks like they were made under the new clock
|
||||
regime rather than the old one.
|
||||
|
||||
when = cooked local time when the change occurs
|
||||
|
||||
dfreq = delta frequency. positive means the clock has been adjusted
|
||||
because it was previously gaining time relative to the external
|
||||
reference(s).
|
||||
|
||||
doffset = offset slewed onto local clock. positive => local clock
|
||||
has been made fast by that amount.
|
||||
|
||||
*/
|
||||
|
||||
extern void SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffset);
|
||||
|
||||
|
||||
/* Predict the offset of the local clock relative to a given source at
|
||||
a given local cooked time. Positive indicates local clock is FAST
|
||||
relative to reference. */
|
||||
extern double SST_PredictOffset(SST_Stats inst, struct timeval *when);
|
||||
|
||||
/* Find the minimum round trip delay in the register */
|
||||
extern double SST_MinRoundTripDelay(SST_Stats inst);
|
||||
|
||||
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
|
||||
|
||||
extern int SST_LoadFromFile(SST_Stats inst, FILE *in);
|
||||
|
||||
extern void SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timeval *now);
|
||||
|
||||
extern void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report);
|
||||
|
||||
typedef enum {
|
||||
SST_Skew_Decrease,
|
||||
SST_Skew_Nochange,
|
||||
SST_Skew_Increase
|
||||
} SST_Skew_Direction;
|
||||
|
||||
extern SST_Skew_Direction SST_LastSkewChange(SST_Stats inst);
|
||||
|
||||
extern void SST_CycleLogFile(void);
|
||||
|
||||
#endif /* GOT_SOURCESTATS_H */
|
||||
|
||||
47
srcparams.h
Normal file
47
srcparams.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/srcparams.h,v 1.10 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file defining parameters that can be set on a per source basis
|
||||
*/
|
||||
|
||||
#ifndef GOT_SRCPARAMS_H
|
||||
#define GOT_SRCPARAMS_H
|
||||
|
||||
typedef struct {
|
||||
int minpoll;
|
||||
int maxpoll;
|
||||
int online;
|
||||
int auto_offline;
|
||||
int presend_minpoll;
|
||||
unsigned long authkey;
|
||||
double max_delay;
|
||||
double max_delay_ratio;
|
||||
} SourceParameters;
|
||||
|
||||
#define INACTIVE_AUTHKEY 0UL
|
||||
|
||||
#endif /* GOT_SRCPARAMS_H */
|
||||
41
strerror.c
Normal file
41
strerror.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/strerror.c,v 1.8 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Replacement strerror function for systems that don't have it
|
||||
*/
|
||||
|
||||
#ifdef SUNOS
|
||||
|
||||
#include <errno.h>
|
||||
extern char *sys_errlist[];
|
||||
|
||||
char *strerror(int n) {
|
||||
return sys_errlist[n];
|
||||
}
|
||||
|
||||
#endif /* SUNOS */
|
||||
104
sys.c
Normal file
104
sys.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys.c,v 1.11 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This file contains all the conditionally compiled bits that pull
|
||||
in the various operating-system specific modules
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
|
||||
#if defined (LINUX)
|
||||
#include "sys_linux.h"
|
||||
#endif
|
||||
|
||||
#if defined (SOLARIS)
|
||||
#include "sys_solaris.h"
|
||||
#endif
|
||||
|
||||
#if defined (SUNOS)
|
||||
#include "sys_sunos.h"
|
||||
#endif
|
||||
|
||||
#if defined (__NetBSD__)
|
||||
#include "sys_netbsd.h"
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Initialise(void)
|
||||
{
|
||||
|
||||
#if defined(LINUX)
|
||||
SYS_Linux_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
SYS_Solaris_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS)
|
||||
SYS_SunOS_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
SYS_NetBSD_Initialise();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Finalise(void)
|
||||
{
|
||||
|
||||
#if defined(LINUX)
|
||||
SYS_Linux_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
SYS_Solaris_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS)
|
||||
SYS_SunOS_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
SYS_NetBSD_Finalise();
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* ================================================== */
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
|
||||
42
sys.h
Normal file
42
sys.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys.h,v 1.7 2002/02/28 23:27:14 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the header for the file that links in the operating system-
|
||||
specific parts of the software
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_H
|
||||
#define GOT_SYS_H
|
||||
|
||||
/* Called at the start of the run to do initialisation */
|
||||
extern void SYS_Initialise(void);
|
||||
|
||||
/* Called at the end of the run to do final clean-up */
|
||||
extern void SYS_Finalise(void);
|
||||
|
||||
#endif /* GOT_SYS_H */
|
||||
850
sys_linux.c
Normal file
850
sys_linux.c
Normal file
@@ -0,0 +1,850 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys_linux.c,v 1.41 2003/07/01 20:56:23 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
This is the module specific to the Linux operating system.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "localp.h"
|
||||
#include "sys_linux.h"
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "wrap_adjtimex.h"
|
||||
|
||||
static long current_tick;
|
||||
|
||||
/* This is the value of tick, in seconds, including the current vernier
|
||||
frequency term */
|
||||
static double current_total_tick;
|
||||
|
||||
/* This is the uncompensated system tick value */
|
||||
static int nominal_tick;
|
||||
|
||||
/* This is the scaling required to go between absolute ppm and the
|
||||
scaled ppm used as an argument to adjtimex. Because chronyd is to an extent
|
||||
'closed loop' maybe it doesn't matter if this is wrongly determined, UNLESS
|
||||
the system's ppm error is close to a multiple of HZ, in which case the
|
||||
relationship between changing the frequency and changing the value of 'tick'
|
||||
will be wrong. This would (I imagine) cause the system to thrash between
|
||||
two states.
|
||||
|
||||
However..., if this effect was not corrected, and the system is left offline
|
||||
for a long period, a substantial error would build up. e.g. with HZ==100,
|
||||
the correction required is 128/128.125, giving a drift of about 84 seconds
|
||||
per day). */
|
||||
static double freq_scale;
|
||||
|
||||
/* The HZ value from the kernel header file (may be over-ridden from config
|
||||
file, e.g. if chronyd binary is moved to a box whose kernel was built with a
|
||||
different HZ value). */
|
||||
static int hz;
|
||||
static double dhz; /* And dbl prec version of same for arithmetic */
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* The operating system kernel version */
|
||||
static int version_major;
|
||||
static int version_minor;
|
||||
static int version_patchlevel;
|
||||
|
||||
/* Flag indicating whether adjtimex() with txc.modes equal to zero
|
||||
returns the remaining time adjustment or not. If not we have to read
|
||||
the outstanding adjustment by setting it to zero, examining the return
|
||||
value and setting the outstanding adjustment back again. */
|
||||
|
||||
static int have_readonly_adjtime;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void handle_end_of_slew(void *anything);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
inline static int
|
||||
round(double x) {
|
||||
int y;
|
||||
y = (int)(x + 0.5);
|
||||
while ((double)y < x - 0.5) y++;
|
||||
while ((double)y > x + 0.5) y--;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Amount of outstanding offset to process */
|
||||
static double offset_register;
|
||||
|
||||
/* Flag set true if a fast slew (one done by altering tick) is being
|
||||
run at the moment */
|
||||
static int fast_slewing;
|
||||
|
||||
/* The amount by which the fast slew was supposed to slew the clock */
|
||||
static double fast_slew_wanted;
|
||||
|
||||
/* The value programmed into the kernel's 'tick' variable whilst
|
||||
slewing a large offset */
|
||||
static long slewing_tick;
|
||||
|
||||
/* The timeval (raw) at which a fast slew was started. We need to
|
||||
know this for two reasons. First, if we want to change the
|
||||
frequency midway through, we will want to abort the slew and return
|
||||
the unprocessed portion to the offset register to start again
|
||||
later. Second, when the end of the slew expires, we need to know
|
||||
precisely how long we have been slewing for, so that we can negate
|
||||
the excess and slew it back the other way. */
|
||||
static struct timeval slew_start_tv;
|
||||
|
||||
/* This is the ID returned to use by the scheduler's timeout handler.
|
||||
We need this if we subsequently wish to abort a slew, because we will have to
|
||||
dequeue the timeout */
|
||||
static SCH_TimeoutID slew_timeout_id;
|
||||
|
||||
/* The adjustment that we apply to 'tick', in seconds, whilst applying
|
||||
a fast slew */
|
||||
static double delta_total_tick;
|
||||
|
||||
/* Max amount of time that we wish to slew by using adjtime (or its
|
||||
equivalent). If more than this is outstanding, we alter the value
|
||||
of tick instead, for a set period. Set this according to the
|
||||
amount of time that a dial-up clock might need to be shifted
|
||||
assuming it is resync'ed about once per day. (TBC) */
|
||||
#define MAX_ADJUST_WITH_ADJTIME (0.2)
|
||||
|
||||
/* The amount by which we alter 'tick' when doing a large slew */
|
||||
static int slew_delta_tick;
|
||||
|
||||
/* The maximum amount by which 'tick' can be biased away from 'nominal_tick'
|
||||
(sys_adjtimex() in the kernel bounds this to 10%) */
|
||||
static int max_tick_bias;
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine stops a fast slew, determines how long the slew has
|
||||
been running for, and consequently how much adjustment has actually
|
||||
been applied. It can be used both when a slew finishes naturally
|
||||
due to a timeout, and when a slew is being aborted. */
|
||||
|
||||
static void
|
||||
stop_fast_slew(void)
|
||||
{
|
||||
struct timeval T1, T1d, T1a;
|
||||
struct timezone tz;
|
||||
double end_window;
|
||||
double fast_slew_done;
|
||||
double slew_duration;
|
||||
double introduced_dispersion;
|
||||
|
||||
/* Should never get here unless this is true */
|
||||
if (!fast_slewing) {
|
||||
CROAK("Should be fast slewing");
|
||||
}
|
||||
|
||||
/* Now set the thing off */
|
||||
if (gettimeofday(&T1, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in stop_fast_slew");
|
||||
}
|
||||
|
||||
if (TMX_SetTick(current_tick) < 0) {
|
||||
CROAK("adjtimex() failed in stop_fast_slew");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1d, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in stop_fast_slew");
|
||||
}
|
||||
|
||||
fast_slewing = 0;
|
||||
|
||||
UTI_AverageDiffTimevals(&T1, &T1d, &T1a, &end_window);
|
||||
UTI_DiffTimevalsToDouble(&slew_duration, &T1a, &slew_start_tv);
|
||||
|
||||
/* Compute the dispersion we have introduced by changing tick this
|
||||
way. If the two samples of gettimeofday differ, there is an
|
||||
uncertainty window wrt when the frequency change actually applies
|
||||
from. We handle this by adding dispersion to all statistics held
|
||||
at higher levels in the system. */
|
||||
|
||||
introduced_dispersion = end_window * delta_total_tick;
|
||||
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
|
||||
|
||||
fast_slew_done = delta_total_tick * slew_duration /
|
||||
(current_total_tick + delta_total_tick);
|
||||
|
||||
offset_register += (fast_slew_wanted + fast_slew_done);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine is called to start a clock offset adjustment */
|
||||
|
||||
static void
|
||||
initiate_slew(void)
|
||||
{
|
||||
double dseconds;
|
||||
long tick_adjust;
|
||||
long offset;
|
||||
struct timeval T0, T0d, T0a;
|
||||
struct timeval end_of_slew;
|
||||
struct timezone tz;
|
||||
double start_window;
|
||||
double introduced_dispersion;
|
||||
|
||||
/* Don't want to get here if we already have an adjust on the go! */
|
||||
if (fast_slewing) {
|
||||
CROAK("Should not be fast slewing");
|
||||
}
|
||||
|
||||
if (offset_register == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
|
||||
/* Use adjtime to do the shift */
|
||||
offset = (long)(0.5 + 1.0e6*(-offset_register));
|
||||
|
||||
if (TMX_ApplyOffset(&offset) < 0) {
|
||||
CROAK("adjtimex() failed in initiate_slew");
|
||||
}
|
||||
|
||||
offset_register = 0.0;
|
||||
|
||||
} else {
|
||||
|
||||
/* If the system clock has a high drift rate, the combination of
|
||||
current_tick + slew_delta_tick could be outside the range that adjtimex
|
||||
will accept. To prevent this, the tick adjustment that is used to slew
|
||||
an error off the clock is clamped according to what tick_adjust is.
|
||||
*/
|
||||
|
||||
long min_allowed_tick, max_allowed_tick;
|
||||
|
||||
min_allowed_tick = nominal_tick - max_tick_bias;
|
||||
max_allowed_tick = nominal_tick + max_tick_bias;
|
||||
|
||||
if (offset_register > 0) {
|
||||
slewing_tick = current_tick - slew_delta_tick;
|
||||
if (slewing_tick <= min_allowed_tick) {
|
||||
slewing_tick = min_allowed_tick + 1;
|
||||
}
|
||||
} else {
|
||||
slewing_tick = current_tick + slew_delta_tick;
|
||||
if (slewing_tick >= max_allowed_tick) {
|
||||
slewing_tick = max_allowed_tick - 1;
|
||||
}
|
||||
}
|
||||
|
||||
tick_adjust = slewing_tick - current_tick;
|
||||
|
||||
delta_total_tick = (double) tick_adjust / 1.0e6;
|
||||
dseconds = - offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
|
||||
|
||||
/* Now set the thing off */
|
||||
if (gettimeofday(&T0, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in initiate_slew");
|
||||
}
|
||||
|
||||
if (TMX_SetTick(slewing_tick) < 0) {
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "c_t=%ld ta=%ld sl_t=%ld dtt=%e",
|
||||
current_tick, tick_adjust, slewing_tick, delta_total_tick);
|
||||
CROAK("adjtimex() failed to start big slew");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T0d, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in initiate_slew");
|
||||
}
|
||||
|
||||
/* Now work out the uncertainty in when we actually started the
|
||||
slew. */
|
||||
|
||||
UTI_AverageDiffTimevals(&T0, &T0d, &T0a, &start_window);
|
||||
|
||||
/* Compute the dispersion we have introduced by changing tick this
|
||||
way. If the two samples of gettimeofday differ, there is an
|
||||
uncertainty window wrt when the frequency change actually applies
|
||||
from. We handle this by adding dispersion to all statistics held
|
||||
at higher levels in the system. */
|
||||
|
||||
introduced_dispersion = start_window * delta_total_tick;
|
||||
lcl_InvokeDispersionNotifyHandlers(introduced_dispersion);
|
||||
|
||||
fast_slewing = 1;
|
||||
slew_start_tv = T0a;
|
||||
|
||||
/* Set up timeout for end of slew */
|
||||
UTI_AddDoubleToTimeval(&T0a, dseconds, &end_of_slew);
|
||||
|
||||
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
|
||||
|
||||
fast_slew_wanted = offset_register;
|
||||
offset_register = 0.0;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This is the callback routine invoked by the scheduler at the end of
|
||||
a slew. */
|
||||
|
||||
static void
|
||||
handle_end_of_slew(void *anything)
|
||||
{
|
||||
stop_fast_slew();
|
||||
initiate_slew(); /* To do any fine trimming required */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine is used to abort a slew that is in progress, if any */
|
||||
|
||||
static void
|
||||
abort_slew(void)
|
||||
{
|
||||
if (fast_slewing) {
|
||||
stop_fast_slew();
|
||||
SCH_RemoveTimeout(slew_timeout_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This routine accrues an offset into the offset register, and starts
|
||||
a slew if required.
|
||||
|
||||
The offset argument is measured in seconds. Positive means the
|
||||
clock needs to be slewed backwards (i.e. is currently fast of true
|
||||
time) */
|
||||
|
||||
static void
|
||||
accrue_offset(double offset)
|
||||
{
|
||||
long toffset;
|
||||
|
||||
/* Add the new offset to the register */
|
||||
offset_register += offset;
|
||||
|
||||
/* Cancel any standard adjtime that is running */
|
||||
toffset = 0;
|
||||
if (TMX_ApplyOffset(&toffset) < 0) {
|
||||
CROAK("adjtimex() failed in accrue_offset");
|
||||
}
|
||||
|
||||
offset_register -= (double) toffset / 1.0e6;
|
||||
|
||||
if (!fast_slewing) {
|
||||
initiate_slew();
|
||||
} /* Otherwise, when the fast slew completes, any other stuff
|
||||
in the offset register will be applied */
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Positive means currently fast of true time, i.e. jump backwards */
|
||||
|
||||
static void
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time;
|
||||
struct timezone tz;
|
||||
|
||||
if (fast_slewing) {
|
||||
abort_slew();
|
||||
}
|
||||
|
||||
if (gettimeofday(&old_time, &tz) < 0) {
|
||||
CROAK("gettimeofday in apply_step_offset");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, &tz) < 0) {
|
||||
CROAK("settimeofday in apply_step_offset");
|
||||
}
|
||||
|
||||
initiate_slew();
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This call sets the Linux kernel frequency to a given value in parts
|
||||
per million relative to the nominal running frequency. Nominal is taken to
|
||||
be tick=10000, freq=0 (for a HZ==100 system, other values otherwise). The
|
||||
convention is that this is called with a positive argument if the local
|
||||
clock runs fast when uncompensated. */
|
||||
|
||||
static void
|
||||
set_frequency(double freq_ppm) {
|
||||
|
||||
long required_tick;
|
||||
double required_freq; /* what we use */
|
||||
double scaled_freq; /* what adjtimex & the kernel use */
|
||||
int required_delta_tick;
|
||||
int neg; /* True if estimate is that local clock runs slow,
|
||||
i.e. positive frequency correction required */
|
||||
|
||||
|
||||
/* If we in the middle of slewing the time by having the value of
|
||||
tick altered, we have to stop doing that, because the timeout
|
||||
expiry etc will change if we don't. */
|
||||
|
||||
if (fast_slewing) {
|
||||
abort_slew();
|
||||
}
|
||||
|
||||
if (freq_ppm < 0.0) {
|
||||
neg = 1;
|
||||
freq_ppm = -freq_ppm;
|
||||
} else {
|
||||
neg = 0;
|
||||
}
|
||||
|
||||
required_delta_tick = round(freq_ppm / dhz);
|
||||
required_freq = freq_ppm - dhz * (double) required_delta_tick;
|
||||
|
||||
if (neg) {
|
||||
/* Uncompensated local clock runs slow */
|
||||
required_tick = nominal_tick + required_delta_tick;
|
||||
scaled_freq = freq_scale * required_freq;
|
||||
} else {
|
||||
/* Uncompensated local clock runs fast */
|
||||
required_tick = nominal_tick - required_delta_tick;
|
||||
scaled_freq = -freq_scale * required_freq;
|
||||
}
|
||||
|
||||
if (TMX_SetFrequency(scaled_freq, required_tick) < 0) {
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "adjtimex failed for set_frequency, freq_ppm=%10.4e scaled_freq=%10.4e required_tick=%ld",
|
||||
freq_ppm, scaled_freq, required_tick);
|
||||
CROAK(buffer);
|
||||
}
|
||||
|
||||
current_tick = required_tick;
|
||||
current_total_tick = ((double)current_tick + required_freq/dhz) / 1.0e6 ;
|
||||
|
||||
initiate_slew(); /* Restart any slews that need to be restarted */
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read the ppm frequency from the kernel */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
double tick_term;
|
||||
double unscaled_freq;
|
||||
double freq_term;
|
||||
|
||||
if (TMX_GetFrequency(&unscaled_freq) < 0) {
|
||||
CROAK("adjtimex failed in read_frequency");
|
||||
}
|
||||
|
||||
/* Use current_tick here rather than txc.tick, otherwise we're
|
||||
thrown off course when doing a fast slew (in which case, txc.tick
|
||||
is nowhere near the nominal value) */
|
||||
tick_term = dhz * (double)(nominal_tick - current_tick);
|
||||
freq_term = unscaled_freq / freq_scale;
|
||||
|
||||
#if 0
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "txc.tick=%ld txc.freq=%ld tick_term=%f freq_term=%f",
|
||||
txc.tick, txc.freq, tick_term, freq_term);
|
||||
#endif
|
||||
|
||||
return tick_term - freq_term;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Given a raw time, determine the correction in seconds to generate
|
||||
the 'cooked' time. The correction has to be added to the
|
||||
raw time */
|
||||
|
||||
static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr)
|
||||
{
|
||||
|
||||
/* Correction is given by these things :
|
||||
1. Any value in offset register
|
||||
2. Amount of fast slew remaining
|
||||
3. Any amount of adjtime correction remaining */
|
||||
|
||||
|
||||
double adjtime_left;
|
||||
double fast_slew_duration;
|
||||
double fast_slew_achieved;
|
||||
double fast_slew_remaining;
|
||||
long offset;
|
||||
|
||||
if (have_readonly_adjtime) {
|
||||
if (TMX_GetOffsetLeft(&offset) < 0) {
|
||||
CROAK("adjtimex() failed in get_offset_correction");
|
||||
}
|
||||
|
||||
adjtime_left = (double)offset / 1.0e6;
|
||||
} else {
|
||||
offset = 0;
|
||||
if (TMX_ApplyOffset(&offset) < 0) {
|
||||
CROAK("adjtimex() failed in get_offset_correction");
|
||||
}
|
||||
|
||||
adjtime_left = (double)offset / 1.0e6;
|
||||
|
||||
/* txc.offset still set from return value of last call */
|
||||
if (TMX_ApplyOffset(&offset) < 0) {
|
||||
CROAK("adjtimex() failed in get_offset_correction");
|
||||
}
|
||||
}
|
||||
|
||||
if (fast_slewing) {
|
||||
UTI_DiffTimevalsToDouble(&fast_slew_duration, raw, &slew_start_tv);
|
||||
fast_slew_achieved = delta_total_tick * fast_slew_duration /
|
||||
(current_total_tick + delta_total_tick);
|
||||
fast_slew_remaining = fast_slew_wanted + fast_slew_achieved;
|
||||
} else {
|
||||
fast_slew_remaining = 0.0;
|
||||
}
|
||||
|
||||
*corr = - (offset_register + fast_slew_remaining) + adjtime_left;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
immediate_step(void)
|
||||
{
|
||||
struct timeval old_time, new_time;
|
||||
struct timezone tz;
|
||||
long offset;
|
||||
|
||||
if (fast_slewing) {
|
||||
abort_slew();
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (TMX_ApplyOffset(&offset) < 0) {
|
||||
CROAK("adjtimex() failed in immediate_step");
|
||||
}
|
||||
|
||||
offset_register -= (double) offset / 1.0e6;
|
||||
|
||||
if (gettimeofday(&old_time, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in immediate_step");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset_register, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, &tz) < 0) {
|
||||
CROAK("settimeofday() failed in immediate_step");
|
||||
}
|
||||
|
||||
offset_register = 0.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Estimate the value of HZ given the value of txc.tick that chronyd finds when
|
||||
* it starts. The only credible values are 100 (Linux/x86) or powers of 2.
|
||||
* Also, the bounds checking inside the kernel's adjtimex system call enforces
|
||||
* a +/- 10% movement of tick away from the nominal value 1e6/HZ. */
|
||||
|
||||
static void
|
||||
guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
|
||||
{
|
||||
int i, tick_lo, tick_hi, ihz;
|
||||
double tick_nominal;
|
||||
/* Pick off the hz=100 case first */
|
||||
if (tick >= 9000 && tick <= 11000) {
|
||||
*hz = 100;
|
||||
*shift_hz = 7;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */
|
||||
ihz = 1 << i;
|
||||
tick_nominal = 1.0e6 / (double) ihz;
|
||||
tick_lo = (int)(0.5 + tick_nominal*2.0/3.0);
|
||||
tick_hi = (int)(0.5 + tick_nominal*4.0/3.0);
|
||||
|
||||
if (tick_lo < tick && tick <= tick_hi) {
|
||||
*hz = ihz;
|
||||
*shift_hz = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* oh dear. doomed. */
|
||||
*hz = 0;
|
||||
*shift_hz = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Compute the scaling to use on any frequency we set, according to
|
||||
the vintage of the Linux kernel being used. */
|
||||
|
||||
static void
|
||||
get_version_specific_details(void)
|
||||
{
|
||||
int major, minor, patch;
|
||||
int shift_hz;
|
||||
double dshift_hz;
|
||||
double basic_freq_scale; /* what to use if HZ!=100 */
|
||||
int config_hz, set_config_hz; /* values of HZ from conf file */
|
||||
int set_config_freq_scale;
|
||||
double config_freq_scale;
|
||||
double calculated_freq_scale;
|
||||
struct tmx_params tmx_params;
|
||||
struct utsname uts;
|
||||
|
||||
TMX_ReadCurrentParams(&tmx_params);
|
||||
|
||||
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
|
||||
|
||||
if (!shift_hz) {
|
||||
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
|
||||
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
|
||||
} else {
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Initial txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld => hz=%d shift_hz=%d",
|
||||
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset, hz, shift_hz);
|
||||
}
|
||||
|
||||
CNF_GetLinuxHz(&set_config_hz, &config_hz);
|
||||
if (set_config_hz) hz = config_hz;
|
||||
/* (If true, presumably freq_scale will be overridden anyway, making shift_hz
|
||||
redundant too.) */
|
||||
|
||||
dhz = (double) hz;
|
||||
dshift_hz = (double)(1UL << shift_hz);
|
||||
basic_freq_scale = dshift_hz / dhz;
|
||||
nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
|
||||
slew_delta_tick = nominal_tick / 12;
|
||||
max_tick_bias = nominal_tick / 10;
|
||||
|
||||
/* The basic_freq_scale comes from:
|
||||
* the kernel increments the usec counter HZ times per second (if the timer
|
||||
interrupt period were perfect)
|
||||
* the following code in the kernel
|
||||
|
||||
time_adj (+/-)= ltemp >>
|
||||
(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
|
||||
|
||||
causes the adjtimex 'freq' value to be divided down by 1<<SHIFT_HZ.
|
||||
|
||||
The net effect is that we have to scale up the value we want by the
|
||||
reciprocal of all this, i.e. multiply by (1<<SHIFT_HZ)/HZ.
|
||||
|
||||
If HZ==100, this code in the kernel comes into play too:
|
||||
#if HZ == 100
|
||||
* Compensate for (HZ==100) != (1 << SHIFT_HZ).
|
||||
* Add 25% and 3.125% to get 128.125; => only 0.125% error (p. 14)
|
||||
*
|
||||
if (time_adj < 0)
|
||||
time_adj -= (-time_adj >> 2) + (-time_adj >> 5);
|
||||
else
|
||||
time_adj += (time_adj >> 2) + (time_adj >> 5);
|
||||
#endif
|
||||
|
||||
Special case that later.
|
||||
*/
|
||||
|
||||
if (uname(&uts) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "Cannot uname(2) to get kernel version, sorry.");
|
||||
}
|
||||
if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) {
|
||||
LOG_FATAL(LOGF_SysLinux, "Cannot read information from uname, sorry");
|
||||
}
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Linux kernel major=%d minor=%d patch=%d", major, minor, patch);
|
||||
|
||||
version_major = major;
|
||||
version_minor = minor;
|
||||
version_patchlevel = patch;
|
||||
|
||||
switch (major) {
|
||||
case 1:
|
||||
/* Does Linux v1.x even support HZ!=100? */
|
||||
switch (minor) {
|
||||
case 2:
|
||||
if (patch == 13) {
|
||||
freq_scale = (hz==100) ? (128.0 / 100.0) : basic_freq_scale ; /* I _think_! */
|
||||
have_readonly_adjtime = 1;
|
||||
} else {
|
||||
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* I guess the change from the 1.2.x scaling to the 2.0.x
|
||||
scaling must have happened during 1.3 development. I
|
||||
haven't a clue where though, until someone looks it
|
||||
up. */
|
||||
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (minor) {
|
||||
case 0:
|
||||
if (patch < 32) {
|
||||
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
|
||||
have_readonly_adjtime = 1;
|
||||
} else if (patch >= 32) {
|
||||
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
|
||||
|
||||
/* The functionality in kernel/time.c in the kernel source
|
||||
was modified with regard to what comes back in the
|
||||
txc.offset field on return from adjtimex. If txc.modes
|
||||
was ADJ_OFFSET_SINGLESHOT on entry, the outstanding
|
||||
adjustment is returned, however the running offset will
|
||||
be modified to the passed value. */
|
||||
have_readonly_adjtime = 0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* I know that earlier 2.1 kernels were like 2.0.31, hence
|
||||
the settings below. However, the 2.0.32 behaviour may
|
||||
have been added late in the 2.1 series, however I have no
|
||||
idea at which patch level. Leave it like this until
|
||||
someone supplies some info. */
|
||||
freq_scale = (hz==100) ? (128.0 / 125.0) : basic_freq_scale;
|
||||
have_readonly_adjtime = 0; /* For safety ! */
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
/* These seem to be like 2.0.32 */
|
||||
freq_scale = (hz==100) ? (128.0 / 128.125) : basic_freq_scale;
|
||||
have_readonly_adjtime = 0;
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported yet, sorry.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL(LOGF_SysLinux, "Kernel's major version not supported yet, sorry");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Override freq_scale if it appears in conf file */
|
||||
CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
|
||||
calculated_freq_scale = freq_scale;
|
||||
if (set_config_freq_scale) freq_scale = config_freq_scale;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "calculated_freq_scale=%.8f freq_scale=%.8f",
|
||||
calculated_freq_scale, freq_scale);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Set denorms to flush to zero instead of trapping. */
|
||||
|
||||
#if defined(__SH5__)
|
||||
static void enable_flush_denorms(void)
|
||||
{
|
||||
float fpscr;
|
||||
unsigned long ifpscr;
|
||||
asm volatile("fgetscr %0" : "=f" (fpscr));
|
||||
asm volatile("fmov.sl %1, %0" : "=r" (ifpscr) : "f" (fpscr));
|
||||
ifpscr |= 0x40000;
|
||||
asm volatile("fmov.ls %1, %0" : "=f" (fpscr) : "r" (ifpscr));
|
||||
asm volatile("fputscr %0" : : "f" (fpscr));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation code for this module */
|
||||
|
||||
void
|
||||
SYS_Linux_Initialise(void)
|
||||
{
|
||||
offset_register = 0.0;
|
||||
fast_slewing = 0;
|
||||
|
||||
#if defined(__SH5__)
|
||||
enable_flush_denorms();
|
||||
#endif
|
||||
|
||||
get_version_specific_details();
|
||||
|
||||
current_tick = nominal_tick;
|
||||
current_total_tick = 1.0 / dhz;
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction, immediate_step);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Finalisation code for this module */
|
||||
|
||||
void
|
||||
SYS_Linux_Finalise(void)
|
||||
{
|
||||
/* Must *NOT* leave a fast slew running - clock would drift way off
|
||||
if the daemon is not restarted */
|
||||
abort_slew();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel)
|
||||
{
|
||||
*major = version_major;
|
||||
*minor = version_minor;
|
||||
*patchlevel = version_patchlevel;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#endif /* LINUX */
|
||||
|
||||
/* vim:ts=8
|
||||
* */
|
||||
|
||||
40
sys_linux.h
Normal file
40
sys_linux.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys_linux.h,v 1.8 2002/02/28 23:27:15 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
The header file for the linux driver
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_LINUX_H
|
||||
#define GOT_SYS_LINUX_H
|
||||
|
||||
extern void SYS_Linux_Initialise(void);
|
||||
|
||||
extern void SYS_Linux_Finalise(void);
|
||||
|
||||
extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
|
||||
|
||||
#endif /* GOT_SYS_LINUX_H */
|
||||
326
sys_netbsd.c
Normal file
326
sys_netbsd.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys_netbsd.c,v 1.2 2002/02/17 22:13:49 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Driver file for the NetBSD operating system.
|
||||
*/
|
||||
|
||||
#ifdef __NetBSD__
|
||||
|
||||
#include <kvm.h>
|
||||
#include <nlist.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sys_netbsd.h"
|
||||
#include "localp.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
clock was estimated to be fast of reference time at the epoch when
|
||||
gettimeofday() returned T0 */
|
||||
|
||||
static double offset_register;
|
||||
|
||||
/* This register contains the epoch to which the offset is referenced */
|
||||
|
||||
static struct timeval T0;
|
||||
|
||||
/* This register contains the current estimate of the system
|
||||
frequency, in absolute (NOT ppm) */
|
||||
|
||||
static double current_freq;
|
||||
|
||||
/* This register contains the number of seconds of adjustment that
|
||||
were passed to adjtime last time it was called. */
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* Kernel parameters to calculate adjtime error. */
|
||||
|
||||
static int kern_tickadj;
|
||||
static long kern_bigadj;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_initialise(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timezone tz;
|
||||
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
|
||||
if (gettimeofday(&T0, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in clock_initialise()");
|
||||
}
|
||||
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
CROAK("adjtime() failed in clock_initialise");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_finalise(void)
|
||||
{
|
||||
/* Nothing to do yet */
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
struct timezone tz;
|
||||
double elapsed, accrued_error;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
long delta, tickdelta;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
|
||||
/* Determine the amount of error built up since the last adjustment */
|
||||
if (gettimeofday(&T1, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in start_adjust");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
|
||||
/* At this point, we need to round the required adjustment the
|
||||
same way the kernel does. */
|
||||
|
||||
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
|
||||
if (delta > kern_bigadj || delta < -kern_bigadj)
|
||||
tickdelta = 10 * kern_tickadj;
|
||||
else
|
||||
tickdelta = kern_tickadj;
|
||||
if (delta % tickdelta)
|
||||
delta = delta / tickdelta * tickdelta;
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = delta;
|
||||
UTI_NormaliseTimeval(&newadj);
|
||||
|
||||
/* Add rounding error back onto offset register. */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
CROAK("adjtime() failed in start_adjust");
|
||||
}
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_adjust(void)
|
||||
{
|
||||
struct timeval T1;
|
||||
struct timezone tz;
|
||||
struct timeval zeroadj, remadj;
|
||||
double adjustment_remaining, adjustment_achieved;
|
||||
double elapsed, elapsed_plus_adjust;
|
||||
|
||||
zeroadj.tv_sec = 0;
|
||||
zeroadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&zeroadj, &remadj) < 0) {
|
||||
CROAK("adjtime() failed in stop_adjust");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, &tz) < 0) {
|
||||
CROAK("gettimeofday() failed in stop_adjust");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
adjustment_achieved = adjustment_requested - adjustment_remaining;
|
||||
elapsed_plus_adjust = elapsed - adjustment_achieved;
|
||||
|
||||
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
slew backwards */
|
||||
|
||||
static void
|
||||
accrue_offset(double offset)
|
||||
{
|
||||
stop_adjust();
|
||||
offset_register += offset;
|
||||
start_adjust();
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static void
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
struct timezone tz;
|
||||
|
||||
stop_adjust();
|
||||
|
||||
if (gettimeofday(&old_time, &tz) < 0) {
|
||||
CROAK("gettimeofday in apply_step_offset");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, &tz) < 0) {
|
||||
CROAK("settimeofday in apply_step_offset");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
T0 = T1;
|
||||
|
||||
start_adjust();
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_frequency(double new_freq_ppm)
|
||||
{
|
||||
stop_adjust();
|
||||
current_freq = new_freq_ppm * 1.0e-6;
|
||||
start_adjust();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr)
|
||||
{
|
||||
stop_adjust();
|
||||
*corr = -offset_register;
|
||||
start_adjust();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_NetBSD_Initialise(void)
|
||||
{
|
||||
static struct nlist nl[] = {
|
||||
{"_tickadj"},
|
||||
{"_bigadj"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
kvm_t *kt;
|
||||
FILE *fp;
|
||||
|
||||
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL);
|
||||
if (!kt) {
|
||||
CROAK("Cannot open kvm\n");
|
||||
}
|
||||
|
||||
if (kvm_nlist(kt, nl) < 0) {
|
||||
CROAK("Cannot read kernel symbols\n");
|
||||
}
|
||||
|
||||
if (kvm_read(kt, nl[0].n_value, (char *)(&kern_tickadj), sizeof(int)) < 0) {
|
||||
CROAK("Cannot read from _tickadj\n");
|
||||
}
|
||||
|
||||
if (kvm_read(kt, nl[1].n_value, (char *)(&kern_bigadj), sizeof(long)) < 0) {
|
||||
CROAK("Cannot read from _bigadj\n");
|
||||
}
|
||||
|
||||
kvm_close(kt);
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction, NULL /* immediate_step */);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_NetBSD_Finalise(void)
|
||||
{
|
||||
clock_finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
#endif /* __NetBSD__ */
|
||||
39
sys_netbsd.h
Normal file
39
sys_netbsd.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
$Header: /cvs/src/chrony/sys_netbsd.h,v 1.2 2002/02/17 22:13:49 richard Exp $
|
||||
|
||||
=======================================================================
|
||||
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for NetBSD driver
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_NETBSD_H
|
||||
#define GOT_SYS_NETBSD_H
|
||||
|
||||
void SYS_NetBSD_Initialise(void);
|
||||
|
||||
void SYS_NetBSD_Finalise(void);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user