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:
parent
e1cdb1f328
commit
f6de7465ec
6 changed files with 75 additions and 13 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue