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.io.IOUtils;
24 import org.apache.commons.net.ntp.NtpUtils;
25 import org.apache.commons.net.ntp.NtpV3Impl;
26 import org.apache.commons.net.ntp.NtpV3Packet;
27 import org.apache.commons.net.ntp.TimeStamp;
28
29
30
31
32
33
34
35
36 public class SimpleNTPServer implements Runnable {
37
38 public static void main(final String[] args) {
39 int port = NtpV3Packet.NTP_PORT;
40 if (args.length != 0) {
41 try {
42 port = Integer.parseInt(args[0]);
43 } catch (final NumberFormatException nfe) {
44 nfe.printStackTrace();
45 }
46 }
47 final SimpleNTPServer timeServer = new SimpleNTPServer(port);
48 try {
49 timeServer.start();
50 } catch (final IOException e) {
51 e.printStackTrace();
52 }
53 }
54
55 private int port;
56 private volatile boolean running;
57 private boolean started;
58
59 private DatagramSocket socket;
60
61
62
63
64 public SimpleNTPServer() {
65 this(NtpV3Packet.NTP_PORT);
66 }
67
68
69
70
71
72
73
74 public SimpleNTPServer(final int port) {
75 if (port < 0) {
76 throw new IllegalArgumentException();
77 }
78 this.port = port;
79 }
80
81
82
83
84
85
86 public void connect() throws IOException {
87 if (socket == null) {
88 socket = new DatagramSocket(port);
89
90 if (port == 0) {
91 port = socket.getLocalPort();
92 }
93 System.out.println("Running NTP service on port " + port + "/UDP");
94 }
95 }
96
97 public int getPort() {
98 return port;
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
202 IOUtils.closeQuietly(socket);
203 socket = null;
204 started = false;
205 }
206
207 }