1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.net.examples.ntp;
18
19 import java.io.IOException;
20 import java.net.DatagramPacket;
21 import java.net.DatagramSocket;
22
23 import org.apache.commons.net.ntp.NtpUtils;
24 import org.apache.commons.net.ntp.NtpV3Impl;
25 import org.apache.commons.net.ntp.NtpV3Packet;
26 import org.apache.commons.net.ntp.TimeStamp;
27
28
29
30
31
32
33
34
35 public class SimpleNTPServer implements Runnable {
36
37 public static void main(final String[] args) {
38 int port = NtpV3Packet.NTP_PORT;
39 if (args.length != 0) {
40 try {
41 port = Integer.parseInt(args[0]);
42 } catch (final NumberFormatException nfe) {
43 nfe.printStackTrace();
44 }
45 }
46 final SimpleNTPServer timeServer = new SimpleNTPServer(port);
47 try {
48 timeServer.start();
49 } catch (final IOException e) {
50 e.printStackTrace();
51 }
52 }
53
54 private int port;
55 private volatile boolean running;
56 private boolean started;
57
58 private DatagramSocket socket;
59
60
61
62
63 public SimpleNTPServer() {
64 this(NtpV3Packet.NTP_PORT);
65 }
66
67
68
69
70
71
72
73 public SimpleNTPServer(final int port) {
74 if (port < 0) {
75 throw new IllegalArgumentException();
76 }
77 this.port = port;
78 }
79
80
81
82
83
84
85 public void connect() throws IOException {
86 if (socket == null) {
87 socket = new DatagramSocket(port);
88
89 if (port == 0) {
90 port = socket.getLocalPort();
91 }
92 System.out.println("Running NTP service on port " + port + "/UDP");
93 }
94 }
95
96 public int getPort() {
97 return port;
98 }
99
100
101
102
103
104
105
106
107
108 protected void handlePacket(final DatagramPacket request, final long rcvTime) throws IOException {
109 final NtpV3Packet message = new NtpV3Impl();
110 message.setDatagramPacket(request);
111 System.out.printf("NTP packet from %s mode=%s%n", request.getAddress().getHostAddress(), NtpUtils.getModeName(message.getMode()));
112 if (message.getMode() == NtpV3Packet.MODE_CLIENT) {
113 final NtpV3Packet response = new NtpV3Impl();
114
115 response.setStratum(1);
116 response.setMode(NtpV3Packet.MODE_SERVER);
117 response.setVersion(NtpV3Packet.VERSION_3);
118 response.setPrecision(-20);
119 response.setPoll(0);
120 response.setRootDelay(62);
121 response.setRootDispersion((int) (16.51 * 65.536));
122
123
124 response.setOriginateTimeStamp(message.getTransmitTimeStamp());
125
126 response.setReceiveTimeStamp(TimeStamp.getNtpTime(rcvTime));
127 response.setReferenceTime(response.getReceiveTimeStamp());
128 response.setReferenceId(0x4C434C00);
129
130
131 response.setTransmitTime(TimeStamp.getNtpTime(System.currentTimeMillis()));
132
133 final DatagramPacket dp = response.getDatagramPacket();
134 dp.setPort(request.getPort());
135 dp.setAddress(request.getAddress());
136 socket.send(dp);
137 }
138
139 }
140
141
142
143
144
145
146 public boolean isRunning() {
147 return running;
148 }
149
150
151
152
153
154
155 public boolean isStarted() {
156 return started;
157 }
158
159
160
161
162 @Override
163 public void run() {
164 running = true;
165 final byte[] buffer = new byte[48];
166 final DatagramPacket request = new DatagramPacket(buffer, buffer.length);
167 do {
168 try {
169 socket.receive(request);
170 final long rcvTime = System.currentTimeMillis();
171 handlePacket(request, rcvTime);
172 } catch (final IOException e) {
173 if (running) {
174 e.printStackTrace();
175 }
176
177 }
178 } while (running);
179 }
180
181
182
183
184
185
186 public void start() throws IOException {
187 if (socket == null) {
188 connect();
189 }
190 if (!started) {
191 started = true;
192 new Thread(this).start();
193 }
194 }
195
196
197
198
199 public void stop() {
200 running = false;
201 if (socket != null) {
202 socket.close();
203 socket = null;
204 }
205 started = false;
206 }
207
208 }