Fix #1600 - more precise SNTP time calculation

This commit is contained in:
cpq committed 2022-08-09 12:13:23 +01:00
1 parent 2279a51d52
commit b7406357c5
3 files changed
+49 -42

No files matched your search

+20 -6
View File
@@ -3912,8 +3912,14 @@ void mg_sha1_final(unsigned char digest[20], mg_sha1_ctx *context) {
#define SNTP_INTERVAL_SEC 3600
#define SNTP_TIME_OFFSET 2208988800UL
#define SNTP_TIME_OFFSET 2208988800UL // (1970 - 1900) in seconds
#define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1
static int64_t gettimestamp(const uint32_t *data) {
uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]);
if (sec) sec -= SNTP_TIME_OFFSET;
return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0);
}
int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
int64_t res = -1;
@@ -3926,10 +3932,14 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
} else if (buf[1] == 0) {
MG_ERROR(("%s", "server sent a kiss of death"));
} else if (version == 4 || version == 3) {
uint32_t *data = (uint32_t *) &buf[40];
unsigned long seconds = mg_ntohl(data[0]) - SNTP_TIME_OFFSET;
unsigned long fracseconds = mg_ntohl(data[1]);
res = ((int64_t) seconds) * 1000 + (((int64_t) (fracseconds) * 1000) >> 32);
// int64_t ref = gettimestamp((uint32_t *) &buf[16]);
int64_t t0 = gettimestamp((uint32_t *) &buf[24]);
int64_t t1 = gettimestamp((uint32_t *) &buf[32]);
int64_t t2 = gettimestamp((uint32_t *) &buf[40]);
int64_t t3 = (int64_t) mg_millis();
int64_t delta = (t3 - t0) - (t2 - t1);
MG_DEBUG(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta));
res = t2 + delta / 2;
} else {
MG_ERROR(("unexpected version: %d", version));
}
@@ -3957,8 +3967,12 @@ void mg_sntp_request(struct mg_connection *c) {
if (c->is_resolving) {
MG_ERROR(("%lu wait until resolved", c->id));
} else {
uint64_t now = mg_millis();
uint8_t buf[48] = {0};
uint32_t *t = (uint32_t *) &buf[40];
buf[0] = (0 << 6) | (4 << 3) | 3;
t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET);
t[1] = mg_htonl((uint32_t) ((now % 1000) / 1000.0 * SNTP_MAX_FRAC));
mg_send(c, buf, sizeof(buf));
}
}
+20 -6
View File
@@ -4,8 +4,14 @@
#include "log.h"
#include "util.h"
#define SNTP_INTERVAL_SEC 3600
#define SNTP_TIME_OFFSET 2208988800UL
#define SNTP_TIME_OFFSET 2208988800UL // (1970 - 1900) in seconds
#define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1
static int64_t gettimestamp(const uint32_t *data) {
uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]);
if (sec) sec -= SNTP_TIME_OFFSET;
return ((int64_t) sec) * 1000 + (int64_t) (frac / SNTP_MAX_FRAC * 1000.0);
}
int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
int64_t res = -1;
@@ -18,10 +24,14 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len) {
} else if (buf[1] == 0) {
MG_ERROR(("%s", "server sent a kiss of death"));
} else if (version == 4 || version == 3) {
uint32_t *data = (uint32_t *) &buf[40];
unsigned long seconds = mg_ntohl(data[0]) - SNTP_TIME_OFFSET;
unsigned long fracseconds = mg_ntohl(data[1]);
res = ((int64_t) seconds) * 1000 + (((int64_t) (fracseconds) * 1000) >> 32);
// int64_t ref = gettimestamp((uint32_t *) &buf[16]);
int64_t t0 = gettimestamp((uint32_t *) &buf[24]);
int64_t t1 = gettimestamp((uint32_t *) &buf[32]);
int64_t t2 = gettimestamp((uint32_t *) &buf[40]);
int64_t t3 = (int64_t) mg_millis();
int64_t delta = (t3 - t0) - (t2 - t1);
MG_DEBUG(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta));
res = t2 + delta / 2;
} else {
MG_ERROR(("unexpected version: %d", version));
}
@@ -49,8 +59,12 @@ void mg_sntp_request(struct mg_connection *c) {
if (c->is_resolving) {
MG_ERROR(("%lu wait until resolved", c->id));
} else {
uint64_t now = mg_millis();
uint8_t buf[48] = {0};
uint32_t *t = (uint32_t *) &buf[40];
buf[0] = (0 << 6) | (4 << 3) | 3;
t[0] = mg_htonl((uint32_t) (now / 1000) + SNTP_TIME_OFFSET);
t[1] = mg_htonl((uint32_t) ((now % 1000) / 1000.0 * SNTP_MAX_FRAC));
mg_send(c, buf, sizeof(buf));
}
}
+9 -30
View File
@@ -299,7 +299,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
int64_t ms = (int64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
int64_t diff = ms > received ? ms - received : received - ms;
MG_DEBUG(("diff: %lld", diff));
// ASSERT(diff < 100); // The diff should be less than 300 ms
ASSERT(diff < 100);
#endif
} else if (ev == MG_EV_OPEN) {
c->is_hexdumping = 1;
@@ -324,39 +324,18 @@ static void test_sntp_server(const char *url) {
}
static void test_sntp(void) {
const unsigned char bad[] =
"\x55\x02\x00\xeb\x00\x00\x00\x1e\x00\x00\x07\xb6\x3e\xc9\xd6\xa2"
"\xdb\xde\xea\x30\x91\x86\xb7\x10\xdb\xde\xed\x98\x00\x00\x00\xde"
"\xdb\xde\xed\x99\x0a\xe2\xc7\x96\xdb\xde\xed\x99\x0a\xe4\x6b\xda";
ASSERT(mg_sntp_parse(bad, sizeof(bad)) < 0);
ASSERT(mg_sntp_parse(NULL, 0) == -1);
test_sntp_server("udp://time.windows.com:123");
// NOTE(cpq): temporarily disabled until Github Actions fix their NTP
// port blockage issue, https://github.com/actions/runner-images/issues/5615
// test_sntp_server("udp://time.apple.com:123");
// test_sntp_server(NULL);
{
int64_t ms;
const unsigned char sntp_good[] =
"\x24\x02\x00\xeb\x00\x00\x00\x1e\x00\x00\x07\xb6\x3e"
"\xc9\xd6\xa2\xdb\xde\xea\x30\x91\x86\xb7\x10\xdb\xde"
"\xed\x98\x00\x00\x00\xde\xdb\xde\xed\x99\x0a\xe2\xc7"
"\x96\xdb\xde\xed\x99\x0a\xe4\x6b\xda";
const unsigned char bad_good[] =
"\x55\x02\x00\xeb\x00\x00\x00\x1e\x00\x00\x07\xb6\x3e"
"\xc9\xd6\xa2\xdb\xde\xea\x30\x91\x86\xb7\x10\xdb\xde"
"\xed\x98\x00\x00\x00\xde\xdb\xde\xed\x99\x0a\xe2\xc7"
"\x96\xdb\xde\xed\x99\x0a\xe4\x6b\xda";
ASSERT((ms = mg_sntp_parse(sntp_good, sizeof(sntp_good))) > 0);
#if MG_ARCH == MG_ARCH_UNIX
time_t t = (time_t) (ms / 1000);
struct tm tm;
gmtime_r(&t, &tm);
ASSERT(tm.tm_year == 116);
ASSERT(tm.tm_mon == 10);
ASSERT(tm.tm_mday == 22);
ASSERT(tm.tm_hour == 16);
ASSERT(tm.tm_min == 15);
ASSERT(tm.tm_sec == 21);
#endif
ASSERT(mg_sntp_parse(bad_good, sizeof(bad_good)) < 0);
}
ASSERT(mg_sntp_parse(NULL, 0) == -1);
}
struct mqtt_data {