View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.examples.ntp;
19  
20  import java.io.IOException;
21  import java.net.InetAddress;
22  import java.net.SocketException;
23  import java.net.UnknownHostException;
24  import java.text.DecimalFormat;
25  import java.text.NumberFormat;
26  import java.time.Duration;
27  import java.util.Objects;
28  
29  import org.apache.commons.net.ntp.NTPUDPClient;
30  import org.apache.commons.net.ntp.NtpUtils;
31  import org.apache.commons.net.ntp.NtpV3Packet;
32  import org.apache.commons.net.ntp.TimeInfo;
33  import org.apache.commons.net.ntp.TimeStamp;
34  
35  /**
36   * This is an example program demonstrating how to use the NTPUDPClient class. This program sends a Datagram client request packet to a Network time Protocol
37   * (NTP) service port on a specified server, retrieves the time, and prints it to standard output along with the fields from the NTP message header (e.g.
38   * stratum level, reference id, poll interval, root delay, mode, ...) See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> for details.
39   * <p>
40   * Usage: NTPClient {@code <hostname-or-address-list>}
41   * </p>
42   * <p>
43   * Example: NTPClient clock.psu.edu
44   * </p>
45   */
46  public final class NTPClient {
47  
48      private static final String OWN_CLOCK_IP_ADDRESS = "127.127.1.0"; // NOPMD
49      private static final NumberFormat numberFormat = new DecimalFormat("0.00");
50  
51      public static void main(final String[] args) {
52          if (args.length == 0) {
53              System.err.println("Usage: NTPClient <hostname-or-address-list>");
54              System.exit(1);
55          }
56  
57          try (NTPUDPClient client = new NTPUDPClient()) {
58              // We want to timeout if a response takes longer than 10 seconds
59              client.setDefaultTimeout(Duration.ofSeconds(10));
60              try {
61                  client.open();
62                  for (final String arg : args) {
63                      System.out.println();
64                      try {
65                          final InetAddress hostAddr = InetAddress.getByName(arg);
66                          System.out.println("> " + hostAddr.getHostName() + "/" + hostAddr.getHostAddress());
67                          final TimeInfo info = client.getTime(hostAddr);
68                          processResponse(info);
69                      } catch (final IOException ioe) {
70                          ioe.printStackTrace();
71                      }
72                  }
73              } catch (final SocketException e) {
74                  e.printStackTrace();
75              }
76          }
77      }
78  
79      /**
80       * Process {@code TimeInfo} object and print its details.
81       *
82       * @param info {@code TimeInfo} object.
83       */
84      public static void processResponse(final TimeInfo info) {
85          final NtpV3Packet message = info.getMessage();
86          final int stratum = message.getStratum();
87          final String refType;
88          if (stratum <= 0) {
89              refType = "(Unspecified or Unavailable)";
90          } else if (stratum == 1) {
91              refType = "(Primary Reference; e.g., GPS)"; // GPS, radio clock, etc.
92          } else {
93              refType = "(Secondary Reference; e.g. via NTP or SNTP)";
94          }
95          // stratum should be 0..15...
96          System.out.println(" Stratum: " + stratum + " " + refType);
97          final int version = message.getVersion();
98          final int li = message.getLeapIndicator();
99          System.out.println(" leap=" + li + ", version=" + version + ", precision=" + message.getPrecision());
100 
101         System.out.println(" mode: " + message.getModeName() + " (" + message.getMode() + ")");
102         final int poll = message.getPoll();
103         // poll value typically btwn MINPOLL (4) and MAXPOLL (14)
104         System.out.println(" poll: " + (poll <= 0 ? 1 : (int) Math.pow(2, poll)) + " seconds (2 ** " + poll + ")");
105         final double disp = message.getRootDispersionInMillisDouble();
106         System.out.println(" rootdelay=" + numberFormat.format(message.getRootDelayInMillisDouble()) + ", rootdispersion(ms): " + numberFormat.format(disp));
107 
108         final int refId = message.getReferenceId();
109         String refAddr = NtpUtils.getHostAddress(refId);
110         String refName = null;
111         if (refId != 0) {
112             if (refAddr.equals(OWN_CLOCK_IP_ADDRESS)) {
113                 refName = "LOCAL"; // This is the ref address for the Local Clock
114             } else if (stratum >= 2) {
115                 // If reference id has 127.127 prefix then it uses its own reference clock
116                 // defined in the form 127.127.clock-type.unit-num (e.g. 127.127.8.0 mode 5
117                 // for GENERIC DCF77 AM; see refclock.htm from the NTP software distribution.
118                 if (!refAddr.startsWith("127.127")) {
119                     try {
120                         final InetAddress addr = InetAddress.getByName(refAddr);
121                         final String name = addr.getHostName();
122                         if (name != null && !name.equals(refAddr)) {
123                             refName = name;
124                         }
125                     } catch (final UnknownHostException e) {
126                         // some stratum-2 servers sync to ref clock device but fudge stratum level higher... (e.g. 2)
127                         // ref not valid host maybe it's a reference clock name?
128                         // otherwise just show the ref IP address.
129                         refName = NtpUtils.getReferenceClock(message);
130                     }
131                 }
132             } else if (version >= 3 && (stratum == 0 || stratum == 1)) {
133                 refName = NtpUtils.getReferenceClock(message);
134                 // refname usually have at least 3 characters (e.g. GPS, WWV, LCL, etc.)
135             }
136             // otherwise give up on naming the beast...
137         }
138         if (refName != null && refName.length() > 1) {
139             refAddr += " (" + refName + ")";
140         }
141         System.out.println(" Reference Identifier:\t" + refAddr);
142 
143         final TimeStamp refNtpTime = message.getReferenceTimeStamp();
144         System.out.println(" Reference Timestamp:\t" + refNtpTime + "  " + refNtpTime.toDateString());
145 
146         // Originate Time is time request sent by client (t1)
147         final TimeStamp origNtpTime = message.getOriginateTimeStamp();
148         System.out.println(" Originate Timestamp:\t" + origNtpTime + "  " + origNtpTime.toDateString());
149 
150         final long destTimeMillis = info.getReturnTime();
151         // Receive Time is time request received by server (t2)
152         final TimeStamp rcvNtpTime = message.getReceiveTimeStamp();
153         System.out.println(" Receive Timestamp:\t" + rcvNtpTime + "  " + rcvNtpTime.toDateString());
154 
155         // Transmit time is time reply sent by server (t3)
156         final TimeStamp xmitNtpTime = message.getTransmitTimeStamp();
157         System.out.println(" Transmit Timestamp:\t" + xmitNtpTime + "  " + xmitNtpTime.toDateString());
158 
159         // Destination time is time reply received by client (t4)
160         final TimeStamp destNtpTime = TimeStamp.getNtpTime(destTimeMillis);
161         System.out.println(" Destination Timestamp:\t" + destNtpTime + "  " + destNtpTime.toDateString());
162 
163         info.computeDetails(); // compute offset/delay if not already done
164         final Long offsetMillis = info.getOffset();
165         final Long delayMillis = info.getDelay();
166         final String delay = Objects.toString(delayMillis, "N/A");
167         final String offset = Objects.toString(offsetMillis, "N/A");
168 
169         System.out.println(" Roundtrip delay(ms)=" + delay + ", clock offset(ms)=" + offset); // offset in ms
170     }
171 
172 }