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

lws_set_timer

This adds a new api lws_set_timer(wsi, secs), which schedules
a callback LWS_CALLBACK_TIMER secs seconds into the future.

The timer can be continuously deferred by calling lws_set_timer()
again before it expires.

Calling lws_set_timer(wsi, -1) cancels any pending timer.
This commit is contained in:
Andy Green 2017-12-05 20:02:29 +08:00
parent 8487279e64
commit 7d59122b5f
6 changed files with 125 additions and 15 deletions

View file

@ -131,6 +131,12 @@ lws_free_wsi(struct lws *wsi)
lws_free(wsi);
}
int
lws_should_be_on_timeout_list(struct lws *wsi)
{
return wsi->timer_active || wsi->pending_timeout;
}
void
lws_remove_from_timeout_list(struct lws *wsi)
{
@ -149,9 +155,55 @@ lws_remove_from_timeout_list(struct lws *wsi)
/* we're out of the list, we should not point anywhere any more */
wsi->timeout_list_prev = NULL;
wsi->timeout_list = NULL;
lws_pt_unlock(pt);
}
static void
lws_add_to_timeout_list(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (wsi->timeout_list_prev)
return;
/* our next guy is current first guy */
wsi->timeout_list = pt->timeout_list;
/* if there is a next guy, set his prev ptr to our next ptr */
if (wsi->timeout_list)
wsi->timeout_list->timeout_list_prev = &wsi->timeout_list;
/* our prev ptr is first ptr */
wsi->timeout_list_prev = &pt->timeout_list;
/* set the first guy to be us */
*wsi->timeout_list_prev = wsi;
}
LWS_VISIBLE void
lws_set_timer(struct lws *wsi, int secs)
{
time_t now;
if (secs < 0) {
wsi->timer_active = 0;
if (!lws_should_be_on_timeout_list(wsi))
lws_remove_from_timeout_list(wsi);
return;
}
time(&now);
wsi->pending_timer_limit = secs;
wsi->pending_timer_set = now;
if (!wsi->timer_active) {
wsi->timer_active = 1;
if (!wsi->pending_timeout)
lws_add_to_timeout_list(wsi);
}
}
LWS_VISIBLE void
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
{
@ -169,17 +221,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
time(&now);
if (reason && !wsi->timeout_list_prev) {
/* our next guy is current first guy */
wsi->timeout_list = pt->timeout_list;
/* if there is a next guy, set his prev ptr to our next ptr */
if (wsi->timeout_list)
wsi->timeout_list->timeout_list_prev = &wsi->timeout_list;
/* our prev ptr is first ptr */
wsi->timeout_list_prev = &pt->timeout_list;
/* set the first guy to be us */
*wsi->timeout_list_prev = wsi;
}
if (reason)
lws_add_to_timeout_list(wsi);
lwsl_debug("%s: %p: %d secs\n", __func__, wsi, secs);
wsi->pending_timeout_limit = secs;
@ -188,7 +231,7 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
lws_pt_unlock(pt);
if (!reason)
if (!reason && !lws_should_be_on_timeout_list(wsi))
lws_remove_from_timeout_list(wsi);
}

View file

@ -1354,6 +1354,12 @@ enum lws_callback_reasons {
* protocol wants to take some action with this information.
* \p in is the lws_vhost and \p len is the number of days left
* before it expires, as a (ssize_t) */
LWS_CALLBACK_TIMER = 73,
/**< When the time elapsed after a call to lws_set_timer(wsi, secs)
* is up, the wsi will get one of these callbacks. The deadline
* can be continuously extended into the future by later calls
* to lws_set_timer() before the deadline expires, or cancelled by
* lws_set_timer(wsi, -1); */
/****** add new things just above ---^ ******/
@ -4404,6 +4410,22 @@ enum pending_timeout {
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
/**
* lws_set_timer() - schedules a callback on the wsi in the future
*
* \param wsi: Websocket connection instance
* \param secs: -1 removes any existing scheduled callback, otherwise the
* number of seconds in the future the callback will occur at.
*
* When the deadline expires, the wsi will get a callback of type
* LWS_CALLBACK_TIMER and the timer is exhausted. The deadline may be
* continuously deferred by further calls to lws_set_timer() with a later
* deadline, or cancelled by lws_set_timer(wsi, -1)
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timer(struct lws *wsi, int secs);
///@}
/*! \defgroup sending-data Sending data

View file

@ -1831,6 +1831,7 @@ struct lws {
#endif
const struct lws_protocols *protocol;
struct lws **same_vh_protocol_prev, *same_vh_protocol_next;
/* we get on the list if either the timeout or the timer is valid */
struct lws *timeout_list;
struct lws **timeout_list_prev;
#if defined(LWS_WITH_PEER_LIMITS)
@ -1873,6 +1874,7 @@ struct lws {
#endif
#endif
time_t pending_timeout_set;
time_t pending_timer_set;
/* ints */
int position_in_fds_table;
@ -1915,6 +1917,8 @@ struct lws {
unsigned int rxflow_will_be_applied:1;
unsigned int event_pipe:1;
unsigned int timer_active:1;
#ifdef LWS_WITH_ACCESS_LOG
unsigned int access_log_pending:1;
#endif
@ -1944,6 +1948,7 @@ struct lws {
unsigned short c_port;
#endif
unsigned short pending_timeout_limit;
unsigned short pending_timer_limit;
uint8_t state; /* enum lws_connection_states */
uint8_t mode; /* enum connection_mode */
@ -2002,6 +2007,9 @@ remove_wsi_socket_from_fds(struct lws *wsi);
LWS_EXTERN int
lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
LWS_EXTERN int
lws_should_be_on_timeout_list(struct lws *wsi);
#ifndef LWS_LATENCY
static inline void
lws_latency(struct lws_context *context, struct lws *wsi, const char *action,

View file

@ -579,14 +579,36 @@ lws_service_timeout_check(struct lws *wsi, time_t sec)
if (lws_ext_cb_active(wsi, LWS_EXT_CB_1HZ, NULL, sec) < 0)
return 0;
if (!wsi->pending_timeout)
return 0;
/*
* is there a timer callback we should be doing?
*/
if (wsi->timer_active &&
lws_compare_time_t(wsi->context, sec, wsi->pending_timer_set) >
wsi->pending_timer_limit) {
wsi->timer_active = 0;
if (wsi->protocol &&
wsi->protocol->callback(wsi, LWS_CALLBACK_TIMER,
wsi->user_space, NULL, 0)) {
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 1;
}
if (!lws_should_be_on_timeout_list(wsi)) {
lws_remove_from_timeout_list(wsi);
return 0;
}
}
/*
* if we went beyond the allowed time, kill the
* connection
*/
if (lws_compare_time_t(wsi->context, sec, wsi->pending_timeout_set) >
if (wsi->pending_timeout &&
lws_compare_time_t(wsi->context, sec, wsi->pending_timeout_set) >
wsi->pending_timeout_limit) {
if (wsi->desc.sockfd != LWS_SOCK_INVALID &&

View file

@ -91,6 +91,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_ESTABLISHED:
pss->number = 0;
/* just to test the timer api */
// lws_set_timer(wsi, 3);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
@ -115,6 +117,11 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
}
break;
case LWS_CALLBACK_TIMER:
lwsl_notice("%s: LWS_CALLBACK_TIMER\n", __func__);
lws_set_timer(wsi, 3);
break;
default:
break;
}

View file

@ -35,6 +35,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_ESTABLISHED:
pss->number = 0;
/* just to test the timer api */
lws_set_timer(wsi, 3);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
@ -62,6 +64,12 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
return -1;
}
break;
case LWS_CALLBACK_TIMER:
lwsl_notice("%s: LWS_CALLBACK_TIMER\n", __func__);
lws_set_timer(wsi, 3);
break;
/*
* this just demonstrates how to use the protocol filter. If you won't
* study and reject connections based on header content, you don't need