mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-08 16:11:18 +00:00
Publish mongoose src and tests
CL: Mongoose Web Server: Publish sources and tests Resolves https://github.com/cesanta/mongoose/issues/745 PUBLISHED_FROM=7ecd7a3c518cfa614a6ba0838678dcb91b75a8c0
This commit is contained in:
1 parent
0ab1c7ef76
commit
8742fac5d8
94 files changed
+24967
No files matched your search
+288
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Cesanta Software Limited
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#include "mongoose/src/internal.h"
|
||||
#include "mongoose/src/sntp.h"
|
||||
#include "mongoose/src/util.h"
|
||||
|
||||
#if MG_ENABLE_SNTP
|
||||
|
||||
#define SNTP_TIME_OFFSET 2208988800
|
||||
|
||||
#ifndef SNTP_TIMEOUT
|
||||
#define SNTP_TIMEOUT 10
|
||||
#endif
|
||||
|
||||
#ifndef SNTP_ATTEMPTS
|
||||
#define SNTP_ATTEMPTS 3
|
||||
#endif
|
||||
|
||||
static uint64_t mg_get_sec(uint64_t val) {
|
||||
return (val & 0xFFFFFFFF00000000) >> 32;
|
||||
}
|
||||
|
||||
static uint64_t mg_get_usec(uint64_t val) {
|
||||
uint64_t tmp = (val & 0x00000000FFFFFFFF);
|
||||
tmp *= 1000000;
|
||||
tmp >>= 32;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void mg_ntp_to_tv(uint64_t val, struct timeval *tv) {
|
||||
uint64_t tmp;
|
||||
tmp = mg_get_sec(val);
|
||||
tmp -= SNTP_TIME_OFFSET;
|
||||
tv->tv_sec = tmp;
|
||||
tv->tv_usec = mg_get_usec(val);
|
||||
}
|
||||
|
||||
static void mg_get_ntp_ts(const char *ntp, uint64_t *val) {
|
||||
uint32_t tmp;
|
||||
memcpy(&tmp, ntp, sizeof(tmp));
|
||||
tmp = ntohl(tmp);
|
||||
*val = (uint64_t) tmp << 32;
|
||||
memcpy(&tmp, ntp + 4, sizeof(tmp));
|
||||
tmp = ntohl(tmp);
|
||||
*val |= tmp;
|
||||
}
|
||||
|
||||
void mg_sntp_send_request(struct mg_connection *c) {
|
||||
uint8_t buf[48] = {0};
|
||||
/*
|
||||
* header - 8 bit:
|
||||
* LI (2 bit) - 3 (not in sync), VN (3 bit) - 4 (version),
|
||||
* mode (3 bit) - 3 (client)
|
||||
*/
|
||||
buf[0] = (3 << 6) | (4 << 3) | 3;
|
||||
|
||||
/*
|
||||
* Next fields should be empty in client request
|
||||
* stratum, 8 bit
|
||||
* poll interval, 8 bit
|
||||
* rrecision, 8 bit
|
||||
* root delay, 32 bit
|
||||
* root dispersion, 32 bit
|
||||
* ref id, 32 bit
|
||||
* ref timestamp, 64 bit
|
||||
* originate Timestamp, 64 bit
|
||||
* receive Timestamp, 64 bit
|
||||
*/
|
||||
|
||||
/*
|
||||
* convert time to sntp format (sntp starts from 00:00:00 01.01.1900)
|
||||
* according to rfc868 it is 2208988800L sec
|
||||
* this information is used to correct roundtrip delay
|
||||
* but if local clock is absolutely broken (and doesn't work even
|
||||
* as simple timer), it is better to disable it
|
||||
*/
|
||||
#ifndef MG_SNTP_NO_DELAY_CORRECTION
|
||||
uint32_t sec;
|
||||
sec = htonl((uint32_t)(mg_time() + SNTP_TIME_OFFSET));
|
||||
memcpy(&buf[40], &sec, sizeof(sec));
|
||||
#endif
|
||||
|
||||
mg_send(c, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
#ifndef MG_SNTP_NO_DELAY_CORRECTION
|
||||
static uint64_t mg_calculate_delay(uint64_t t1, uint64_t t2, uint64_t t3) {
|
||||
/* roundloop delay = (T4 - T1) - (T3 - T2) */
|
||||
uint64_t d1 = ((mg_time() + SNTP_TIME_OFFSET) * 1000000) -
|
||||
(mg_get_sec(t1) * 1000000 + mg_get_usec(t1));
|
||||
uint64_t d2 = (mg_get_sec(t3) * 1000000 + mg_get_usec(t3)) -
|
||||
(mg_get_sec(t2) * 1000000 + mg_get_usec(t2));
|
||||
|
||||
return (d1 > d2) ? d1 - d2 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
MG_INTERNAL int mg_sntp_parse_reply(const char *buf, int len,
|
||||
struct mg_sntp_message *msg) {
|
||||
uint8_t hdr;
|
||||
uint64_t trsm_ts_T3, delay = 0;
|
||||
int mode;
|
||||
struct timeval tv;
|
||||
|
||||
if (len < 48) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = buf[0];
|
||||
|
||||
if ((hdr & 0x38) >> 3 != 4) {
|
||||
/* Wrong version */
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode = hdr & 0x7;
|
||||
if (mode != 4 && mode != 5) {
|
||||
/* Not a server reply */
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
msg->kiss_of_death = (buf[1] == 0); /* Server asks to not send requests */
|
||||
|
||||
mg_get_ntp_ts(&buf[40], &trsm_ts_T3);
|
||||
|
||||
#ifndef MG_SNTP_NO_DELAY_CORRECTION
|
||||
{
|
||||
uint64_t orig_ts_T1, recv_ts_T2;
|
||||
mg_get_ntp_ts(&buf[24], &orig_ts_T1);
|
||||
mg_get_ntp_ts(&buf[32], &recv_ts_T2);
|
||||
delay = mg_calculate_delay(orig_ts_T1, recv_ts_T2, trsm_ts_T3);
|
||||
}
|
||||
#endif
|
||||
|
||||
mg_ntp_to_tv(trsm_ts_T3, &tv);
|
||||
|
||||
msg->time = (double) tv.tv_sec + (((double) tv.tv_usec + delay) / 1000000.0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mg_sntp_handler(struct mg_connection *c, int ev,
|
||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
||||
struct mbuf *io = &c->recv_mbuf;
|
||||
struct mg_sntp_message msg;
|
||||
|
||||
c->handler(c, ev, ev_data MG_UD_ARG(user_data));
|
||||
|
||||
switch (ev) {
|
||||
case MG_EV_RECV: {
|
||||
if (mg_sntp_parse_reply(io->buf, io->len, &msg) < 0) {
|
||||
DBG(("Invalid SNTP packet received (%d)", (int) io->len));
|
||||
c->handler(c, MG_SNTP_MALFORMED_REPLY, NULL MG_UD_ARG(user_data));
|
||||
} else {
|
||||
c->handler(c, MG_SNTP_REPLY, (void *) &msg MG_UD_ARG(user_data));
|
||||
}
|
||||
|
||||
mbuf_remove(io, io->len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mg_set_protocol_sntp(struct mg_connection *c) {
|
||||
if ((c->flags & MG_F_UDP) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->proto_handler = mg_sntp_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr,
|
||||
MG_CB(mg_event_handler_t event_handler,
|
||||
void *user_data),
|
||||
const char *sntp_server_name) {
|
||||
struct mg_connection *c = NULL;
|
||||
char url[100], *p_url = url;
|
||||
const char *proto = "", *port = "", *tmp;
|
||||
|
||||
/* If port is not specified, use default (123) */
|
||||
tmp = strchr(sntp_server_name, ':');
|
||||
if (tmp != NULL && *(tmp + 1) == '/') {
|
||||
tmp = strchr(tmp + 1, ':');
|
||||
}
|
||||
|
||||
if (tmp == NULL) {
|
||||
port = ":123";
|
||||
}
|
||||
|
||||
/* Add udp:// if needed */
|
||||
if (strncmp(sntp_server_name, "udp://", 6) != 0) {
|
||||
proto = "udp://";
|
||||
}
|
||||
|
||||
mg_asprintf(&p_url, sizeof(url), "%s%s%s", proto, sntp_server_name, port);
|
||||
|
||||
c = mg_connect(mgr, p_url, event_handler MG_UD_ARG(user_data));
|
||||
|
||||
if (c == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mg_set_protocol_sntp(c);
|
||||
|
||||
cleanup:
|
||||
if (p_url != url) {
|
||||
MG_FREE(p_url);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct sntp_data {
|
||||
mg_event_handler_t hander;
|
||||
int count;
|
||||
};
|
||||
|
||||
static void mg_sntp_util_ev_handler(struct mg_connection *c, int ev,
|
||||
void *ev_data MG_UD_ARG(void *user_data)) {
|
||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
||||
void *user_data = c->user_data;
|
||||
#endif
|
||||
struct sntp_data *sd = (struct sntp_data *) user_data;
|
||||
|
||||
switch (ev) {
|
||||
case MG_EV_CONNECT:
|
||||
if (*(int *) ev_data != 0) {
|
||||
mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case MG_EV_TIMER:
|
||||
if (sd->count <= SNTP_ATTEMPTS) {
|
||||
mg_sntp_send_request(c);
|
||||
mg_set_timer(c, mg_time() + 10);
|
||||
sd->count++;
|
||||
} else {
|
||||
mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
|
||||
c->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
}
|
||||
break;
|
||||
case MG_SNTP_MALFORMED_REPLY:
|
||||
mg_call(c, sd->hander, c->user_data, MG_SNTP_FAILED, NULL);
|
||||
c->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
break;
|
||||
case MG_SNTP_REPLY:
|
||||
mg_call(c, sd->hander, c->user_data, MG_SNTP_REPLY, ev_data);
|
||||
c->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
break;
|
||||
case MG_EV_CLOSE:
|
||||
MG_FREE(user_data);
|
||||
c->user_data = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
|
||||
mg_event_handler_t event_handler,
|
||||
const char *sntp_server_name) {
|
||||
struct mg_connection *c;
|
||||
struct sntp_data *sd = (struct sntp_data *) MG_CALLOC(1, sizeof(*sd));
|
||||
if (sd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = mg_sntp_connect(mgr, MG_CB(mg_sntp_util_ev_handler, sd),
|
||||
sntp_server_name);
|
||||
if (c == NULL) {
|
||||
MG_FREE(sd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sd->hander = event_handler;
|
||||
#if !MG_ENABLE_CALLBACK_USERDATA
|
||||
c->user_data = sd;
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif /* MG_ENABLE_SNTP */
|
||||
Reference in new issue
Block a user