1224ba2bdSOllivier Robert#!/usr/bin/perl -w 2224ba2bdSOllivier Robert# --*-perl-*- 3c0b746e5SOllivier Robert;# 4c0b746e5SOllivier Robert;# ntploopstat,v 3.1 1993/07/06 01:09:11 jbj Exp 5c0b746e5SOllivier Robert;# 6c0b746e5SOllivier Robert;# Poll NTP server using NTP mode 7 loopinfo request. 7c0b746e5SOllivier Robert;# Log info and timestamp to file for processing by ntploopwatch. 8c0b746e5SOllivier Robert;# 9c0b746e5SOllivier Robert;# 10c0b746e5SOllivier Robert;# Copyright (c) 1992 11c0b746e5SOllivier Robert;# Rainer Pruy Friedrich-Alexander Universitaet Erlangen-Nuernberg 12c0b746e5SOllivier Robert;# 13c0b746e5SOllivier Robert;################################################################# 14c0b746e5SOllivier Robert;# 15c0b746e5SOllivier Robert;# The format written to the logfile is the same as used by xntpd 16c0b746e5SOllivier Robert;# for the loopstats file. 17c0b746e5SOllivier Robert;# This script however allows to gather loop filter statistics from 18c0b746e5SOllivier Robert;# remote servers where you do not have access to the loopstats logfile. 19c0b746e5SOllivier Robert;# 20c0b746e5SOllivier Robert;# Please note: Communication delays affect the accuracy of the 21c0b746e5SOllivier Robert;# timestamps recorded. Effects from these delays will probably 22c0b746e5SOllivier Robert;# not show up, as timestamps are recorded to the second only. 23c0b746e5SOllivier Robert;# (Should have implemented &gettimeofday()..) 24c0b746e5SOllivier Robert;# 25c0b746e5SOllivier Robert 26224ba2bdSOllivier Robert$0 =~ s!^.*/([^/]+)$!$1!; # beautify script name 27c0b746e5SOllivier Robert 28c0b746e5SOllivier Robert$ntpserver = 'localhost'; # default host to poll 29c0b746e5SOllivier Robert$delay = 60; # default sampling rate 30c0b746e5SOllivier Robert ;# keep it shorter than minpoll (=64) 31c0b746e5SOllivier Robert ;# to get all values 32c0b746e5SOllivier Robert 33c0b746e5SOllivier Robertrequire "ctime.pl"; 34c0b746e5SOllivier Robert;# handle bug in early ctime distributions 35c0b746e5SOllivier Robert$ENV{'TZ'} = 'MET' unless defined($ENV{'TZ'}) || $] > 4.010; 36c0b746e5SOllivier Robert 37c0b746e5SOllivier Robertif (defined(@ctime'MoY)) 38c0b746e5SOllivier Robert{ 39c0b746e5SOllivier Robert *MonthName = *ctime'MoY; 40c0b746e5SOllivier Robert} 41c0b746e5SOllivier Robertelse 42c0b746e5SOllivier Robert{ 43c0b746e5SOllivier Robert @MonthName = ('Jan','Feb','Mar','Apr','May','Jun', 44c0b746e5SOllivier Robert 'Jul','Aug','Sep','Oct','Nov','Dec'); 45c0b746e5SOllivier Robert} 46c0b746e5SOllivier Robert 47c0b746e5SOllivier Robert;# this routine can be redefined to point to syslog if necessary 48c0b746e5SOllivier Robertsub msg 49c0b746e5SOllivier Robert{ 50c0b746e5SOllivier Robert return unless $verbose; 51c0b746e5SOllivier Robert 52c0b746e5SOllivier Robert print STDERR "$0: "; 53c0b746e5SOllivier Robert printf STDERR @_; 54c0b746e5SOllivier Robert} 55c0b746e5SOllivier Robert 56c0b746e5SOllivier Robert;############################################################# 57c0b746e5SOllivier Robert;# 58c0b746e5SOllivier Robert;# process command line 59c0b746e5SOllivier Robert$usage = <<"E-O-S"; 60c0b746e5SOllivier Robert 61c0b746e5SOllivier Robertusage: 62c0b746e5SOllivier Robert $0 [-d<delay>] [-t<timeout>] [-l <logfile>] [-v] [ntpserver] 63c0b746e5SOllivier RobertE-O-S 64c0b746e5SOllivier Robert 65c0b746e5SOllivier Robertwhile($_ = shift) 66c0b746e5SOllivier Robert{ 67c0b746e5SOllivier Robert /^-v(\d*)$/ && ($verbose=($1 eq '') ? 1 : $1,1) && next; 68c0b746e5SOllivier Robert /^-d(\d*)$/ && 69c0b746e5SOllivier Robert do { 70c0b746e5SOllivier Robert ($1 ne '') && ($delay = $1,1) && next; 71c0b746e5SOllivier Robert @ARGV || die("$0: delay value missing after -d\n$usage"); 72c0b746e5SOllivier Robert $delay = shift; 73c0b746e5SOllivier Robert ($delay >= 0) || die("$0: bad delay value \"$delay\"\n$usage"); 74c0b746e5SOllivier Robert next; 75c0b746e5SOllivier Robert }; 76c0b746e5SOllivier Robert /^-l$/ && 77c0b746e5SOllivier Robert do { 78c0b746e5SOllivier Robert @ARGV || die("$0: logfile missing after -l\n$usage"); 79c0b746e5SOllivier Robert $logfile = shift; 80c0b746e5SOllivier Robert next; 81c0b746e5SOllivier Robert }; 82c0b746e5SOllivier Robert /^-t(\d*(\.\d*)?)$/ && 83c0b746e5SOllivier Robert do { 84c0b746e5SOllivier Robert ($1 ne '') && ($timeout = $1,1) && next; 85c0b746e5SOllivier Robert @ARGV || die("$0: timeout value missing after -t\n$usage\n"); 86c0b746e5SOllivier Robert $timeout = shift; 87c0b746e5SOllivier Robert ($timeout > 0) || 88c0b746e5SOllivier Robert die("$0: bad timeout value \"$timeout\"\n$usage"); 89c0b746e5SOllivier Robert next; 90c0b746e5SOllivier Robert }; 91c0b746e5SOllivier Robert 92c0b746e5SOllivier Robert /^-/ && die("$0: unknown option \"$_\"\n$usage"); 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert ;# any other argument is server to poll 95c0b746e5SOllivier Robert $ntpserver = $_; 96c0b746e5SOllivier Robert last; 97c0b746e5SOllivier Robert} 98c0b746e5SOllivier Robert 99c0b746e5SOllivier Robertif (@ARGV) 100c0b746e5SOllivier Robert{ 101c0b746e5SOllivier Robert warn("unexpected arguments: ".join(" ",@ARGV).".\n"); 102c0b746e5SOllivier Robert die("$0: too many servers specified\n$usage"); 103c0b746e5SOllivier Robert} 104c0b746e5SOllivier Robert 105c0b746e5SOllivier Robert;# logfile defaults to include server name 106c0b746e5SOllivier Robert;# The name of the current month is appended and 107c0b746e5SOllivier Robert;# the file is opened and closed for each sample. 108c0b746e5SOllivier Robert;# 109c0b746e5SOllivier Robert$logfile = "loopstats:$ntpserver." unless defined($logfile); 110c0b746e5SOllivier Robert$timeout = 12.0 unless defined($timeout); # wait $timeout seconds for reply 111c0b746e5SOllivier Robert 112c0b746e5SOllivier Robert$MAX_FAIL = 60; # give up after $MAX_FAIL failed polls 113c0b746e5SOllivier Robert 114c0b746e5SOllivier Robert 115c0b746e5SOllivier Robert$MJD_1970 = 40587; 116c0b746e5SOllivier Robert 117c0b746e5SOllivier Robertif (eval 'require "syscall.ph";') 118c0b746e5SOllivier Robert{ 119c0b746e5SOllivier Robert if (defined(&SYS_gettimeofday)) 120c0b746e5SOllivier Robert { 121c0b746e5SOllivier Robert ;# assume standard 122c0b746e5SOllivier Robert ;# gettimeofday(struct timeval *tp,struct timezone *tzp) 123c0b746e5SOllivier Robert ;# syntax for gettimeofday syscall 124c0b746e5SOllivier Robert ;# tzp = NULL -> undef 125c0b746e5SOllivier Robert ;# tp = (long,long) 126c0b746e5SOllivier Robert eval 'sub time { local($tz) = pack("LL",0,0); 127c0b746e5SOllivier Robert (&msg("gettimeofday failed: $!\n"), 128c0b746e5SOllivier Robert return (time)) 129c0b746e5SOllivier Robert unless syscall(&SYS_gettimeofday,$tz,undef) == 0; 130c0b746e5SOllivier Robert local($s,$us) = unpack("LL",$tz); 131c0b746e5SOllivier Robert return $s + $us/1000000; }'; 132c0b746e5SOllivier Robert local($t1,$t2,$t3); 133c0b746e5SOllivier Robert $t1 = time; 134c0b746e5SOllivier Robert eval '$t2 = &time;'; 135c0b746e5SOllivier Robert $t3 = time; 136c0b746e5SOllivier Robert die("$0: gettimeofday failed: $@.\n") if defined($@) && $@; 137c0b746e5SOllivier Robert die("$0: gettimeofday inconsistency time=$t1,gettimeofday=$t2,time=$t2\n") 138c0b746e5SOllivier Robert if (int($t1) != int($t2) && int($t3) != int($t2)); 139c0b746e5SOllivier Robert &msg("Using gettimeofday for timestamps\n"); 140c0b746e5SOllivier Robert } 141c0b746e5SOllivier Robert else 142c0b746e5SOllivier Robert { 143c0b746e5SOllivier Robert warn("No gettimeofday syscall found - using time builtin for timestamps\n"); 144c0b746e5SOllivier Robert eval 'sub time { return time; }'; 145c0b746e5SOllivier Robert } 146c0b746e5SOllivier Robert} 147c0b746e5SOllivier Robertelse 148c0b746e5SOllivier Robert{ 149c0b746e5SOllivier Robert warn("No syscall.ph file found - using time builtin for timestamps\n"); 150c0b746e5SOllivier Robert eval 'sub time { return time; }'; 151c0b746e5SOllivier Robert} 152c0b746e5SOllivier Robert 153c0b746e5SOllivier Robert 154c0b746e5SOllivier Robert;#------------------+ 155c0b746e5SOllivier Robert;# from ntp_request.h 156c0b746e5SOllivier Robert;#------------------+ 157c0b746e5SOllivier Robert 158c0b746e5SOllivier Robert;# NTP mode 7 packet format: 159c0b746e5SOllivier Robert;# Byte 1: ResponseBit MoreBit Version(3bit) Mode(3bit)==7 160c0b746e5SOllivier Robert;# Byte 2: AuthBit Sequence # - 0 - 127 see MoreBit 161c0b746e5SOllivier Robert;# Byte 3: Implementation # 162c0b746e5SOllivier Robert;# Byte 4: Request Code 163c0b746e5SOllivier Robert;# 164c0b746e5SOllivier Robert;# Short 1: Err(3bit) NumItems(12bit) 165c0b746e5SOllivier Robert;# Short 2: MBZ(3bit)=0 DataItemSize(12bit) 166c0b746e5SOllivier Robert;# 0 - 500 byte Data 167c0b746e5SOllivier Robert;# if AuthBit is set: 168c0b746e5SOllivier Robert;# Long: KeyId 169c0b746e5SOllivier Robert;# 2xLong: AuthCode 170c0b746e5SOllivier Robert 171c0b746e5SOllivier Robert;# 172c0b746e5SOllivier Robert$IMPL_XNTPD = 2; 173c0b746e5SOllivier Robert$REQ_LOOP_INFO = 8; 174c0b746e5SOllivier Robert 175c0b746e5SOllivier Robert 176c0b746e5SOllivier Robert;# request packet for REQ_LOOP_INFO: 177c0b746e5SOllivier Robert;# B1: RB=0 MB=0 V=2 M=7 178c0b746e5SOllivier Robert;# B2: S# = 0 179c0b746e5SOllivier Robert;# B3: I# = IMPL_XNTPD 180c0b746e5SOllivier Robert;# B4: RC = REQ_LOOP_INFO 181c0b746e5SOllivier Robert;# S1: E=0 NI=0 182c0b746e5SOllivier Robert;# S2: MBZ=0 DIS=0 183c0b746e5SOllivier Robert;# data: 32 byte 0 padding 184c0b746e5SOllivier Robert;# 8byte timestamp if encryption, 0 padding otherwise 185c0b746e5SOllivier Robert$loopinfo_reqpkt = 186c0b746e5SOllivier Robert pack("CCCC nn x32 x8", 0x17, 0, $IMPL_XNTPD, $REQ_LOOP_INFO, 0, 0); 187c0b746e5SOllivier Robert 188c0b746e5SOllivier Robert;# ignore any auth data in packets 189c0b746e5SOllivier Robert$loopinfo_response_size = 190c0b746e5SOllivier Robert 1+1+1+1+2+2 # header size like request pkt 191c0b746e5SOllivier Robert + 8 # l_fp last_offset 192c0b746e5SOllivier Robert + 8 # l_fp drift_comp 193c0b746e5SOllivier Robert + 4 # u_long compliance 194c0b746e5SOllivier Robert + 4 # u_long watchdog_timer 195c0b746e5SOllivier Robert ; 196c0b746e5SOllivier Robert$loopinfo_response_fmt = "C4n2N2N2NN"; 197c0b746e5SOllivier Robert$loopinfo_response_fmt_v2 = "C4n2N2N2N2N"; 198c0b746e5SOllivier Robert 199c0b746e5SOllivier Robert;# 200c0b746e5SOllivier Robert;# prepare connection to server 201c0b746e5SOllivier Robert;# 202c0b746e5SOllivier Robert 203c0b746e5SOllivier Robert;# workaround for broken socket.ph on dynix_ptx 204c0b746e5SOllivier Roberteval 'sub INTEL {1;}' unless defined(&INTEL); 205c0b746e5SOllivier Roberteval 'sub ATT {1;}' unless defined(&ATT); 206c0b746e5SOllivier Robert 207c0b746e5SOllivier Robertrequire "sys/socket.ph"; 208c0b746e5SOllivier Robert 209c0b746e5SOllivier Robertrequire 'netinet/in.ph'; 210c0b746e5SOllivier Robert 211c0b746e5SOllivier Robert;# if you do not have netinet/in.ph enable the following lines 212c0b746e5SOllivier Robert;#eval 'sub INADDR_ANY { 0x00000000; }' unless defined(&INADDR_ANY); 213c0b746e5SOllivier Robert;#eval 'sub IPPRORO_UDP { 17; }' unless defined(&IPPROTO_UDP); 214c0b746e5SOllivier Robert 215c0b746e5SOllivier Robertif ($ntpserver =~ /^((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)\.((0x?)?\w+)$/) 216c0b746e5SOllivier Robert{ 217c0b746e5SOllivier Robert local($a,$b,$c,$d) = ($1,$3,$5,$7); 218c0b746e5SOllivier Robert $a = oct($a) if defined($2); 219c0b746e5SOllivier Robert $b = oct($b) if defined($4); 220c0b746e5SOllivier Robert $c = oct($c) if defined($6); 221c0b746e5SOllivier Robert $d = oct($d) if defined($8); 222c0b746e5SOllivier Robert $server_addr = pack("C4", $a,$b,$c,$d); 223c0b746e5SOllivier Robert 224c0b746e5SOllivier Robert $server_mainname 225c0b746e5SOllivier Robert = (gethostbyaddr($server_addr,&AF_INET))[$[] || $ntpserver; 226c0b746e5SOllivier Robert} 227c0b746e5SOllivier Robertelse 228c0b746e5SOllivier Robert{ 229c0b746e5SOllivier Robert ($server_mainname,$server_addr) 230c0b746e5SOllivier Robert = (gethostbyname($ntpserver))[$[,$[+4]; 231c0b746e5SOllivier Robert 232c0b746e5SOllivier Robert die("$0: host \"$ntpserver\" is unknown\n") 233c0b746e5SOllivier Robert unless defined($server_addr); 234c0b746e5SOllivier Robert} 235c0b746e5SOllivier Robert&msg ("Address of server \"$ntpserver\" is \"%d.%d.%d.%d\"\n", 236c0b746e5SOllivier Robert unpack("C4",$server_addr)); 237c0b746e5SOllivier Robert 238c0b746e5SOllivier Robert$proto_udp = (getprotobyname('udp'))[$[+2] || &IPPROTO_UDP; 239c0b746e5SOllivier Robert 240c0b746e5SOllivier Robert$ntp_port = 241c0b746e5SOllivier Robert (getservbyname('ntp','udp'))[$[+2] || 242c0b746e5SOllivier Robert (warn "Could not get port number for service \"ntp/udp\" using 123\n"), 243c0b746e5SOllivier Robert ($ntp_port=123); 244c0b746e5SOllivier Robert 245c0b746e5SOllivier Robert;# 246c0b746e5SOllivier Robert0 && &SOCK_DGRAM; # satisfy perl -w ... 247c0b746e5SOllivier Robertsocket(S, &AF_INET, &SOCK_DGRAM, $proto_udp) || 248c0b746e5SOllivier Robert die("Cannot open socket: $!\n"); 249c0b746e5SOllivier Robert 250c0b746e5SOllivier Robertbind(S, pack("S n N x8", &AF_INET, 0, &INADDR_ANY)) || 251c0b746e5SOllivier Robert die("Cannot bind: $!\n"); 252c0b746e5SOllivier Robert 253c0b746e5SOllivier Robert($my_port, $my_addr) = (unpack("S n a4 x8",getsockname(S)))[$[+1,$[+2]; 254c0b746e5SOllivier Robert 255c0b746e5SOllivier Robert&msg("Listening at address %d.%d.%d.%d port %d\n", 256c0b746e5SOllivier Robert unpack("C4",$my_addr), $my_port); 257c0b746e5SOllivier Robert 258c0b746e5SOllivier Robert$server_inaddr = pack("Sna4x8", &AF_INET, $ntp_port, $server_addr); 259c0b746e5SOllivier Robert 260c0b746e5SOllivier Robert;############################################################ 261c0b746e5SOllivier Robert;# 262c0b746e5SOllivier Robert;# the main loop: 263c0b746e5SOllivier Robert;# send request 264c0b746e5SOllivier Robert;# get reply 265c0b746e5SOllivier Robert;# wait til next sample time 266c0b746e5SOllivier Robert 267c0b746e5SOllivier Robertundef($lasttime); 268c0b746e5SOllivier Robert$lostpacket = 0; 269c0b746e5SOllivier Robert 270c0b746e5SOllivier Robertwhile(1) 271c0b746e5SOllivier Robert{ 272c0b746e5SOllivier Robert $stime = &time; 273c0b746e5SOllivier Robert 274c0b746e5SOllivier Robert &msg("Sending request $stime...\n"); 275c0b746e5SOllivier Robert 276c0b746e5SOllivier Robert $ret = send(S,$loopinfo_reqpkt,0,$server_inaddr); 277c0b746e5SOllivier Robert 278c0b746e5SOllivier Robert if (! defined($ret) || $ret < length($loopinfo_reqpkt)) 279c0b746e5SOllivier Robert { 280c0b746e5SOllivier Robert warn("$0: send failed ret=($ret): $!\n"); 281c0b746e5SOllivier Robert $fail++; 282c0b746e5SOllivier Robert next; 283c0b746e5SOllivier Robert } 284c0b746e5SOllivier Robert 285c0b746e5SOllivier Robert &msg("Waiting for reply...\n"); 286c0b746e5SOllivier Robert 287c0b746e5SOllivier Robert $mask = ""; vec($mask,fileno(S),1) = 1; 288c0b746e5SOllivier Robert $ret = select($mask,undef,undef,$timeout); 289c0b746e5SOllivier Robert 290c0b746e5SOllivier Robert if (! defined($ret)) 291c0b746e5SOllivier Robert { 292c0b746e5SOllivier Robert warn("$0: select failed: $!\n"); 293c0b746e5SOllivier Robert $fail++; 294c0b746e5SOllivier Robert next; 295c0b746e5SOllivier Robert } 296c0b746e5SOllivier Robert elsif ($ret == 0) 297c0b746e5SOllivier Robert { 298c0b746e5SOllivier Robert warn("$0: request to $ntpserver timed out ($timeout seconds)\n"); 299c0b746e5SOllivier Robert ;# do not count this event as failure 300c0b746e5SOllivier Robert ;# it usually this happens due to dropped udp packets on noisy and 301c0b746e5SOllivier Robert ;# havily loaded lines, so just try again; 302c0b746e5SOllivier Robert $lostpacket = 1; 303c0b746e5SOllivier Robert next; 304c0b746e5SOllivier Robert } 305c0b746e5SOllivier Robert 306c0b746e5SOllivier Robert &msg("Receiving reply...\n"); 307c0b746e5SOllivier Robert 308c0b746e5SOllivier Robert $len = 520; # max size of a mode 7 packet 309c0b746e5SOllivier Robert $reply = ""; # just make it defined for -w 310c0b746e5SOllivier Robert $ret = recv(S,$reply,$len,0); 311c0b746e5SOllivier Robert 312c0b746e5SOllivier Robert if (!defined($ret)) 313c0b746e5SOllivier Robert { 314c0b746e5SOllivier Robert warn("$0: recv failed: $!\n"); 315c0b746e5SOllivier Robert $fail++; 316c0b746e5SOllivier Robert next; 317c0b746e5SOllivier Robert } 318c0b746e5SOllivier Robert 319c0b746e5SOllivier Robert $etime = &time; 320c0b746e5SOllivier Robert &msg("Received at\t$etime\n"); 321c0b746e5SOllivier Robert 322c0b746e5SOllivier Robert ;#$time = ($stime + $etime) / 2; # symmetric delay assumed 323c0b746e5SOllivier Robert $time = $etime; # the above assumption breaks for X25 324c0b746e5SOllivier Robert ;# so taking etime makes timestamps be a 325c0b746e5SOllivier Robert ;# little late, but keeps them increasing 326c0b746e5SOllivier Robert ;# monotonously 327c0b746e5SOllivier Robert 328c0b746e5SOllivier Robert &msg(sprintf("Reply from %d.%d.%d.%d took %f seconds\n", 329c0b746e5SOllivier Robert (unpack("SnC4",$ret))[$[+2 .. $[+5], ($etime - $stime))); 330c0b746e5SOllivier Robert 331c0b746e5SOllivier Robert if ($len < $loopinfo_response_size) 332c0b746e5SOllivier Robert { 333c0b746e5SOllivier Robert warn("$0: short packet ($len bytes) received ($loopinfo_response_size bytes expected\n"); 334c0b746e5SOllivier Robert $fail++; 335c0b746e5SOllivier Robert next; 336c0b746e5SOllivier Robert } 337c0b746e5SOllivier Robert 338c0b746e5SOllivier Robert ($b1,$b2,$b3,$b4,$s1,$s2, 339c0b746e5SOllivier Robert $offset_i,$offset_f,$drift_i,$drift_f,$compl,$watchdog) 340c0b746e5SOllivier Robert = unpack($loopinfo_response_fmt,$reply); 341c0b746e5SOllivier Robert 342c0b746e5SOllivier Robert ;# check reply 343c0b746e5SOllivier Robert if (($s1 >> 12) != 0) # error ! 344c0b746e5SOllivier Robert { 345c0b746e5SOllivier Robert die("$0: got error reply ".($s1>>12)."\n"); 346c0b746e5SOllivier Robert } 347c0b746e5SOllivier Robert if (($b1 != 0x97 && $b1 != 0x9f) || # Reply NotMore V=2 M=7 348c0b746e5SOllivier Robert ($b2 != 0 && $b2 != 0x80) || # S=0 Auth no/yes 349c0b746e5SOllivier Robert $b3 != $IMPL_XNTPD || # ! IMPL_XNTPD 350c0b746e5SOllivier Robert $b4 != $REQ_LOOP_INFO || # Ehh.. not loopinfo reply ? 351c0b746e5SOllivier Robert $s1 != 1 || # ???? 352c0b746e5SOllivier Robert ($s2 != 24 && $s2 != 28) # 353c0b746e5SOllivier Robert ) 354c0b746e5SOllivier Robert { 355c0b746e5SOllivier Robert warn("$0: Bad/unexpected reply from server:\n"); 356c0b746e5SOllivier Robert warn(" \"".unpack("H*",$reply)."\"\n"); 357c0b746e5SOllivier Robert warn(" ".sprintf("b1=%x b2=%x b3=%x b4=%x s1=%d s2=%d\n", 358c0b746e5SOllivier Robert $b1,$b2,$b3,$b4,$s1,$s2)); 359c0b746e5SOllivier Robert $fail++; 360c0b746e5SOllivier Robert next; 361c0b746e5SOllivier Robert } 362c0b746e5SOllivier Robert elsif ($s2 == 28) 363c0b746e5SOllivier Robert { 364c0b746e5SOllivier Robert ;# seems to be a version 2 xntpd 365c0b746e5SOllivier Robert ($b1,$b2,$b3,$b4,$s1,$s2, 366c0b746e5SOllivier Robert $offset_i,$offset_f,$drift_i,$drift_f,$compl_i,$compl_f,$watchdog) 367c0b746e5SOllivier Robert = unpack($loopinfo_response_fmt_v2,$reply); 368c0b746e5SOllivier Robert $compl = &lfptoa($compl_i, $compl_f); 369c0b746e5SOllivier Robert } 370c0b746e5SOllivier Robert 371c0b746e5SOllivier Robert $time -= $watchdog; 372c0b746e5SOllivier Robert 373c0b746e5SOllivier Robert $offset = &lfptoa($offset_i, $offset_f); 374c0b746e5SOllivier Robert $drift = &lfptoa($drift_i, $drift_f); 375c0b746e5SOllivier Robert 376c0b746e5SOllivier Robert &log($time,$offset,$drift,$compl) && ($fail = 0);; 377c0b746e5SOllivier Robert} 378c0b746e5SOllivier Robertcontinue 379c0b746e5SOllivier Robert{ 380c0b746e5SOllivier Robert die("$0: Too many failures - terminating\n") if $fail > $MAX_FAIL; 381c0b746e5SOllivier Robert &msg("Sleeping " . ($lostpacket ? ($delay / 2) : $delay) . " seconds...\n"); 382c0b746e5SOllivier Robert 383c0b746e5SOllivier Robert sleep($lostpacket ? ($delay / 2) : $delay); 384c0b746e5SOllivier Robert $lostpacket = 0; 385c0b746e5SOllivier Robert} 386c0b746e5SOllivier Robert 387c0b746e5SOllivier Robertsub log 388c0b746e5SOllivier Robert{ 389c0b746e5SOllivier Robert local($time,$offs,$freq,$cmpl) = @_; 390c0b746e5SOllivier Robert local($y,$m,$d); 391c0b746e5SOllivier Robert local($fname,$suff) = ($logfile); 392c0b746e5SOllivier Robert 393c0b746e5SOllivier Robert 394c0b746e5SOllivier Robert ;# silently drop sample if distance to last sample is too low 395c0b746e5SOllivier Robert if (defined($lasttime) && ($lasttime + 2) >= $time) 396c0b746e5SOllivier Robert { 397c0b746e5SOllivier Robert &msg("Dropped packet - old sample\n"); 398c0b746e5SOllivier Robert return 1; 399c0b746e5SOllivier Robert } 400c0b746e5SOllivier Robert 401c0b746e5SOllivier Robert ;# $suff determines which samples end up in the same file 402c0b746e5SOllivier Robert ;# could have used $year (;-) or WeekOfYear, DayOfYear,.... 403c0b746e5SOllivier Robert ;# Change it to your suit... 404c0b746e5SOllivier Robert 405c0b746e5SOllivier Robert ($d,$m,$y) = (localtime($time))[$[+3 .. $[+5]; 406c0b746e5SOllivier Robert $suff = sprintf("%04d%02d%02d",$y+1900,$m+1,$d); 407c0b746e5SOllivier Robert $fname .= $suff; 408c0b746e5SOllivier Robert if (!open(LOG,">>$fname")) 409c0b746e5SOllivier Robert { 410c0b746e5SOllivier Robert warn("$0: open($fname) failed: $!\n"); 411c0b746e5SOllivier Robert $fail++; 412c0b746e5SOllivier Robert return 0; 413c0b746e5SOllivier Robert } 414c0b746e5SOllivier Robert else 415c0b746e5SOllivier Robert { 416c0b746e5SOllivier Robert ;# file format 417c0b746e5SOllivier Robert ;# MJD seconds offset drift compliance 418c0b746e5SOllivier Robert printf LOG ("%d %.3lf %.8lf %.7lf %d\n", 419c0b746e5SOllivier Robert int($time/86400)+$MJD_1970, 420c0b746e5SOllivier Robert $time - int($time/86400) * 86400, 421c0b746e5SOllivier Robert $offs,$freq,$cmpl); 422c0b746e5SOllivier Robert close(LOG); 423c0b746e5SOllivier Robert $lasttime = $time; 424c0b746e5SOllivier Robert } 425c0b746e5SOllivier Robert return 1; 426c0b746e5SOllivier Robert} 427c0b746e5SOllivier Robert 428c0b746e5SOllivier Robert;# see ntp_fp.h to understand this 429c0b746e5SOllivier Robertsub lfptoa 430c0b746e5SOllivier Robert{ 431c0b746e5SOllivier Robert local($i,$f) = @_; 432c0b746e5SOllivier Robert local($sign) = 1; 433c0b746e5SOllivier Robert 434c0b746e5SOllivier Robert 435c0b746e5SOllivier Robert if ($i & 0x80000000) 436c0b746e5SOllivier Robert { 437c0b746e5SOllivier Robert if ($f == 0) 438c0b746e5SOllivier Robert { 439c0b746e5SOllivier Robert $i = -$i; 440c0b746e5SOllivier Robert } 441c0b746e5SOllivier Robert else 442c0b746e5SOllivier Robert { 443c0b746e5SOllivier Robert $f = -$f; 444c0b746e5SOllivier Robert $i = ~$i; 445c0b746e5SOllivier Robert $i += 1; # 2s complement 446c0b746e5SOllivier Robert } 447c0b746e5SOllivier Robert $sign = -1; 448c0b746e5SOllivier Robert ;#print "NEG: $i $f\n"; 449c0b746e5SOllivier Robert } 450c0b746e5SOllivier Robert else 451c0b746e5SOllivier Robert { 452c0b746e5SOllivier Robert ;#print "POS: $i $f\n"; 453c0b746e5SOllivier Robert } 454c0b746e5SOllivier Robert ;# unlike xntpd I have perl do the dirty work. 455c0b746e5SOllivier Robert ;# Using floats here may affect precision, but 456c0b746e5SOllivier Robert ;# currently these bits aren't significant anyway 457c0b746e5SOllivier Robert return $sign * ($i + $f/2**32); 458c0b746e5SOllivier Robert} 459