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