diff --git a/lib/context.c b/lib/context.c index fb27fd68..57ad8b5c 100644 --- a/lib/context.c +++ b/lib/context.c @@ -1443,6 +1443,13 @@ lws_vhost_destroy1(struct lws_vhost *vh) } } + /* + * destroy any pending timed events + */ + + while (vh->timed_vh_protocol_list) + lws_timed_callback_remove(vh, vh->timed_vh_protocol_list); + /* * let the protocols destroy the per-vhost protocol objects */ diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index fc7e3579..15143562 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -235,6 +235,42 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) lws_remove_from_timeout_list(wsi); } +int +lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p) +{ + lws_start_foreach_llp(struct lws_timed_vh_protocol **, pt, + vh->timed_vh_protocol_list) { + if (*pt == p) { + *pt = p->next; + lws_free(p); + + return 0; + } + } lws_end_foreach_llp(pt, next); + + return 1; +} + +LWS_VISIBLE LWS_EXTERN int +lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols *prot, + int reason, int secs) +{ + struct lws_timed_vh_protocol *p = (struct lws_timed_vh_protocol *) + lws_malloc(sizeof(*p), "timed_vh"); + + if (!p) + return 1; + + p->protocol = prot; + p->reason = reason; + p->time = lws_now_secs() + secs; + p->next = vh->timed_vh_protocol_list; + + vh->timed_vh_protocol_list = p; + + return 0; +} + static void lws_remove_child_from_any_parent(struct lws *wsi) { @@ -1197,6 +1233,29 @@ lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len) return 0; } +LWS_VISIBLE LWS_EXTERN int +lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in, + size_t len) +{ + int n; + struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi"); + + wsi->context = vh->context; + wsi->vhost = vh; + + for (n = 0; n < wsi->vhost->count_protocols; n++) { + wsi->protocol = &vh->protocols[n]; + if (wsi->protocol->callback(wsi, reason, NULL, in, len)) { + lws_free(wsi); + return 1; + } + } + + lws_free(wsi); + + return 0; +} + LWS_VISIBLE LWS_EXTERN void lws_set_fops(struct lws_context *context, const struct lws_plat_file_ops *fops) { diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index f7975363..6c0e4439 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -4426,6 +4426,26 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs); LWS_VISIBLE LWS_EXTERN void lws_set_timer(struct lws *wsi, int secs); +/* + * lws_timed_callback_vh_protocol() - calls back a protocol on a vhost after + * the specified delay + * + * \param vh: the vhost to call back + * \param protocol: the protocol to call back + * \param reason: callback reason + * \param secs: how many seconds in the future to do the callback. Set to + * -1 to cancel the timer callback. + * + * Callback the specified protocol with a fake wsi pointing to the specified + * vhost and protocol, with the specified reason, at the specified time in the + * future. + * + * Returns 0 if OK. + */ +LWS_VISIBLE LWS_EXTERN int +lws_timed_callback_vh_protocol(struct lws_vhost *vh, + const struct lws_protocols *prot, + int reason, int secs); ///@} /*! \defgroup sending-data Sending data @@ -4750,9 +4770,31 @@ lws_callback_all_protocol_vhost_args(struct lws_vhost *vh, * - Which: connections using this protocol on same VHOST as wsi ONLY * - When: now * - What: reason + * + * This is deprecated since v2.5, use lws_callback_vhost_protocols_vhost() + * which takes the pointer to the vhost directly without using or needing the + * wsi. */ LWS_VISIBLE LWS_EXTERN int -lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len); +lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len) +LWS_WARN_DEPRECATED; + +/** + * lws_callback_vhost_protocols_vhost() - Callback all protocols enabled on a vhost + * with the given reason + * + * \param vh: vhost that will get callbacks + * \param reason: Callback reason index + * \param in: in argument to callback + * \param len: len argument to callback + * + * - Which: connections using this protocol on same VHOST as wsi ONLY + * - When: now + * - What: reason + */ +LWS_VISIBLE LWS_EXTERN int +lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in, + size_t len); LWS_VISIBLE LWS_EXTERN int lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index e4764995..307e2838 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -898,6 +898,13 @@ struct http2_settings { uint32_t s[H2SET_COUNT]; }; +struct lws_timed_vh_protocol { + struct lws_timed_vh_protocol *next; + const struct lws_protocols *protocol; + time_t time; + int reason; +}; + /* * virtual host -related context information * vhostwide SSL context @@ -958,6 +965,7 @@ struct lws_vhost { #ifndef LWS_NO_EXTENSIONS const struct lws_extension *extensions; #endif + struct lws_timed_vh_protocol *timed_vh_protocol_list; void *user; int listen_port; @@ -2048,6 +2056,9 @@ lws_b64_selftest(void); LWS_EXTERN int lws_service_flag_pending(struct lws_context *context, int tsi); +LWS_EXTERN int +lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p); + #if defined(_WIN32) LWS_EXTERN struct lws * wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd); diff --git a/lib/service.c b/lib/service.c index 5b9c4206..68cbbad9 100644 --- a/lib/service.c +++ b/lib/service.c @@ -1176,6 +1176,35 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, lwsl_notice("load: %s\n", s); } #endif + /* + * Phase 4: vhost / protocol timer callbacks + */ + + wsi = NULL; + lws_start_foreach_ll(struct lws_vhost *, v, + context->vhost_list) { + struct lws_timed_vh_protocol *nx; + if (v->timed_vh_protocol_list) { + lws_start_foreach_ll(struct lws_timed_vh_protocol *, + q, v->timed_vh_protocol_list) { + if (now >= q->time) { + if (!wsi) + wsi = lws_zalloc(sizeof(*wsi), "cbwsi"); + wsi->context = context; + wsi->vhost = v; + wsi->protocol = q->protocol; + lwsl_notice("timed cb: vh %s, protocol %s, reason %d\n", v->name, q->protocol->name, q->reason); + q->protocol->callback(wsi, q->reason, NULL, NULL, 0); + nx = q->next; + lws_timed_callback_remove(v, q); + q = nx; + continue; /* we pointed ourselves to the next from the now-deleted guy */ + } + } lws_end_foreach_ll(q, next); + } + } lws_end_foreach_ll(v, vhost_next); + if (wsi) + lws_free(wsi); } /*