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