mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-17 10:49:47 +00:00
Fix #1600 - more precise SNTP time calculation
This commit is contained in:
1 parent
2279a51d52
commit
b7406357c5
3 files changed
+49
-42
No files matched your search
+20
-6
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user