1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.ntp;
19
20 import java.net.DatagramPacket;
21 import java.util.Arrays;
22
23
24
25
26 public class NtpV3Impl implements NtpV3Packet {
27
28 private static final int MODE_INDEX = 0;
29 private static final int MODE_SHIFT = 0;
30
31 private static final int VERSION_INDEX = 0;
32 private static final int VERSION_SHIFT = 3;
33
34 private static final int LI_INDEX = 0;
35 private static final int LI_SHIFT = 6;
36
37 private static final int STRATUM_INDEX = 1;
38 private static final int POLL_INDEX = 2;
39 private static final int PRECISION_INDEX = 3;
40
41 private static final int ROOT_DELAY_INDEX = 4;
42 private static final int ROOT_DISPERSION_INDEX = 8;
43 private static final int REFERENCE_ID_INDEX = 12;
44
45 private static final int REFERENCE_TIMESTAMP_INDEX = 16;
46 private static final int ORIGINATE_TIMESTAMP_INDEX = 24;
47 private static final int RECEIVE_TIMESTAMP_INDEX = 32;
48 private static final int TRANSMIT_TIMESTAMP_INDEX = 40;
49
50
51
52
53
54
55
56
57
58
59 protected static final int ui(final byte b) {
60 return b & 0xFF;
61 }
62
63
64
65
66
67
68
69 protected static final long ul(final byte b) {
70 return b & 0xFF;
71 }
72
73 private final byte[] buf = new byte[48];
74
75 private volatile DatagramPacket dp;
76
77
78 public NtpV3Impl() {
79 }
80
81
82
83
84
85
86
87
88
89 @Override
90 public boolean equals(final Object obj) {
91 if (this == obj) {
92 return true;
93 }
94 if (obj == null || getClass() != obj.getClass()) {
95 return false;
96 }
97 final NtpV3Impl other = (NtpV3Impl) obj;
98 return Arrays.equals(buf, other.buf);
99 }
100
101
102
103
104
105
106 @Override
107 public synchronized DatagramPacket getDatagramPacket() {
108 if (dp == null) {
109 dp = new DatagramPacket(buf, buf.length);
110 dp.setPort(NTP_PORT);
111 }
112 return dp;
113 }
114
115
116
117
118
119
120 private int getInt(final int index) {
121 return ui(buf[index]) << 24 | ui(buf[index + 1]) << 16 | ui(buf[index + 2]) << 8 | ui(buf[index + 3]);
122 }
123
124
125
126
127
128
129
130 @Override
131 public int getLeapIndicator() {
132 return ui(buf[LI_INDEX]) >> LI_SHIFT & 0x3;
133 }
134
135
136
137
138
139
140 private long getLong(final int index) {
141 return ul(buf[index]) << 56 | ul(buf[index + 1]) << 48 | ul(buf[index + 2]) << 40 | ul(buf[index + 3]) << 32 | ul(buf[index + 4]) << 24
142 | ul(buf[index + 5]) << 16 | ul(buf[index + 6]) << 8 | ul(buf[index + 7]);
143 }
144
145
146
147
148
149
150 @Override
151 public int getMode() {
152 return ui(buf[MODE_INDEX]) >> MODE_SHIFT & 0x7;
153 }
154
155
156
157
158
159
160 @Override
161 public String getModeName() {
162 return NtpUtils.getModeName(getMode());
163 }
164
165
166
167
168
169
170 @Override
171 public TimeStamp getOriginateTimeStamp() {
172 return getTimestamp(ORIGINATE_TIMESTAMP_INDEX);
173 }
174
175
176
177
178
179
180
181
182 @Override
183 public int getPoll() {
184 return buf[POLL_INDEX];
185 }
186
187
188
189
190
191
192 @Override
193 public int getPrecision() {
194 return buf[PRECISION_INDEX];
195 }
196
197
198
199
200
201
202 @Override
203 public TimeStamp getReceiveTimeStamp() {
204 return getTimestamp(RECEIVE_TIMESTAMP_INDEX);
205 }
206
207
208
209
210
211
212 @Override
213 public int getReferenceId() {
214 return getInt(REFERENCE_ID_INDEX);
215 }
216
217
218
219
220
221
222
223 @Override
224 public String getReferenceIdString() {
225 final int version = getVersion();
226 final int stratum = getStratum();
227 if (version == VERSION_3 || version == VERSION_4) {
228 if (stratum == 0 || stratum == 1) {
229 return idAsString();
230 }
231
232 if (version == VERSION_4) {
233 return idAsHex();
234 }
235 }
236
237
238
239 if (stratum >= 2) {
240 return idAsIPAddress();
241 }
242 return idAsHex();
243 }
244
245
246
247
248
249
250 @Override
251 public TimeStamp getReferenceTimeStamp() {
252 return getTimestamp(REFERENCE_TIMESTAMP_INDEX);
253 }
254
255
256
257
258
259
260
261 @Override
262 public int getRootDelay() {
263 return getInt(ROOT_DELAY_INDEX);
264 }
265
266
267
268
269
270
271
272 @Override
273 public double getRootDelayInMillisDouble() {
274 final double l = getRootDelay();
275 return l / 65.536;
276 }
277
278
279
280
281
282
283 @Override
284 public int getRootDispersion() {
285 return getInt(ROOT_DISPERSION_INDEX);
286 }
287
288
289
290
291
292
293 @Override
294 public long getRootDispersionInMillis() {
295 final long l = getRootDispersion();
296 return l * 1000 / 65536L;
297 }
298
299
300
301
302
303
304 @Override
305 public double getRootDispersionInMillisDouble() {
306 final double l = getRootDispersion();
307 return l / 65.536;
308 }
309
310
311
312
313
314
315
316 @Override
317 public int getStratum() {
318 return ui(buf[STRATUM_INDEX]);
319 }
320
321
322
323
324
325
326
327 private TimeStamp getTimestamp(final int index) {
328 return new TimeStamp(getLong(index));
329 }
330
331
332
333
334
335
336 @Override
337 public TimeStamp getTransmitTimeStamp() {
338 return getTimestamp(TRANSMIT_TIMESTAMP_INDEX);
339 }
340
341
342
343
344
345
346 @Override
347 public String getType() {
348 return "NTP";
349 }
350
351
352
353
354
355
356 @Override
357 public int getVersion() {
358 return ui(buf[VERSION_INDEX]) >> VERSION_SHIFT & 0x7;
359 }
360
361
362
363
364
365
366
367 @Override
368 public int hashCode() {
369 return Arrays.hashCode(buf);
370 }
371
372 private String idAsHex() {
373 return Integer.toHexString(getReferenceId());
374 }
375
376
377
378
379
380
381 private String idAsIPAddress() {
382 return ui(buf[REFERENCE_ID_INDEX]) + "." + ui(buf[REFERENCE_ID_INDEX + 1]) + "." + ui(buf[REFERENCE_ID_INDEX + 2]) + "."
383 + ui(buf[REFERENCE_ID_INDEX + 3]);
384 }
385
386 private String idAsString() {
387 final StringBuilder id = new StringBuilder();
388 for (int i = 0; i <= 3; i++) {
389 final char c = (char) buf[REFERENCE_ID_INDEX + i];
390 if (c == 0) {
391 break;
392 }
393 id.append(c);
394 }
395 return id.toString();
396 }
397
398
399
400
401
402
403
404 @Override
405 public void setDatagramPacket(final DatagramPacket srcDp) {
406 if (srcDp == null || srcDp.getLength() < buf.length) {
407 throw new IllegalArgumentException();
408 }
409 final byte[] incomingBuf = srcDp.getData();
410 int len = srcDp.getLength();
411 if (len > buf.length) {
412 len = buf.length;
413 }
414 System.arraycopy(incomingBuf, 0, buf, 0, len);
415 final DatagramPacket dp = getDatagramPacket();
416 dp.setAddress(srcDp.getAddress());
417 final int port = srcDp.getPort();
418 dp.setPort(port > 0 ? port : NTP_PORT);
419 dp.setData(buf);
420 }
421
422
423
424
425
426
427
428 private void setInt(final int idx, int value) {
429 for (int i = 3; i >= 0; i--) {
430 buf[idx + i] = (byte) (value & 0xff);
431 value >>>= 8;
432 }
433 }
434
435
436
437
438
439
440 @Override
441 public void setLeapIndicator(final int li) {
442 buf[LI_INDEX] = (byte) (buf[LI_INDEX] & 0x3F | (li & 0x3) << LI_SHIFT);
443 }
444
445
446
447
448
449
450 @Override
451 public void setMode(final int mode) {
452 buf[MODE_INDEX] = (byte) (buf[MODE_INDEX] & 0xF8 | mode & 0x7);
453 }
454
455
456
457
458
459
460 @Override
461 public void setOriginateTimeStamp(final TimeStamp ts) {
462 setTimestamp(ORIGINATE_TIMESTAMP_INDEX, ts);
463 }
464
465
466
467
468
469
470 @Override
471 public void setPoll(final int poll) {
472 buf[POLL_INDEX] = (byte) (poll & 0xFF);
473 }
474
475
476
477
478
479
480
481 @Override
482 public void setPrecision(final int precision) {
483 buf[PRECISION_INDEX] = (byte) (precision & 0xFF);
484 }
485
486
487
488
489
490
491 @Override
492 public void setReceiveTimeStamp(final TimeStamp ts) {
493 setTimestamp(RECEIVE_TIMESTAMP_INDEX, ts);
494 }
495
496
497
498
499
500
501 @Override
502 public void setReferenceId(final int refId) {
503 setInt(REFERENCE_ID_INDEX, refId);
504 }
505
506
507
508
509
510
511 @Override
512 public void setReferenceTime(final TimeStamp ts) {
513 setTimestamp(REFERENCE_TIMESTAMP_INDEX, ts);
514 }
515
516
517
518
519
520
521
522 @Override
523 public void setRootDelay(final int delay) {
524 setInt(ROOT_DELAY_INDEX, delay);
525 }
526
527
528
529
530
531
532
533 @Override
534 public void setRootDispersion(final int dispersion) {
535 setInt(ROOT_DISPERSION_INDEX, dispersion);
536 }
537
538
539
540
541
542
543 @Override
544 public void setStratum(final int stratum) {
545 buf[STRATUM_INDEX] = (byte) (stratum & 0xFF);
546 }
547
548
549
550
551
552
553
554 private void setTimestamp(final int index, final TimeStamp t) {
555 long ntpTime = t == null ? 0 : t.ntpValue();
556
557
558 for (int i = 7; i >= 0; i--) {
559 buf[index + i] = (byte) (ntpTime & 0xFF);
560 ntpTime >>>= 8;
561 }
562
563 }
564
565
566
567
568
569
570 @Override
571 public void setTransmitTime(final TimeStamp ts) {
572 setTimestamp(TRANSMIT_TIMESTAMP_INDEX, ts);
573 }
574
575
576
577
578
579
580 @Override
581 public void setVersion(final int version) {
582 buf[VERSION_INDEX] = (byte) (buf[VERSION_INDEX] & 0xC7 | (version & 0x7) << VERSION_SHIFT);
583 }
584
585
586
587
588
589
590 @Override
591 public String toString() {
592 return "[version:" + getVersion() + ", mode:" + getMode() + ", poll:" + getPoll() + ", precision:" + getPrecision() + ", delay:" + getRootDelay()
593 + ", dispersion(ms):" + getRootDispersionInMillisDouble() + ", id:" + getReferenceIdString() + ", xmitTime:"
594 + getTransmitTimeStamp().toDateString() + " ]";
595 }
596
597 }