diff --git a/lib/core/context.c b/lib/core/context.c index 1a39b10ab..fad0b7d4e 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -1369,7 +1369,7 @@ __lws_vhost_destroy2(struct lws_vhost *vh) */ while (vh->timed_vh_protocol_list) - lws_timed_callback_remove(vh, 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/core/libwebsockets.c b/lib/core/libwebsockets.c index 0b2a0b5ac..28323fd58 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -120,8 +120,10 @@ lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi) { if (wsi->vhost == vh) return; + lws_context_lock(vh->context, __func__); /* ---------- context { */ wsi->vhost = vh; vh->count_bound_wsi++; + lws_context_unlock(vh->context); /* } context ---------- */ lwsl_info("%s: vh %s: count_bound_wsi %d\n", __func__, vh->name, vh->count_bound_wsi); assert(wsi->vhost->count_bound_wsi > 0); @@ -487,8 +489,10 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) lws_pt_unlock(pt); } +/* requires context + vh lock */ + int -lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p) +__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) { @@ -503,9 +507,30 @@ lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p) return 1; } +int +lws_pthread_self_to_tsi(struct lws_context *context) +{ +#if LWS_MAX_SMP > 1 + pthread_t ps = pthread_self(); + struct lws_context_per_thread *pt = &context->pt[0]; + int n; + + for (n = 0; n < context->count_threads; n++) { + if (pthread_equal(ps, pt->self)) + return n; + pt++; + } + + return -1; +#else + return 0; +#endif +} + LWS_VISIBLE LWS_EXTERN int -lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols *prot, - int reason, int secs) +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"); @@ -513,12 +538,22 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols if (!p) return 1; + p->tsi_req = lws_pthread_self_to_tsi(vh->context); + if (p->tsi_req < 0) /* not called from a service thread --> tsi 0 */ + p->tsi_req = 0; + + lws_context_lock(vh->context, __func__); /* context ----------------- */ + p->protocol = prot; p->reason = reason; p->time = lws_now_secs() + secs; - p->next = vh->timed_vh_protocol_list; + lws_vhost_lock(vh); /* vhost ---------------------------------------- */ + p->next = vh->timed_vh_protocol_list; vh->timed_vh_protocol_list = p; + lws_vhost_unlock(vh); /* -------------------------------------- vhost */ + + lws_context_unlock(vh->context); /* ------------------------- context */ return 0; } diff --git a/lib/core/private.h b/lib/core/private.h index 857366a6a..a5722b890 100644 --- a/lib/core/private.h +++ b/lib/core/private.h @@ -351,6 +351,7 @@ struct lws_context_per_thread { #if LWS_MAX_SMP > 1 pthread_mutex_t lock_stats; struct lws_mutex_refcount mr; + pthread_t self; #endif struct lws_context *context; @@ -445,6 +446,7 @@ struct lws_timed_vh_protocol { struct lws_vhost *vhost; /* only used for pending processing */ time_t time; int reason; + int tsi_req; }; /* @@ -1097,7 +1099,7 @@ 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); +__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p); LWS_EXTERN int LWS_WARN_UNUSED_RESULT __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi); @@ -1437,6 +1439,10 @@ LWS_EXTERN int lws_plat_service(struct lws_context *context, int timeout_ms); LWS_EXTERN LWS_VISIBLE int _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi); + +LWS_EXTERN int +lws_pthread_self_to_tsi(struct lws_context *context); + LWS_EXTERN int lws_plat_init(struct lws_context *context, const struct lws_context_creation_info *info); diff --git a/lib/core/service.c b/lib/core/service.c index 00258fa21..065756b15 100644 --- a/lib/core/service.c +++ b/lib/core/service.c @@ -658,7 +658,7 @@ lws_service_periodic_checks(struct lws_context *context, our_fd = pollfd->fd; /* - * Phase 1: check every wsi on the timeout check list + * Phase 1: check every wsi on our pt's timeout check list */ lws_pt_lock(pt, __func__); @@ -792,7 +792,7 @@ lws_service_periodic_checks(struct lws_context *context, lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *, q, v->timed_vh_protocol_list, next) { - if (now >= q->time) + if (now >= q->time && q->tsi_req == tsi) n++; } lws_end_foreach_ll_safe(q); } @@ -839,6 +839,8 @@ lws_service_periodic_checks(struct lws_context *context, if (v->timed_vh_protocol_list) { + lws_vhost_lock(v); /* vhost ------------------------- */ + lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *, q, v->timed_vh_protocol_list, next) { @@ -846,7 +848,7 @@ lws_service_periodic_checks(struct lws_context *context, if (m == n) break; - if (now >= q->time) { + if (now >= q->time && q->tsi_req == tsi) { /* * tmr is an allocated array. @@ -858,10 +860,12 @@ lws_service_periodic_checks(struct lws_context *context, /* take the timer out now we took * responsibility */ - lws_timed_callback_remove(v, q); + __lws_timed_callback_remove(v, q); } } lws_end_foreach_ll_safe(q); + + lws_vhost_unlock(v); /* ----------------------- vhost */ } } lws_end_foreach_ll(v, vhost_next); @@ -1085,6 +1089,9 @@ lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi) int n; pt->inside_service = 1; +#if LWS_MAX_SMP > 1 + pt->self = pthread_self(); +#endif if (context->event_loop_ops->run_pt) { /* we are configured for an event loop */ diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 2bd9ab1b2..0daf9c6b9 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -697,6 +697,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, p = (unsigned char *)args.p; } + *p = '\0'; n = lws_serve_http_file(wsi, path, mimetype, (char *)start, lws_ptr_diff(p, start)); @@ -2299,8 +2300,8 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, /* Only add cache control if its not specified by any other_headers. */ if (!other_headers || - (!strstr(other_headers, "cache-control") && - !strstr(other_headers, "Cache-Control"))) { + (!strstr(other_headers, "cache-control") && + !strstr(other_headers, "Cache-Control"))) { if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL, (unsigned char *)cc, cclen, &p, end)) return -1; diff --git a/lib/roles/listen/ops-listen.c b/lib/roles/listen/ops-listen.c index 92f8cd856..977c4b037 100644 --- a/lib/roles/listen/ops-listen.c +++ b/lib/roles/listen/ops-listen.c @@ -79,8 +79,8 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi, * block the connect queue for other legit peers. */ - accept_fd = accept((int)pollfd->fd, - (struct sockaddr *)&cli_addr, &clilen); + accept_fd = accept((int)pollfd->fd, + (struct sockaddr *)&cli_addr, &clilen); lws_latency(context, wsi, "listener accept", (int)accept_fd, accept_fd != LWS_SOCK_INVALID); if (accept_fd == LWS_SOCK_INVALID) { @@ -88,9 +88,8 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi, LWS_ERRNO == LWS_EWOULDBLOCK) { break; } - lwsl_err("ERROR on accept: %s\n", - strerror(LWS_ERRNO)); - break; + lwsl_err("accept: %s\n", strerror(LWS_ERRNO)); + return LWS_HPI_RET_HANDLED; } lws_plat_set_socket_options(wsi->vhost, accept_fd, 0); @@ -130,9 +129,12 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi, fd.sockfd = accept_fd; cwsi = lws_adopt_descriptor_vhost(wsi->vhost, opts, fd, NULL, NULL); - if (!cwsi) + if (!cwsi) { + lwsl_err("%s: lws_adopt_descriptor_vhost failed\n", + __func__); /* already closed cleanly as necessary */ return LWS_HPI_RET_WSI_ALREADY_DIED; + } if (lws_server_socket_service_ssl(cwsi, accept_fd)) { lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,