8 #include "xclox/ntp/packet.hpp"
10 #include "tools/helper.hpp"
15 using namespace xclox::ntp;
16 using namespace std::chrono;
29 0x98, 0x76, 0x54, 0x32,
30 0xCB, 0xA9, 0x87, 0x65,
31 0x23, 0x45, 0x67, 0x89,
32 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC,
33 0xE9, 0x87, 0x65, 0x43, 0x21, 0x0F, 0xED, 0xCB,
34 0xE8, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
35 0xE7, 0x65, 0x43, 0x21, 0x0F, 0xED, 0xCB, 0xA9
38 const auto& ntpToSys = [](
const system_clock::duration& duration) {
return duration - xclox::ntp::internal::EpochDeltaSeconds; };
40 TEST_CASE(
"default constructible to null")
43 CHECK(p.
data() == zeros);
46 TEST_CASE(
"constructible from raw data")
49 CHECK(p1.data() == zeros);
52 CHECK(p2.data() == ones);
55 CHECK(p3.data() == pattern);
58 TEST_CASE(
"zeroed data is null")
61 CHECK(p1.
isNull() ==
true);
64 CHECK(p2.isNull() ==
true);
67 CHECK(p3.isNull() ==
false);
69 for (
size_t i = 0; i != std::tuple_size<Packet::DataType> {}; ++i) {
73 CHECK(p4.isNull() ==
false);
77 TEST_CASE(
"leap bits [0-1]")
79 for (uint8_t i = 0; i < 4; ++i) {
81 data[0] =
static_cast<uint8_t
>(i << 6);
87 TEST_CASE(
"version bits [2-4]")
89 for (uint8_t i = 0; i < 8; ++i) {
91 data[0] =
static_cast<uint8_t
>(i << 3);
93 CHECK(p.version() == i);
97 TEST_CASE(
"mode bits [5-7]")
99 for (uint8_t i = 0; i < 8; ++i) {
101 data[0] =
static_cast<uint8_t
>(i);
103 CHECK(p.mode() == i);
107 TEST_CASE(
"leap, version, and mode bits coexist")
109 for (uint8_t i = 0; i < 8; ++i) {
111 data[0] =
static_cast<uint8_t
>(i << 6 | i << 3 | i);
114 CHECK(p.leap() == i);
116 CHECK(p.version() == i);
117 CHECK(p.mode() == i);
121 TEST_CASE(
"stratum bits [8-15]")
128 CHECK(p2.stratum() == 1);
131 CHECK(p3.stratum() == 254);
134 TEST_CASE(
"poll bits [16-23]")
138 CHECK(p1.
poll() == 0);
141 CHECK(p2.poll() == 1);
142 data[2] =
static_cast<uint8_t
>(-10);
144 CHECK(p3.poll() == -10);
147 TEST_CASE(
"precision bits [24-31]")
154 CHECK(p2.precision() == 1);
155 data[3] =
static_cast<uint8_t
>(-20);
157 CHECK(p3.precision() == -20);
160 TEST_CASE(
"32-bit values ( root delay [32-63], root dispersion [64-95], reference ID [96-127] )")
162 std::map<size_t, uint32_t (
Packet::*)()
const> offsetFunctionMap {
167 for (
const auto& pair : offsetFunctionMap) {
170 CHECK((p1.*pair.second)() == 0);
171 data[pair.first + 3] = 1;
173 CHECK((p2.*pair.second)() == 1);
174 data[pair.first + 0] = 0x01;
175 data[pair.first + 1] = 0x23;
176 data[pair.first + 2] = 0x45;
177 data[pair.first + 3] = 0x67;
179 CHECK((p3.*pair.second)() == 0x01234567);
183 TEST_CASE(
"64-bit timestamps ( reference [128-191], origin [192-255], receive [256-319], transmit [320-383] )")
185 std::map<size_t, uint64_t (
Packet::*)()
const> offsetFunctionMap {
191 for (
const auto& pair : offsetFunctionMap) {
194 CHECK((p1.*pair.second)() == 0);
195 data[pair.first + 7] = 1;
197 CHECK((p2.*pair.second)() == 1);
198 data[pair.first + 0] = 0x01;
199 data[pair.first + 1] = 0x23;
200 data[pair.first + 2] = 0x45;
201 data[pair.first + 3] = 0x67;
202 data[pair.first + 4] = 0x89;
203 data[pair.first + 5] = 0xAB;
204 data[pair.first + 6] = 0xCD;
205 data[pair.first + 7] = 0xEF;
207 CHECK((p3.*pair.second)() == 0x0123456789ABCDEF);
211 TEST_CASE(
"constructible from values")
228 CHECK(p0.data() == zeros);
234 static_cast<int8_t
>(0xFF),
235 static_cast<int8_t
>(0xFF),
244 CHECK(p1.
data() == ones);
250 static_cast<int8_t
>(0xFA),
251 static_cast<int8_t
>(0xEC),
260 CHECK(p2.data() == pattern);
263 TEST_CASE(
"comparable")
271 CHECK_FALSE(p2 == p3);
272 CHECK_FALSE(p3 == p4);
275 CHECK_FALSE(p1 != p1);
276 CHECK_FALSE(p1 != p2);
279 CHECK_FALSE(p3 != p3);
280 CHECK_FALSE(p4 != p4);
283 TEST_CASE(
"copyable")
314 CHECK(p6 ==
Packet(zeros));
315 CHECK(p7 ==
Packet(ones));
316 CHECK(p8 ==
Packet(pattern));
319 TEST_CASE(
"packet delay & offset")
321 SUBCASE(
"null packet")
324 CHECK(p.
delay(0) == system_clock::duration(0));
325 CHECK(p.
offset(0) == system_clock::duration(0));
327 SUBCASE(
"up-to-date clocks")
329 uint64_t origin = 0xE902661000000000;
330 uint64_t receive = origin + 0x40000000;
331 uint64_t transmit = origin + 0x80000000;
332 uint64_t destination = origin + 0xC0000000;
333 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
334 CHECK(p.delay(destination) == milliseconds(500));
335 CHECK(p.offset(destination) == system_clock::duration(0));
337 SUBCASE(
"zero latency")
339 uint64_t origin = 0xE902661000000000;
340 uint64_t receive = origin;
341 uint64_t transmit = origin + 0x80000000;
342 uint64_t destination = transmit;
343 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
344 CHECK(p.delay(destination) == system_clock::duration(0));
345 CHECK(p.offset(destination) == system_clock::duration(0));
347 SUBCASE(
"client clock is at NTP epoch")
350 uint64_t receive = 0xE902661010000000;
351 uint64_t transmit = receive + 0x10000000;
352 uint64_t destination = origin + 0x30000000;
353 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
354 CHECK(p.delay(destination) == milliseconds(125));
355 CHECK(p.offset(destination) == seconds(0xE9026610));
357 SUBCASE(
"client clock is at end of NTP era")
359 uint64_t origin = 0xFFFFFFFF00000000;
360 uint64_t receive = 0xE902661010000000;
361 uint64_t transmit = receive + 0x10000000;
362 uint64_t destination = origin + 0x30000000;
363 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
364 CHECK(p.delay(destination) == milliseconds(125));
365 CHECK(p.offset(destination) == -seconds(0x16FD99EF));
367 SUBCASE(
"client clock is at start of next NTP era")
370 uint64_t receive = 0xFFFFFFFF10000000;
371 uint64_t transmit = receive + 0x10000000;
372 uint64_t destination = origin + 0x40000000;
373 system_clock::time_point destinationTP(ntpToSys(seconds(0x100000000) + milliseconds(250)));
374 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
375 CHECK(p.delay(destination) == microseconds(187500));
377 CHECK(p.offset(destination) == seconds(0xFFFFFFFF) - microseconds(31250));
379 CHECK(p.offset(destinationTP) == -seconds(1) - microseconds(31250));
381 SUBCASE(
"server clock is at start of next NTP era")
383 uint64_t origin = 0xFFFFFFFF00000000;
384 uint64_t receive = 0x0000000010000000;
385 uint64_t transmit = receive + 0x10000000;
386 uint64_t destination = origin + 0x40000000;
387 system_clock::time_point destinationTP(ntpToSys(seconds(0xFFFFFFFF) + milliseconds(250)));
388 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
389 CHECK(p.delay(destination) == microseconds(187500));
391 CHECK(p.offset(destination) == -seconds(0xFFFFFFFF) - microseconds(31250));
393 CHECK(p.offset(destinationTP) == seconds(1) - microseconds(31250));
395 SUBCASE(
"client clock behind server clock by 68 years")
397 uint64_t origin = 0x8000000100000000;
398 uint64_t receive = 0x0000000010000000;
399 uint64_t transmit = receive + 0x10000000;
400 uint64_t destination = origin + 0x40000000;
401 system_clock::time_point destinationTP(ntpToSys(seconds(0x80000001) + milliseconds(250)));
402 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
403 CHECK(p.delay(destination) == microseconds(187500));
405 CHECK(p.offset(destination) == -seconds(0x80000001) - microseconds(31250));
407 CHECK(p.offset(destinationTP) == seconds(0x7FFFFFFF) - microseconds(31250));
409 SUBCASE(
"server clock behind client clock by 68 years")
411 uint64_t origin = 0x8000000000000000;
412 uint64_t receive = 0x0000000010000000;
413 uint64_t transmit = receive + 0x10000000;
414 uint64_t destination = origin + 0x40000000;
415 system_clock::time_point destinationTP(ntpToSys(seconds(0x80000000) + milliseconds(250)));
416 Packet p(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, origin, receive, transmit);
417 CHECK(p.delay(destination) == microseconds(187500));
419 CHECK(p.offset(destination) == -seconds(0x80000000) - microseconds(31250));
421 CHECK(p.offset(destinationTP) == -seconds(0x80000000) - microseconds(31250));
Packet is an immutable raw NTP packet.
Definition: packet.hpp:54
int8_t precision() const
Returns a signed integer representing the precision of the system clock, in log2 seconds.
Definition: packet.hpp:187
bool isNull() const
Returns whether the underlying data is all zeros.
Definition: packet.hpp:119
uint64_t transmitTimestamp() const
Returns the server's time at which the packet departed to the client.
Definition: packet.hpp:229
internal::DataType DataType
Type of packet's underlying data.
Definition: packet.hpp:56
std::chrono::system_clock::duration offset(uint64_t destination) const
Returns the time offset of the server relative to the client.
Definition: packet.hpp:253
uint32_t referenceID() const
Returns a 32-bit code identifying the particular server or reference clock.
Definition: packet.hpp:205
uint32_t rootDispersion() const
Returns the total dispersion to the reference clock, in NTP short format.
Definition: packet.hpp:199
std::chrono::system_clock::duration delay(uint64_t destination) const
Returns the round-trip delay of the NTP packet passed from client to server and back again.
Definition: packet.hpp:240
uint64_t originTimestamp() const
Returns the client's time at which the packet departed to the server.
Definition: packet.hpp:217
uint64_t referenceTimestamp() const
Returns the server's time at which the system clock was last set or corrected.
Definition: packet.hpp:211
int8_t poll() const
Returns a signed integer representing the maximum interval between successive messages,...
Definition: packet.hpp:181
DataType data() const
Returns a raw data representation of the underlying packet.
Definition: packet.hpp:113
uint64_t receiveTimestamp() const
Returns the server's time at which the packet arrived from the client.
Definition: packet.hpp:223
uint8_t stratum() const
Returns an unsigned integer representing the level of the server in the NTP hierarchy.
Definition: packet.hpp:175
uint32_t rootDelay() const
Returns the total round-trip delay to the reference clock, in NTP short format.
Definition: packet.hpp:193