File Coverage

blib/lib/Net/SNTP/Client.pm
Criterion Covered Total %
statement 139 147 94.5
branch 41 62 66.1
condition 12 29 41.3
subroutine 22 23 95.6
pod 1 1 100.0
total 215 262 82.0


line stmt bran cond sub pod time code
1             package Net::SNTP::Client;
2              
3             ## Validate the version of Perl
4              
5 1 50   1   61907 BEGIN { die 'Perl version 5.6.0 or greater is required' if ($] < 5.006); }
6              
7 1     1   8 use strict;
  1         2  
  1         20  
8 1     1   4 use warnings FATAL => 'all';
  1         2  
  1         51  
9              
10             =head1 NAME
11              
12             Net::SNTP::Client - Perl module to calculate the roundtrip delay d and
13             system clock offset t from NTP or SNTP Server.
14              
15              
16             =head1 VERSION
17              
18             Version 0.23
19              
20              
21             =cut
22              
23             ## Version of the Net::SNTP::Client module
24              
25             our $VERSION = '0.23';
26             $VERSION = eval $VERSION;
27              
28              
29             ## Load our modules
30              
31 1     1   396 use IO::Socket::INET;
  1         16859  
  1         5  
32 1     1   859 use Time::HiRes qw( gettimeofday );
  1         1103  
  1         4  
33              
34              
35             ## Handle importing/exporting of symbols
36              
37 1     1   130 use base qw( Exporter );
  1         2  
  1         98  
38             our @EXPORT_OK = qw ( getSNTPTime );
39              
40              
41             =head1 SYNOPSIS
42              
43             The Net::SNTP::Client - Perl module retrieves the time from an NTP or
44             SNTP server and uses the local time to calculate the roundtrip delay
45             d and system clock offset t based on RFC4330. The module is calculating
46             with higher accuracy in comparison to other modules.
47              
48             use Net::SNTP::Client qw ( getSNTPTime );
49              
50             my ( $error , $hashRefOutput ) = getSNTPTime( %hashInput );
51             ...
52              
53              
54             =head1 ABSTRACT
55              
56             The module sends a UDP packet formated according to
57             L to a defined NTP
58             or SNTP server set by the user. The received packet, gets decoded
59             to a human readable form and also calculated the roundtrip delay
60             d and system clock offset t, based on the decoded data.
61              
62              
63             =head1 DESCRIPTION
64              
65             This module exports a single method (getSNTPTime) and returns
66             an associative hash of hashes upon RFC4330 and a string in
67             case of an error occurs. The response from the NTP or SNTP server
68             is beeen decoded to a human readable format. The obtained
69             information recieved from the server can be can be used into
70             further processing or manipulation according to the user needs.
71             Maximum accuracy down to nano seconds can only be achieved on LinuxOS.
72              
73              
74             =over 4
75              
76             =item * HOSTNAME
77              
78             -hostname: The mandatory key inorder the method to produce
79             an output is only the hostname, the rest of the keys are optional.
80              
81              
82             =item * PORT
83              
84             -port: By default the the port is set to 123 (NTP default port).
85             The user has the option to overwite the port based on the expected
86             NTP port on the server side (e.g. -port => 123456).
87              
88              
89             =item * TIMEOUT
90              
91             -timeOut: By default the time out is set to 10 seconds. The user
92             has the option to overwite the time out input option based on the
93             expected connection time (e.g. timeOut => 15).
94              
95              
96             =item * RFC4330 OUTPUT
97              
98             -RFC4330: This is an optional way to produce an easy visual
99             output based on RFC4330 documentation. Expected input is a string,
100             integer or boolean in the form (0 or 1).
101              
102              
103             =item * CLEARSCREEN
104              
105             -clearScreen: This is an optional choice based on user preference
106             if he/she desires to clear the "terminal screen" before printing
107             the captured data. Expected input is a string, integer or boolean
108             in the form (0 or 1).
109              
110              
111             =back
112              
113             =head1 SUBROUTINES/METHODS
114              
115             my ( $error , $hashRefOutput ) = getSNTPTime( %hashInput );
116              
117              
118             =cut
119              
120             ## Define constands
121              
122             # The_version_of_constant provided by perl 5.6.1 does not support that.
123             # use constant {
124             # TRUE => 1,
125             # FALSE => 0,
126             # TIMEOUT => 10,
127             # MAXBYTES => 512,
128             # UNIX_EPOCH => 2208988800,
129             # MIN_UDP_PORT => 1,
130             # MAX_UDP_PORT => 65536,
131             # DEFAULT_NTP_PORT => 123,
132             # };
133              
134              
135 1     1   7 use constant TRUE => 1;
  1         1  
  1         58  
136 1     1   5 use constant FALSE => 0;
  1         2  
  1         46  
137 1     1   12 use constant TIMEOUT => 10;
  1         2  
  1         45  
138 1     1   4 use constant MAXBYTES => 512;
  1         3  
  1         50  
139 1     1   5 use constant UNIX_EPOCH => 2208988800;
  1         1  
  1         37  
140 1     1   4 use constant MIN_UDP_PORT => 1;
  1         2  
  1         46  
141 1     1   6 use constant MAX_UDP_PORT => 65536;
  1         1  
  1         36  
142 1     1   5 use constant DEFAULT_NTP_PORT => 123;
  1         1  
  1         1721  
143              
144             =head2 getSNTPTime
145              
146             my %hashInput = (
147             -hostname => $hostname, # hostnmae or IP
148             -port => $port, # default NTP port 123
149             -timeOut => $timeOut, # default 10
150             -RFC4330 => $RFC4330, # default 0
151             -clearScreen => $clearScreen, # default 0
152             );
153              
154             my ( $error , $hashRefOutput ) = getSNTPTime( %hashInput );
155              
156             This module exports a single method - getSNTPTime and an error
157             string in case of an error or a faulty operation. It expects a
158             hash as an input. The input can have four different hash
159             keys (-hostname, port, RFC4330 and -clearScreen).
160              
161              
162             =cut
163              
164             sub getSNTPTime {
165 11     11 1 23906 my $error = undef;
166 11         46 my %moduleInput = @_;
167              
168 11 100       31 return ($error = "Not defined key(s)", \%moduleInput)
169             if (_checkHashKeys(%moduleInput));
170             return ($error = "Not defined Hostname/IP", \%moduleInput)
171 10 100       29 if (!$moduleInput{-hostname});
172             return ($error = "Not correct port number", \%moduleInput)
173 8 100       21 if (_verifyPort($moduleInput{-port}));
174             return ($error = "Not correct timeOut input", \%moduleInput)
175 5 100       15 if (_verifyNumericInput($moduleInput{-timeOut}));
176             return ($error = "Not correct RFC4330 input", \%moduleInput)
177 4 100       12 if (_verifyBoolean($moduleInput{-RFC4330}));
178             return ($error = "Not correct clearScreen input", \%moduleInput)
179 3 100       10 if (_verifyBoolean($moduleInput{-clearScreen}));
180              
181 2         3 my $client_socket;
182 2         4 eval {
183             $client_socket = new IO::Socket::INET (
184             PeerHost => $moduleInput{-hostname},
185             Type => SOCK_DGRAM,
186 2 50 50     19 PeerPort => $moduleInput{-port} || DEFAULT_NTP_PORT, # Default 123
187             Proto => 'udp'
188             ) or die "Error Creating Socket";
189             };
190 2 50 33     75099 return ($error = "Problem While Creating Socket '$!'", \%moduleInput)
191             if ( $@ && $@ =~ /Error Creating Socket/ );
192              
193 2         34 my %SNTP_Client_Hash = (
194             "LI" => 0,
195             "VN" => 4,
196             "Mode" => 3,
197             "Stratum" => 0,
198             "Poll" => 0,
199             "Precision" => 0,
200             "Root Delay" => 0,
201             "Root Dispersion" => 0,
202             "Reference Identifier" => 0,
203             "Reference Timestamp" => "0.0",
204             "Originate Timestamp" => "0.0",
205             "Receive Timestamp Sec" => 0,
206             "Receive Timestamp Micro Sec" => 0,
207             "Transmit Timestamp Sec" => 0,
208             "Transmit Timestamp Micro Sec" => 0,
209             );
210              
211 2         11 my @SNTP_Receive = ( "LI VN Mode",
212             "Stratum",
213             "Poll",
214             "Precision",
215             "Root Delay",
216             "Root Delay Fraction",
217             "Root Dispersion",
218             "Root Dispersion Fraction",
219             "Reference Identifier",
220             "Reference Timestamp Sec",
221             "Reference Timestamp Micro Sec",
222             "Originate Timestamp Sec",
223             "Originate Timestamp Micro Sec",
224             "Receive Timestamp Sec",
225             "Receive Timestamp Micro Sec",
226             "Transmit Timestamp Sec",
227             "Transmit Timestamp Micro Sec" );
228              
229             ( $SNTP_Client_Hash{"Transmit Timestamp Sec"} ,
230 2         13 $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"} ) = gettimeofday();
231              
232             my $sendSntpPacket = pack( "B8 C3 N11",
233             '00100011',
234             (0) x 12,
235             $SNTP_Client_Hash{"Transmit Timestamp Sec"},
236 2         21 $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"} );
237              
238 2         5 eval {
239 2 50       13 $client_socket->send( $sendSntpPacket )
240             or die "Error Sending";
241             };
242 2 50 33     434 return ($error = "Problem While Sending '$!'", \%moduleInput)
243             if ( $@ && $@ =~ /Error Sending/ );
244              
245 2 50       11 $moduleInput{-timeOut} = TIMEOUT if ( !defined $moduleInput{-timeOut});
246 2         4 my $rcvSntpPacket = undef;
247 2         3 eval {
248 2     0   54 local $SIG{ALRM} = sub { die "Error Timeout"; };
  0         0  
249 2         21 alarm($moduleInput{-timeOut});
250 2 50       14 $client_socket->recv( $rcvSntpPacket , MAXBYTES )
251             or die "Error Receiving";
252 2         45140 alarm(0)
253             };
254              
255 2 50 33     20 if ( $@ && $@ =~ /Error Receiving/ ){
    50 33        
256 0         0 return ($error = "Problem While Receiving '$!'", \%moduleInput);
257              
258             }
259             elsif ($@ && $@ =~ /Error Timeout/) {
260 0         0 return ($error = "Net::SNTP::Client timed out waiting the packet '$!'", \%moduleInput);
261             }
262              
263             ( $SNTP_Client_Hash{"Receive Timestamp Sec"} ,
264 2         28 $SNTP_Client_Hash{"Receive Timestamp Micro Sec"} ) = gettimeofday();
265              
266 2         8 eval {
267 2 50       21 $client_socket->close()
268             or die "Error Closing Socket";
269             };
270 2 50 33     123 return ($error = "Problem While Clossing Socket '$!'", \%moduleInput)
271             if ( $@ && $@ =~ /Error Closing Socket/ );
272              
273 2         5 my %RcV;
274 2         150 @RcV{@SNTP_Receive} = unpack("B8 C3 s n3 H8 N8" , $rcvSntpPacket);
275              
276 2         16 $RcV{"LI Binary"} = substr( $RcV{"LI VN Mode"} , 0 , 2 );
277 2         9 $RcV{"LI"} = _binaryToDecimal( $RcV{"LI Binary"} , 8 , "c" );
278 2         5 delete $RcV{"LI Binary"};
279              
280 2         8 $RcV{"VN Binary"} = substr( $RcV{"LI VN Mode"} , 2 , 3 );
281 2         6 $RcV{"VN"} = _binaryToDecimal( $RcV{"VN Binary"} , 8 , "c" );
282 2         5 delete $RcV{"VN Binary"};
283              
284 2         13 $RcV{"Mode Binary"} = substr( $RcV{"LI VN Mode"} , 5 , 3 );
285 2         7 $RcV{"Mode"} = _binaryToDecimal( $RcV{"Mode Binary"} , 8 , "c" );
286 2         4 delete $RcV{"Mode Binary"};
287 2         5 delete $RcV{"LI VN Mode"};
288              
289 2         12 $RcV{"Poll"} = (sprintf("%.1d", $RcV{"Poll"}));
290              
291 2 50       9 if ($RcV{"Precision"} > 127) {
292 2         7 $RcV{"Precision"} = $RcV{"Precision"} - 255;
293             }
294             else {
295 0         0 $RcV{"Precision"} = "-" . $RcV{"Precision"};
296             }
297              
298             $RcV{"Root Delay Fraction"} =
299 2         8 sprintf("%05d", $RcV{"Root Delay Fraction"});
300              
301             $RcV{"Root Delay"} =
302 2         9 $RcV{"Root Delay"} . "." . $RcV{"Root Delay Fraction"};
303              
304             $RcV{"Root Dispersion Fraction"} =
305 2         7 sprintf("%05d", $RcV{"Root Dispersion Fraction"});
306              
307             $RcV{"Root Dispersion"} =
308 2         12 $RcV{"Root Dispersion"} . "." . $RcV{"Root Dispersion Fraction"};
309              
310             $RcV{"Reference Identifier"} =
311 2         8 _unpackIP($RcV{"Stratum"},$RcV{"Reference Identifier"});
312              
313 2         5 $RcV{"Reference Timestamp Sec"} -= UNIX_EPOCH;
314 2         4 $RcV{"Receive Timestamp Sec"} -= UNIX_EPOCH;
315 2         19 $RcV{"Transmit Timestamp Sec"} -= UNIX_EPOCH;
316              
317             my $d = (
318             (
319             ( $SNTP_Client_Hash{"Receive Timestamp Sec"} . "." . $SNTP_Client_Hash{"Receive Timestamp Micro Sec"} ) -
320             ( $SNTP_Client_Hash{"Transmit Timestamp Sec"} . "." . $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"} )
321             ) -
322             (
323             ( $RcV{"Transmit Timestamp Sec"} . "." . $RcV{"Transmit Timestamp Micro Sec"} ) -
324 2         31 ( $RcV{"Receive Timestamp Sec"} . "." . $RcV{"Receive Timestamp Micro Sec"} )
325             )
326             );
327              
328             my $t = (
329             (
330             (
331             ( $RcV{"Receive Timestamp Sec"} . "." . $RcV{"Receive Timestamp Micro Sec"} ) -
332             ( $SNTP_Client_Hash{"Transmit Timestamp Sec"} . "." . $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"} )
333             ) +
334             (
335             ( $RcV{"Transmit Timestamp Sec"} . "." . $RcV{"Transmit Timestamp Micro Sec"} ) -
336 2         21 ( $SNTP_Client_Hash{"Receive Timestamp Sec"} . "." . $SNTP_Client_Hash{"Receive Timestamp Micro Sec"} )
337             )
338             ) / 2
339             );
340              
341 2 0       7 (system $^O eq 'MSWin32' ? 'cls' : 'clear') if ($moduleInput{-clearScreen});
    50          
342              
343 2         5 my %moduleOutput = ();
344              
345 2 50       6 if ( $moduleInput{-RFC4330} ) {
346             $moduleOutput{-RFC4330} = "
347             \t Timestamp Name \t ID \t When Generated
348             \t ------------------------------------------------------------
349             \t Originate Timestamp \t T1 \t time request sent by client
350             \t Receive Timestamp \t T2 \t time request received by server
351             \t Transmit Timestamp \t T3 \t time reply sent by server
352             \t Destination Timestamp \t T4 \t time reply received by client
353              
354             \t The roundtrip delay d and local clock offset t are defined as
355              
356             \t d = (T4 - T1) - (T2 - T3) \t t = ((T2 - T1) + (T3 - T4)) / 2 \n
357              
358             \t Round Trip delay: ".$d."\n
359             \t Clock offset: ".$t."\n
360              
361             \t Field Name \t\t\t Unicast/Anycast
362             \t\t\t\t Request \t\t Reply
363             \t ------------------------------------------------------------
364             \t LI \t\t\t ".$SNTP_Client_Hash{"LI"}." \t\t\t ".$RcV{"LI"}."
365             \t VN \t\t\t ".$SNTP_Client_Hash{"VN"}." \t\t\t ".$RcV{"VN"}."
366             \t Mode \t\t\t ".$SNTP_Client_Hash{"Mode"}." \t\t\t ".$RcV{"Mode"}."
367             \t Stratum \t\t ".$SNTP_Client_Hash{"Stratum"}." \t\t\t ".$RcV{"Stratum"}."
368             \t Poll \t\t\t ".$SNTP_Client_Hash{"Poll"}." \t\t\t ".$RcV{"Poll"}."
369             \t Precision \t\t ".$SNTP_Client_Hash{"Precision"}." \t\t\t ".$RcV{"Precision"}."
370             \t Root Delay \t\t ".$SNTP_Client_Hash{"Root Delay"}." \t\t\t ".$RcV{"Root Delay"}."
371             \t Root Dispersion \t ".$SNTP_Client_Hash{"Root Dispersion"}." \t\t\t ".$RcV{"Root Dispersion"}."
372             \t Reference Identifier \t ".$SNTP_Client_Hash{"Reference Identifier"}." \t\t\t ".$RcV{"Reference Identifier"}."
373             \t Reference Timestamp \t ".$SNTP_Client_Hash{"Reference Timestamp"}." \t\t\t ".
374             $RcV{"Reference Timestamp Sec"}.".".
375             $RcV{"Reference Timestamp Micro Sec"}."
376             \t Originate Timestamp \t ".$SNTP_Client_Hash{"Originate Timestamp"}." \t\t\t ".
377             $RcV{"Originate Timestamp Sec"}.".".
378             $RcV{"Originate Timestamp Micro Sec"}."
379             \t Receive Timestamp \t ".
380             $SNTP_Client_Hash{"Receive Timestamp Sec"}.".".$SNTP_Client_Hash{"Receive Timestamp Micro Sec"}." \t ".
381             $RcV{"Receive Timestamp Sec"} . ".".
382             $RcV{"Receive Timestamp Micro Sec"}."
383             \t Transmit Timestamp \t ".
384             $SNTP_Client_Hash{"Transmit Timestamp Sec"} . "." . $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"}." \t ".
385             $RcV{"Transmit Timestamp Sec"} . ".".
386 0         0 $RcV{"Transmit Timestamp Micro Sec"}."";
387             }
388             else {
389             %moduleOutput = (
390             $moduleInput{-hostname} => {
391             "LI" => $RcV{"LI"},
392             "VN" => $RcV{"VN"},
393             "Mode" => $RcV{"Mode"},
394             "Stratum" => $RcV{"Stratum"},
395             "Poll" => $RcV{"Poll"},
396             "Precision" => $RcV{"Precision"},
397             "Root Delay" => $RcV{"Root Delay"},
398             "Root Dispersion" => $RcV{"Root Dispersion"},
399             "Reference Identifier" => $RcV{"Reference Identifier"},
400             "Reference Timestamp" => $RcV{"Reference Timestamp Sec"}.".".
401             $RcV{"Reference Timestamp Micro Sec"},
402             "Originate Timestamp" => $RcV{"Originate Timestamp Sec"}.".".
403             $RcV{"Originate Timestamp Micro Sec"},
404             "Receive Timestamp" => $RcV{"Receive Timestamp Sec"}.".".
405             $RcV{"Receive Timestamp Micro Sec"},
406             "Transmit Timestamp" => $RcV{"Transmit Timestamp Sec"}.".".
407             $RcV{"Transmit Timestamp Micro Sec"},
408             },
409             $0 => {
410             "LI" => $SNTP_Client_Hash{"LI"},
411             "VN" => $SNTP_Client_Hash{"VN"},
412             "Mode" => $SNTP_Client_Hash{"Mode"},
413             "Stratum" => $SNTP_Client_Hash{"Stratum"},
414             "Poll" => $SNTP_Client_Hash{"Poll"},
415             "Precision" => $SNTP_Client_Hash{"Precision"},
416             "Root Delay" => $SNTP_Client_Hash{"Root Delay"},
417             "Root Dispersion" => $SNTP_Client_Hash{"Root Dispersion"},
418             "Reference Identifier" => $SNTP_Client_Hash{"Reference Identifier"},
419             "Reference Timestamp" => $SNTP_Client_Hash{"Reference Timestamp"},
420             "Originate Timestamp" => $SNTP_Client_Hash{"Originate Timestamp"},
421             "Receive Timestamp" => $SNTP_Client_Hash{"Receive Timestamp Sec"}.".".
422             $SNTP_Client_Hash{"Receive Timestamp Micro Sec"},
423             "Transmit Timestamp" => $SNTP_Client_Hash{"Transmit Timestamp Sec"}.".".
424 2         92 $SNTP_Client_Hash{"Transmit Timestamp Micro Sec"},
425             },
426             RFC4330 => {
427             "Round Trip Delay" => $d,
428             "Clock Offset" => $t
429             }
430             )
431             }
432 2         47 return $error, \%moduleOutput;
433             }
434              
435             sub _checkHashKeys {
436 11     11   27 my @keysToCompare = ( "-hostname", "-port", "-timeOut", "-RFC4330", "-clearScreen" );
437 11         25 my %hashInputToCompare = @_;
438 11         23 my @hashInputKeysToCompare = keys %hashInputToCompare;
439 11         26 my @differendKeys = _keyDifference(\@hashInputKeysToCompare, \@keysToCompare);
440 11 100       27 if (@differendKeys) { return TRUE } else { return FALSE };
  1         11  
  10         36  
441             };
442              
443             sub _keyDifference {
444 11     11   14 my %hashdiff = map{ $_ => 1 } @{$_[1]};
  55         90  
  11         24  
445 11         15 return grep { !defined $hashdiff{$_} } @{$_[0]};
  41         77  
  11         24  
446             }
447              
448             sub _verifyNumericInput {
449 15     15   31 my $numericInput = shift;
450 15 100       32 return FALSE if (!defined $numericInput);
451 11 100 66     84 if ( defined $numericInput && $numericInput =~ /^[0-9]+$/ && $numericInput > 0 ) {
      66        
452 6         18 return FALSE;
453             }
454 5         20 return TRUE;
455             };
456              
457             sub _verifyPort {
458 8     8   14 my $port = shift;
459 8 50       16 return FALSE if (!defined $port);
460 8 100       17 if ( !_verifyNumericInput($port) ) {
461 6 100 66     21 if ( $port >= MIN_UDP_PORT && MAX_UDP_PORT >= $port ) {
462 5         11 return FALSE;
463             }
464             }
465 3         16 return TRUE;
466             };
467              
468             sub _verifyBoolean {
469 7     7   11 my $input = shift;
470 7 100       19 return FALSE if (!defined $input);
471 2 50       5 if ( !_verifyNumericInput($input) ) {
472 0 0 0     0 if ( $input eq "0" or $input eq "1" ) {
473 0         0 return FALSE;
474             }
475             }
476 2         11 return TRUE;
477             };
478              
479             sub _unpackIP{
480 2     2   2 my $ip;
481 2         5 my $stratum = shift;
482 2         5 my $tmp_ip = shift;
483 2 50       6 if($stratum < 2){
484 0         0 $ip = unpack("A4",
485             pack("H8", $tmp_ip)
486             );
487             }else{
488 2         11 $ip = sprintf("%d.%d.%d.%d",
489             unpack("C4",
490             pack("H8", $tmp_ip)
491             )
492             );
493             }
494 2         8 return $ip;
495             };
496              
497             sub _binaryToDecimal {
498 6     6   10 my $bits = shift;
499 6         9 my $size = shift;
500 6         9 my $template = shift;
501 6         41 return unpack($template, pack("B$size", substr("0" x $size . $bits , -$size)));
502             };
503              
504             =head1 EXAMPLE
505              
506             This example gets the time from a remote NTP server from the
507             L
508             and calculates the roundtrip delay d and local clock offset
509             t as defined on RFC4330.
510              
511             We use the L
512             module to print the output.
513              
514             #!/usr/bin/perl
515             use strict;
516             use warnings;
517             use Data::Dumper;
518              
519             use Net::SNTP::Client;
520              
521             my %hashInput = (
522             -hostname => "0.pool.ntp.org",
523             -port => 123,
524             -timeOut => 10,
525             -RFC4330 => 1,
526             -clearScreen => 1,
527             );
528              
529             my ( $error , $hashRefOutput ) = getSNTPTime( %hashInput );
530              
531             print Dumper $hashRefOutput;
532             print "Error: $error\n" if ($error);
533              
534             DEPENDENCIES
535              
536             The module is implemented using IO::Socket::INET and Time::HiRes
537             and requires both these modules to be installed.
538              
539              
540             =head1 AUTHOR
541              
542             Athanasios Garyfalos, C<< >>
543              
544              
545             =head1 BUGS
546              
547             Please report any bugs or feature requests to C, or through
548             the web interface at L. I will be notified, and then you'll
549             automatically be notified of progress on your bug as I make changes.
550              
551              
552             =head1 SUPPORT
553              
554             You can find documentation for this module with the perldoc command.
555              
556             perldoc Net::SNTP::Client
557              
558             You can also look for information at:
559              
560              
561             =over 4
562              
563             =item * RT: CPAN's request tracker (report bugs here)
564              
565             L
566              
567             =item * AnnoCPAN: Annotated CPAN documentation
568              
569             L
570              
571             =item * CPAN Ratings
572              
573             L
574              
575             =item * Search CPAN
576              
577             L
578              
579             =back
580              
581             =head1 SEE ALSO
582              
583             perl, IO::Socket, Net::NTP, Net::SNTP::Server, L
584              
585             Net::NTP has a similar focus as this module. In my opinion it
586             is less accurate when it comes to the precission bellow second(s).
587              
588             =head1 REPOSITORY
589              
590             L
591              
592              
593             =head1 DIFFERENCES FROM OTHER MODULES
594              
595             Based on the current known modules Net::SNTP::Client is only similar
596             to Net::NTP module. The two modules do not have in common the
597             encoding and decoding process of fractions of seconds.
598              
599             Be aware that on different OS different precision can be achieved.
600              
601             =head1 DIFFERENCES BETWEEN NTP AND SNTP
602              
603             SNTP (Simple Network Time Protocol) and NTP (Network Time Protocol)
604             are describing exactly the same network package format, the differences
605             can be found in the way how a system deals with the content of these
606             packages in order to synchronize its time.
607              
608             =head1 ACKNOWLEDGEMENTS
609              
610             The original concept for this module was based on F
611             written by James G. Willmore Ewillmorejg@gmail.comE.
612              
613             Copyright 2004 by James G. Willmore
614              
615             This library is free software; you can redistribute it and/or modify it under
616             the same terms as Perl itself.
617              
618              
619             =head1 LICENSE AND COPYRIGHT
620              
621             Copyright 2015 Athanasios Garyfalos.
622              
623             This program is free software; you can redistribute it and/or modify it
624             under the terms of the the Artistic License (2.0). You may obtain a
625             copy of the full license at:
626              
627             L
628              
629             Any use, modification, and distribution of the Standard or Modified
630             Versions is governed by this Artistic License. By using, modifying or
631             distributing the Package, you accept this license. Do not use, modify,
632             or distribute the Package, if you do not accept this license.
633              
634             If your Modified Version has been derived from a Modified Version made
635             by someone other than you, you are nevertheless required to ensure that
636             your Modified Version complies with the requirements of this license.
637              
638             This license does not grant you the right to use any trademark, service
639             mark, tradename, or logo of the Copyright Holder.
640              
641             This license includes the non-exclusive, worldwide, free-of-charge
642             patent license to make, have made, use, offer to sell, sell, import and
643             otherwise transfer the Package with respect to any patent claims
644             licensable by the Copyright Holder that are necessarily infringed by the
645             Package. If you institute patent litigation (including a cross-claim or
646             counterclaim) against any party alleging that the Package constitutes
647             direct or contributory patent infringement, then this Artistic License
648             to you shall terminate on the date that such litigation is filed.
649              
650             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
651             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
652             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
653             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
654             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
655             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
656             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
657             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
658              
659             =head1 CHANGE LOG
660             $Log: Client.pm,v $
661             Revision 23.0 2019/31/10 7:01:21 pm Thanos
662              
663             =cut
664              
665             1; # End of Net::SNTP::Client