1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

lws_compare_time_t: conceal time discontiguities on all platforms

This provides platform-independent support for time discontiguities.

On embedded without battery RTC, commonly we only get time after
NTP completes.  This makes the cert checking happen when we have
a reasonable time and introduces lws_compare_time_t() to correctly
compare time_t s that may sit on either side of a time discontiguity.
This commit is contained in:
Andy Green 2017-11-24 11:00:59 +08:00
parent e1cdb1f328
commit f6de7465ec
6 changed files with 75 additions and 13 deletions

View file

@ -1578,7 +1578,8 @@ lws_check_deferred_free(struct lws_context *context, int force)
lws_start_foreach_llp(struct lws_deferred_free **, pdf,
context->deferred_free_list) {
if (now > (*pdf)->deadline || force) {
if (force ||
lws_compare_time_t(context, now, (*pdf)->deadline) > 5) {
df = *pdf;
*pdf = df->next;
/* finalize vh destruction */
@ -1605,7 +1606,7 @@ lws_vhost_destroy(struct lws_vhost *vh)
/* part 2 is deferred to allow all the handle closes to complete */
df->next = vh->context->deferred_free_list;
df->deadline = lws_now_secs() + 5;
df->deadline = lws_now_secs();
df->payload = vh;
vh->context->deferred_free_list = df;
}

View file

@ -182,7 +182,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
}
lwsl_debug("%s: %p: %d secs\n", __func__, wsi, secs);
wsi->pending_timeout_limit = now + secs;
wsi->pending_timeout_limit = secs;
wsi->pending_timeout_set = now;
wsi->pending_timeout = reason;
lws_pt_unlock(pt);
@ -1295,6 +1296,18 @@ lws_now_secs(void)
return tv.tv_sec;
}
LWS_VISIBLE LWS_EXTERN int
lws_compare_time_t(struct lws_context *context, time_t t1, time_t t2)
{
if (t1 < context->time_discontiguity)
t1 += context->time_fixup;
if (t2 < context->time_discontiguity)
t2 += context->time_fixup;
return (int)(t1 - t2);
}
#if LWS_POSIX
@ -2423,8 +2436,7 @@ lws_restart_ws_ping_pong_timer(struct lws *wsi)
if (!lws_state_is_ws(wsi->state))
return;
wsi->ws->time_next_ping_check = (time_t)lws_now_secs() +
wsi->context->ws_ping_pong_interval;
wsi->ws->time_next_ping_check = (time_t)lws_now_secs();
}
static const char *hex = "0123456789ABCDEF";

View file

@ -5286,6 +5286,26 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
LWS_VISIBLE LWS_EXTERN unsigned long
lws_now_secs(void);
/**
* lws_compare_time_t(): return relationship between two time_t
*
* \param context: struct lws_context
* \param t1: time_t 1
* \param t2: time_t 2
*
* returns <0 if t2 > t1; >0 if t1 > t2; or == 0 if t1 == t2.
*
* This is aware of clock discontiguities that may have affected either t1 or
* t2 and adapts the comparison for them.
*
* For the discontiguity detection to work, you must avoid any arithmetic on
* the times being compared. For example to have a timeout that triggers
* 15s from when it was set, store the time it was set and compare like
* `if (lws_compare_time_t(context, now, set_time) > 15)`
*/
LWS_VISIBLE LWS_EXTERN int
lws_compare_time_t(struct lws_context *context, time_t t1, time_t t2);
/**
* lws_get_context - Allow getting lws_context from a Websocket connection
* instance

View file

@ -1130,6 +1130,8 @@ struct lws_context {
time_t last_ws_ping_pong_check_s;
time_t last_cert_check_s;
time_t time_up;
time_t time_discontiguity;
time_t time_fixup;
const struct lws_plat_file_ops *fops;
struct lws_plat_file_ops fops_platform;
#if defined(LWS_WITH_HTTP2)
@ -1974,7 +1976,7 @@ struct lws {
uint64_t accept_start_us;
#endif
#endif
time_t pending_timeout_limit;
time_t pending_timeout_set;
/* ints */
int position_in_fds_table;
@ -2049,6 +2051,8 @@ struct lws {
#ifndef LWS_NO_CLIENT
unsigned short c_port;
#endif
unsigned short pending_timeout_limit;
uint8_t state; /* enum lws_connection_states */
uint8_t mode; /* enum connection_mode */
@ -2167,7 +2171,7 @@ lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_service_timeout_check(struct lws *wsi, unsigned int sec);
lws_service_timeout_check(struct lws *wsi, time_t sec);
LWS_EXTERN void
lws_remove_from_timeout_list(struct lws *wsi);

View file

@ -565,7 +565,7 @@ bail_die:
}
int
lws_service_timeout_check(struct lws *wsi, unsigned int sec)
lws_service_timeout_check(struct lws *wsi, time_t sec)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int n = 0;
@ -586,7 +586,8 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
* if we went beyond the allowed time, kill the
* connection
*/
if ((time_t)sec > wsi->pending_timeout_limit) {
if (lws_compare_time_t(wsi->context, sec, wsi->pending_timeout_set) >
wsi->pending_timeout_limit) {
if (wsi->desc.sockfd != LWS_SOCK_INVALID &&
wsi->position_in_fds_table >= 0)
@ -993,8 +994,31 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
if (context->time_up < 1464083026 && now > 1464083026)
context->time_up = now;
/* TODO: if using libev, we should probably use timeout watchers... */
if (context->last_timeout_check_s != now) {
if (context->last_timeout_check_s &&
now - context->last_timeout_check_s > 100) {
/*
* There has been a discontiguity. Any stored time that is
* less than context->time_discontiguity should have context->
* time_fixup added to it.
*
* Some platforms with no RTC will experience this as a normal
* event when ntp sets their clock, but we can have started
* long before that with a 0-based unix time.
*/
context->time_discontiguity = now;
context->time_fixup = now - context->last_timeout_check_s;
lwsl_notice("time discontiguity: at old time %llus, "
"new time %llus: +%llus\n",
(unsigned long long)context->last_timeout_check_s,
(unsigned long long)context->time_discontiguity,
(unsigned long long)context->time_fixup);
context->last_timeout_check_s = now - 1;
}
if (lws_compare_time_t(context, context->last_timeout_check_s, now)) {
context->last_timeout_check_s = now;
#if defined(LWS_WITH_STATS)

View file

@ -235,7 +235,7 @@ lws_tls_check_cert_lifetime(struct lws_vhost *v)
n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO, &ir, 0);
if (n)
return -1;
return 1;
life = (ir.time - now) / (24 * 3600);
lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name, (int)life);
@ -254,7 +254,8 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context)
struct lws_vhost *v = context->vhost_list;
while (v) {
lws_tls_check_cert_lifetime(v);
if (lws_tls_check_cert_lifetime(v) < 0)
return -1;
v = v->vhost_next;
}