diff --git a/.gitignore b/.gitignore index d2b3e444..74c0e3c7 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ libwebsockets.pc build/ *.swp doc +/build2/ +/build3/ diff --git a/lib/context.c b/lib/context.c index c85a4816..2ccfbe96 100644 --- a/lib/context.c +++ b/lib/context.c @@ -1163,6 +1163,7 @@ lws_create_context(const struct lws_context_creation_info *info) lwsl_info("Using event loop: %s\n", context->event_loop_ops->name); #if defined(LWS_WITH_TLS) + time(&context->tls.last_cert_check_s); if (info->alpn) context->tls.alpn_default = info->alpn; else { @@ -1365,8 +1366,6 @@ lws_create_context(const struct lws_context_creation_info *info) if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) lws_plat_drop_app_privileges(info); - time(&context->last_cert_check_s); - /* expedite post-context init (eg, protocols) */ lws_cancel_service(context); @@ -1729,6 +1728,22 @@ static void lws_context_destroy3(struct lws_context *context) { struct lws_context **pcontext_finalize = context->pcontext_finalize; + struct lws_context_per_thread *pt; + int n; + + for (n = 0; n < context->count_threads; n++) { + pt = &context->pt[n]; + + if (context->event_loop_ops->destroy_pt) + context->event_loop_ops->destroy_pt(context, n); + + lws_free_set_NULL(context->pt[n].serv_buf); + +#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) + while (pt->http.ah_list) + _lws_destroy_ah(pt, pt->http.ah_list); +#endif + } lws_free(context); lwsl_info("%s: ctx %p freed\n", __func__, context); @@ -1746,8 +1761,9 @@ lws_context_destroy2(struct lws_context *context) { struct lws_vhost *vh = NULL, *vh1; #if defined(LWS_WITH_PEER_LIMITS) - uint32_t n; + uint32_t nu; #endif + int n; lwsl_info("%s: ctx %p\n", __func__, context); @@ -1780,9 +1796,9 @@ lws_context_destroy2(struct lws_context *context) lws_plat_context_late_destroy(context); #if defined(LWS_WITH_PEER_LIMITS) - for (n = 0; n < context->pl_hash_elements; n++) { + for (nu = 0; nu < context->pl_hash_elements; nu++) { lws_start_foreach_llp(struct lws_peer **, peer, - context->pl_hash_table[n]) { + context->pl_hash_table[nu]) { struct lws_peer *df = *peer; *peer = df->next; lws_free(df); @@ -1807,6 +1823,11 @@ lws_context_destroy2(struct lws_context *context) return; } + if (!context->pt[0].event_loop_foreign) + for (n = 0; n < context->count_threads; n++) + if (context->pt[n].inside_service) + return; + lws_context_destroy3(context); } @@ -1844,6 +1865,8 @@ lws_context_destroy(struct lws_context *context) } lwsl_info("%s: ctx %p: already being destroyed\n", __func__, context); + + lws_context_destroy3(context); return; } @@ -1891,20 +1914,6 @@ lws_context_destroy(struct lws_context *context) lws_pt_mutex_destroy(pt); } - for (n = 0; n < context->count_threads; n++) { - pt = &context->pt[n]; - - if (context->event_loop_ops->destroy_pt) - context->event_loop_ops->destroy_pt(context, n); - - lws_free_set_NULL(context->pt[n].serv_buf); - -#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) - while (pt->http.ah_list) - _lws_destroy_ah(pt, pt->http.ah_list); -#endif - } - /* * inform all the protocols that they are done and will have no more * callbacks. @@ -1944,10 +1953,5 @@ lws_context_destroy(struct lws_context *context) return; } - if (!context->pt[0].event_loop_foreign) - for (n = 0; n < context->count_threads; n++) - if (context->pt[n].inside_service) - return; - lws_context_destroy2(context); } diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index 746d5712..d60072c0 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010-2017 Andy Green + * Copyright (C) 2010-2018 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,13 +21,66 @@ #include "private-libwebsockets.h" +static void +lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) +{ + struct lws_context_per_thread *pt = + (struct lws_context_per_thread *)watcher->data; + lws_usec_t us; + + lws_pt_lock(pt, __func__); + us = __lws_hrtimer_service(pt); + if (us != LWS_HRTIMER_NOWAIT) { + ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); + ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); + } + lws_pt_unlock(pt); +} + +static void +lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents) +{ + struct lws_context_per_thread *pt = lws_container_of(handle, + struct lws_context_per_thread, ev.idle); + lws_usec_t us; + + lws_service_do_ripe_rxflow(pt); + + /* + * is there anybody with pending stuff that needs service forcing? + */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* -1 timeout means just do forced service */ + _lws_plat_service_tsi(pt->context, -1, pt->tid); + /* still somebody left who wants forced service? */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) + /* yes... come back again later */ + return; + } + + /* account for hrtimer */ + + lws_pt_lock(pt, __func__); + us = __lws_hrtimer_service(pt); + if (us != LWS_HRTIMER_NOWAIT) { + ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); + ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); + } + lws_pt_unlock(pt); + + /* there is nobody who needs service forcing, shut down idle */ + ev_idle_stop(loop, handle); +} + static void lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { + struct lws_context_per_thread *pt; struct lws_io_watcher *lws_io = lws_container_of(watcher, struct lws_io_watcher, ev.watcher); struct lws_context *context = lws_io->context; struct lws_pollfd eventfd; + struct lws *wsi; if (revents & EV_ERROR) return; @@ -45,7 +98,12 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) eventfd.revents |= LWS_POLLOUT; } - lws_service_fd(context, &eventfd); + wsi = wsi_from_fd(context, watcher->fd); + pt = &context->pt[(int)wsi->tsi]; + + lws_service_fd_tsi(context, &eventfd, (int)wsi->tsi); + + ev_idle_start(pt->ev.io_loop, &pt->ev.idle); } LWS_VISIBLE void @@ -64,6 +122,7 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents) static int elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) { + struct lws_context_per_thread *pt = &context->pt[tsi]; struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev.watcher; struct lws_vhost *vh = context->vhost_list; const char *backend_name; @@ -84,7 +143,7 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) return -1; } - context->pt[tsi].ev.io_loop = loop; + pt->ev.io_loop = loop; /* * Initialize the accept w_accept with all the listening sockets @@ -138,6 +197,11 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) lwsl_info(" libev backend: %s\n", backend_name); (void)backend_name; + ev_timer_init(&pt->ev.hrtimer, lws_ev_hrtimer_cb, 0, 0); + pt->ev.hrtimer.data = pt; + + ev_idle_init(&pt->ev.idle, lws_ev_idle_cb); + return status; } @@ -147,17 +211,22 @@ elops_destroy_pt_ev(struct lws_context *context, int tsi) struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_vhost *vh = context->vhost_list; - if (!pt->ev.io_loop) - return; - while (vh) { if (vh->lserv_wsi) ev_io_stop(pt->ev.io_loop, &vh->w_accept.ev.watcher); vh = vh->vhost_next; } - if (!pt->event_loop_foreign) + + /* static assets */ + + ev_timer_stop(pt->ev.io_loop, &pt->ev.hrtimer); + ev_idle_stop(pt->ev.io_loop, &pt->ev.idle); + + if (!pt->event_loop_foreign) { ev_signal_stop(pt->ev.io_loop, &pt->w_sigint.ev.watcher); + ev_loop_destroy(pt->ev.io_loop); + } } static int @@ -226,7 +295,7 @@ static int elops_destroy_context2_ev(struct lws_context *context) { struct lws_context_per_thread *pt; - int n, m, internal = 0; + int n, m; lwsl_debug("%s\n", __func__); @@ -240,7 +309,6 @@ elops_destroy_context2_ev(struct lws_context *context) if (pt->event_loop_foreign || !pt->ev.io_loop) continue; - internal = 1; if (!context->finalize_destroy_after_internal_loops_stopped) { ev_break(pt->ev.io_loop, EVBREAK_ONE); continue; @@ -252,7 +320,7 @@ elops_destroy_context2_ev(struct lws_context *context) ev_loop_destroy(pt->ev.io_loop); } - return internal; + return 0; } static int @@ -281,6 +349,15 @@ elops_init_vhost_listen_wsi_ev(struct lws *wsi) return 0; } +static void +elops_destroy_wsi_ev(struct lws *wsi) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + + ev_io_stop(pt->ev.io_loop, &wsi->w_read.ev.watcher); + ev_io_stop(pt->ev.io_loop, &wsi->w_write.ev.watcher); +} + struct lws_event_loop_ops event_loop_ops_ev = { /* name */ "libev", /* init_context */ elops_init_context_ev, @@ -295,7 +372,7 @@ struct lws_event_loop_ops event_loop_ops_ev = { /* io */ elops_io_ev, /* run_pt */ elops_run_pt_ev, /* destroy_pt */ elops_destroy_pt_ev, - /* destroy wsi */ NULL, + /* destroy wsi */ elops_destroy_wsi_ev, /* periodic_events_available */ 0, }; diff --git a/lib/event-libs/libev/private.h b/lib/event-libs/libev/private.h index 54e1b124..52de727a 100644 --- a/lib/event-libs/libev/private.h +++ b/lib/event-libs/libev/private.h @@ -23,9 +23,19 @@ #include +#define LWS_EV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \ + { (_x)->data = _ctx; \ + _ctx->count_event_loop_static_asset_handles++; } +#define LWS_EV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \ + ((struct lws_context *)(_x)->data))) +#define LWS_EV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \ + (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \ + count_event_loop_static_asset_handles)) + struct lws_pt_eventlibs_libev { struct ev_loop *io_loop; struct ev_timer hrtimer; + struct ev_idle idle; }; struct lws_io_watcher_libev { diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 43dda05c..5cb47263 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -21,24 +21,83 @@ #include "private-libwebsockets.h" +static void +lws_event_hrtimer_cb(int fd, short event, void *p) +{ + struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; + struct timeval tv; + lws_usec_t us; + + lws_pt_lock(pt, __func__); + us = __lws_hrtimer_service(pt); + if (us != LWS_HRTIMER_NOWAIT) { + tv.tv_sec = us / 1000000; + tv.tv_usec = us - (tv.tv_sec * 1000000); + evtimer_add(pt->event.hrtimer, &tv); + } + lws_pt_unlock(pt); +} + +static void +lws_event_idle_timer_cb(int fd, short event, void *p) +{ + struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; + struct timeval tv; + lws_usec_t us; + + lws_service_do_ripe_rxflow(pt); + + /* + * is there anybody with pending stuff that needs service forcing? + */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* -1 timeout means just do forced service */ + _lws_plat_service_tsi(pt->context, -1, pt->tid); + /* still somebody left who wants forced service? */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* yes... come back again later */ + + tv.tv_sec = 0; + tv.tv_usec = 1000; + evtimer_add(pt->event.idle_timer, &tv); + + return; + } + } + + /* account for hrtimer */ + + lws_pt_lock(pt, __func__); + us = __lws_hrtimer_service(pt); + if (us != LWS_HRTIMER_NOWAIT) { + tv.tv_sec = us / 1000000; + tv.tv_usec = us - (tv.tv_sec * 1000000); + evtimer_add(pt->event.hrtimer, &tv); + } + lws_pt_unlock(pt); +} + static void lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx) { struct lws_io_watcher *lws_io = (struct lws_io_watcher *)ctx; struct lws_context *context = lws_io->context; + struct lws_context_per_thread *pt; struct lws_pollfd eventfd; + struct timeval tv; + struct lws *wsi; if (revents & EV_TIMEOUT) return; /* !!! EV_CLOSED doesn't exist in libevent2 */ - #if LIBEVENT_VERSION_NUMBER < 0x02000000 +#if LIBEVENT_VERSION_NUMBER < 0x02000000 if (revents & EV_CLOSED) { event_del(lws_io->event.watcher); event_free(lws_io->event.watcher); return; } - #endif +#endif eventfd.fd = sock_fd; eventfd.events = 0; @@ -52,7 +111,16 @@ lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx) eventfd.revents |= LWS_POLLOUT; } - lws_service_fd(context, &eventfd); + wsi = wsi_from_fd(context, sock_fd); + pt = &context->pt[(int)wsi->tsi]; + + lws_service_fd_tsi(context, &eventfd, wsi->tsi); + + /* set the idle timer for 1ms ahead */ + + tv.tv_sec = 0; + tv.tv_usec = 1000; + evtimer_add(pt->event.idle_timer, &tv); } LWS_VISIBLE void @@ -77,6 +145,7 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) { struct lws_vhost *vh = context->vhost_list; struct event_base *loop = (struct event_base *)_loop; + struct lws_context_per_thread *pt = &context->pt[tsi]; lwsl_info("%s: loop %p\n", __func__, _loop); @@ -91,7 +160,7 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) return -1; } - context->pt[tsi].event.io_loop = loop; + pt->event.io_loop = loop; /* * Initialize all events with the listening sockets @@ -110,13 +179,22 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) vh = vh->vhost_next; } + /* static event loop objects */ + + pt->event.hrtimer = event_new(loop, -1, EV_PERSIST, + lws_event_hrtimer_cb, pt); + + pt->event.idle_timer = event_new(loop, -1, EV_PERSIST, + lws_event_idle_timer_cb, pt); + /* Register the signal watcher unless it's a foreign loop */ - if (context->pt[tsi].event_loop_foreign) + + if (pt->event_loop_foreign) return 0; - context->pt[tsi].w_sigint.event.watcher = evsignal_new(loop, SIGINT, - lws_event_sigint_cb, &context->pt[tsi]); - event_add(context->pt[tsi].w_sigint.event.watcher, NULL); + pt->w_sigint.event.watcher = evsignal_new(loop, SIGINT, + lws_event_sigint_cb, pt); + event_add(pt->w_sigint.event.watcher, NULL); return 0; } @@ -217,8 +295,15 @@ elops_destroy_pt_event(struct lws_context *context, int tsi) vh = vh->vhost_next; } - if (!pt->event_loop_foreign) + event_free(pt->event.hrtimer); + event_free(pt->event.idle_timer); + + if (!pt->event_loop_foreign) { + event_del(pt->w_sigint.event.watcher); event_free(pt->w_sigint.event.watcher); + + event_base_free(pt->event.io_loop); + } } static void @@ -227,10 +312,10 @@ elops_destroy_wsi_event(struct lws *wsi) if (!wsi) return; - if(wsi->w_read.event.watcher) + if (wsi->w_read.event.watcher) event_free(wsi->w_read.event.watcher); - if(wsi->w_write.event.watcher) + if (wsi->w_write.event.watcher) event_free(wsi->w_write.event.watcher); } @@ -271,7 +356,7 @@ static int elops_destroy_context2_event(struct lws_context *context) { struct lws_context_per_thread *pt; - int n, m, internal = 0; + int n, m; lwsl_debug("%s\n", __func__); @@ -285,7 +370,6 @@ elops_destroy_context2_event(struct lws_context *context) if (pt->event_loop_foreign || !pt->event.io_loop) continue; - internal = 1; if (!context->finalize_destroy_after_internal_loops_stopped) { event_base_loopexit(pt->event.io_loop, NULL); continue; @@ -305,7 +389,7 @@ elops_destroy_context2_event(struct lws_context *context) } - return internal; + return 0; } struct lws_event_loop_ops event_loop_ops_event = { diff --git a/lib/event-libs/libevent/private.h b/lib/event-libs/libevent/private.h index 347c7fe5..1c2d3607 100644 --- a/lib/event-libs/libevent/private.h +++ b/lib/event-libs/libevent/private.h @@ -26,6 +26,7 @@ struct lws_pt_eventlibs_libevent { struct event_base *io_loop; struct event *hrtimer; + struct event *idle_timer; }; struct lws_io_watcher_libevent { diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index ecc7e2de..ee948b64 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010-2017 Andy Green + * Copyright (C) 2010-2018 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -116,11 +116,7 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents) eventfd.revents |= LWS_POLLOUT; } } - lws_service_fd(context, &eventfd); - - lws_pt_lock(pt, __func__); - __lws_hrtimer_service(pt); - lws_pt_unlock(pt); + lws_service_fd_tsi(context, &eventfd, wsi->tsi); uv_idle_start(&pt->uv.idle, lws_uv_idle); } @@ -526,7 +522,8 @@ elops_destroy_context1_uv(struct lws_context *context) UV_RUN_NOWAIT))) ; if (m) - lwsl_err("%s: tsi %d: failed to close everything\n", __func__, n); + lwsl_err("%s: tsi %d: not all closed\n", + __func__, n); } } @@ -891,8 +888,9 @@ lws_libuv_closewsi(uv_handle_t* handle) vh = vh->vhost_next; } - if (context->pt[0].event_loop_foreign) { - lwsl_info("%s: calling lws_context_destroy2\n", __func__); + if (!context->count_event_loop_static_asset_handles && + context->pt[0].event_loop_foreign) { + lwsl_info("%s: call lws_context_destroy2\n", __func__); lws_context_destroy2(context); } } diff --git a/lib/event-libs/libuv/private.h b/lib/event-libs/libuv/private.h index 173340e3..cf8f7104 100644 --- a/lib/event-libs/libuv/private.h +++ b/lib/event-libs/libuv/private.h @@ -24,6 +24,11 @@ #include /* + * libuv's async destroy cb means that asking to close something doesn't mean + * you can destroy it or parent things until after the close completes. + * + * So we must reference-count creation and close completions with libuv. + * * All "static" (per-pt or per-context) uv handles must * * - have their .data set to point to the context diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 4ff58781..9f60bd60 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -757,7 +757,6 @@ struct lws_peer { struct lws_context { time_t last_timeout_check_s; 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; diff --git a/lib/service.c b/lib/service.c index 8cf8c934..a08506fb 100644 --- a/lib/service.c +++ b/lib/service.c @@ -554,9 +554,6 @@ lws_service_periodic_checks(struct lws_context *context, struct lws *wsi; int timed_out = 0; time_t now; -#if defined(LWS_WITH_TLS) - int n = 0; -#endif #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) struct allocated_headers *ah; int m; @@ -810,12 +807,10 @@ lws_service_periodic_checks(struct lws_context *context, /* * Phase 6: check the remaining cert lifetime daily */ -#if defined(LWS_WITH_TLS) - n = lws_compare_time_t(context, now, context->last_cert_check_s); - if ((!context->last_cert_check_s || n > (24 * 60 * 60)) && - !lws_tls_check_all_cert_lifetimes(context)) - context->last_cert_check_s = now; -#endif + + if (context->tls_ops && + context->tls_ops->periodic_housekeeping) + context->tls_ops->periodic_housekeeping(context, now); return timed_out; } @@ -869,7 +864,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, } #if defined(LWS_WITH_TLS) - if (lwsi_state(wsi) == LRS_SHUTDOWN && lws_is_ssl(wsi) && wsi->tls.ssl) { + if (lwsi_state(wsi) == LRS_SHUTDOWN && + lws_is_ssl(wsi) && wsi->tls.ssl) { switch (__lws_tls_shutdown(wsi)) { case LWS_SSL_CAPABLE_DONE: case LWS_SSL_CAPABLE_ERROR: @@ -927,6 +923,10 @@ handled: #endif pollfd->revents = 0; + lws_pt_lock(pt, __func__); + __lws_hrtimer_service(pt); + lws_pt_unlock(pt); + return 0; } diff --git a/lib/tls/mbedtls/ssl.c b/lib/tls/mbedtls/ssl.c index 44eb0614..b024dfa6 100644 --- a/lib/tls/mbedtls/ssl.c +++ b/lib/tls/mbedtls/ssl.c @@ -501,7 +501,20 @@ tops_fake_POLLIN_for_buffered_mbedtls(struct lws_context_per_thread *pt) return lws_tls_fake_POLLIN_for_buffered(pt); } +static int +tops_periodic_housekeeping_mbedtls(struct lws_context *context, time_t now) +{ + int n; + + n = lws_compare_time_t(context, now, context->tls.last_cert_check_s); + if ((!context->tls.last_cert_check_s || n > (24 * 60 * 60)) && + !lws_tls_check_all_cert_lifetimes(context)) + context->tls.last_cert_check_s = now; + + return 0; +} + const struct lws_tls_ops tls_ops_mbedtls = { /* fake_POLLIN_for_buffered */ tops_fake_POLLIN_for_buffered_mbedtls, - + /* periodic_housekeeping */ tops_periodic_housekeeping_mbedtls, }; diff --git a/lib/tls/openssl/ssl.c b/lib/tls/openssl/ssl.c index d92ea781..ec43770c 100644 --- a/lib/tls/openssl/ssl.c +++ b/lib/tls/openssl/ssl.c @@ -689,7 +689,21 @@ tops_fake_POLLIN_for_buffered_openssl(struct lws_context_per_thread *pt) return lws_tls_fake_POLLIN_for_buffered(pt); } +static int +tops_periodic_housekeeping_openssl(struct lws_context *context, time_t now) +{ + int n; + + n = lws_compare_time_t(context, now, context->tls.last_cert_check_s); + if ((!context->tls.last_cert_check_s || n > (24 * 60 * 60)) && + !lws_tls_check_all_cert_lifetimes(context)) + context->tls.last_cert_check_s = now; + + return 0; +} + const struct lws_tls_ops tls_ops_openssl = { /* fake_POLLIN_for_buffered */ tops_fake_POLLIN_for_buffered_openssl, + /* periodic_housekeeping */ tops_periodic_housekeeping_openssl, }; diff --git a/lib/tls/private.h b/lib/tls/private.h index 20f9bd36..5c6beeb9 100644 --- a/lib/tls/private.h +++ b/lib/tls/private.h @@ -93,6 +93,7 @@ struct lws_context_per_thread; struct lws_tls_ops { int (*fake_POLLIN_for_buffered)(struct lws_context_per_thread *pt); + int (*periodic_housekeeping)(struct lws_context *context, time_t now); }; #if defined(LWS_WITH_TLS) @@ -110,6 +111,7 @@ extern const struct lws_tls_ops tls_ops_openssl, tls_ops_mbedtls; struct lws_context_tls { char alpn_discovered[32]; const char *alpn_default; + time_t last_cert_check_s; }; struct lws_pt_tls { diff --git a/lib/tls/tls-server.c b/lib/tls/tls-server.c index 01e4ca63..19549a5d 100644 --- a/lib/tls/tls-server.c +++ b/lib/tls/tls-server.c @@ -214,7 +214,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) lws_gate_accepts(context, 0); #if defined(LWS_WITH_STATS) - context->updated = 1; + context->updated = 1; #endif /* * we are not accepted yet, but we need to enter ourselves diff --git a/minimal-examples/http-server/README.md b/minimal-examples/http-server/README.md index d9ea25f3..1adb6943 100644 --- a/minimal-examples/http-server/README.md +++ b/minimal-examples/http-server/README.md @@ -3,6 +3,7 @@ minimal-http-server-basicauth|Shows how to protect a mount using a password file and basic auth minimal-http-server-dynamic|Serves both static and dynamically generated http content minimal-http-server-eventlib-foreign|Demonstrates integrating lws with a foreign event library +minimal-http-server-eventlib-demos|Using the demo plugins with event libraries minimal-http-server-eventlib|Same as minimal-http-server but works with a supported event library minimal-http-server-form-get|Process a GET form minimal-http-server-form-post-file|Process a multipart POST form with file transfer diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib-demos/CMakeLists.txt new file mode 100644 index 00000000..593d6871 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-minimal-http-server-eventlib-demos) +set(SRCS minimal-http-server-eventlib-demos.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_ROLE_H1 1 requirements) +require_lws_config(LWS_ROLE_WS 1 requirements) +require_lws_config(LWS_WITHOUT_SERVER 0 requirements) + +if (requirements) + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/README.md b/minimal-examples/http-server/minimal-http-server-eventlib-demos/README.md new file mode 100644 index 00000000..90720e4c --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/README.md @@ -0,0 +1,30 @@ +# lws minimal http server eventlib demos + +This demonstrates a slightly more complex demo that can use +any of the event loops (it defaults to poll) + +It uses statically included plugins to provide the lws test server functions + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +--uv|Use the libuv event library (lws must have been configured with `-DLWS_WITH_LIBUV=1`) +--event|Use the libevent library (lws must have been configured with `-DLWS_WITH_LIBEVENT=1`) +--ev|Use the libev event library (lws must have been configured with `-DLWS_WITH_LIBEV=1`) + +## build + +``` + $ cmake . && make +``` + +## usage + +``` + $ ./lws-minimal-http-server-eventlib-demos +[2018/03/04 09:30:02:7986] USER: LWS minimal http server-eventlib-demos | visit http://localhost:7681 +[2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on +``` + +Visit http://localhost:7681 + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.cert b/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.cert new file mode 100644 index 00000000..6f372db4 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.cert @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE= +-----END CERTIFICATE----- diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.key b/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.key new file mode 100644 index 00000000..148f8598 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/localhost-100y.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +fBrpEY1IATtPq1taBZZogRqI3rOkkPk= +-----END PRIVATE KEY----- diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c b/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c new file mode 100644 index 00000000..f624fa51 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c @@ -0,0 +1,186 @@ +/* + * lws-minimal-http-server-eventlib + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates a minimal http[s] server that can work with any of the + * supported event loop backends, or the default poll() one. + * + * To keep it simple, it serves stuff from the subdirectory + * "./mount-origin" of the directory it was started in. + * You can change that by changing mount.origin below. + */ + +#include +#include +#include + +#define LWS_PLUGIN_STATIC +#include "../../../plugins/protocol_lws_mirror.c" +#include "../../../plugins/protocol_lws_status.c" +#include "../../../plugins/protocol_dumb_increment.c" +#include "../../../plugins/protocol_post_demo.c" + +static struct lws_context *context; + +static struct lws_protocols protocols[] = { + /* first protocol must always be HTTP handler */ + + { "http-only", lws_callback_http_dummy, 0, 0, }, + LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT, + LWS_PLUGIN_PROTOCOL_MIRROR, + LWS_PLUGIN_PROTOCOL_LWS_STATUS, + LWS_PLUGIN_PROTOCOL_POST_DEMO, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +/* + * mount handlers for sections of the URL space + */ + +static const struct lws_http_mount mount_ziptest = { + NULL, /* linked-list pointer to next*/ + "/ziptest", /* mountpoint in URL namespace on this vhost */ + "candide.zip", /* handler */ + NULL, /* default filename if none given */ + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_FILE, /* origin points to a callback */ + 8, /* strlen("/ziptest"), ie length of the mountpoint */ + NULL, + + { NULL, NULL } // sentinel +}; + +static const struct lws_http_mount mount_post = { + (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ + "/formtest", /* mountpoint in URL namespace on this vhost */ + "protocol-post-demo", /* handler */ + NULL, /* default filename if none given */ + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_CALLBACK, /* origin points to a callback */ + 9, /* strlen("/formtest"), ie length of the mountpoint */ + NULL, + + { NULL, NULL } // sentinel +}; + + +static const struct lws_http_mount mount = { + /* .mount_next */ &mount_post, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ "./mount-origin", /* serve from dir */ + /* .def */ "test.html", /* default filename */ + /* .protocol */ NULL, + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ NULL, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 0, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, +}; + +void signal_cb(void *handle, int signum) +{ + lwsl_err("%s: signal %d\n", __func__, signum); + + switch (signum) { + case SIGTERM: + case SIGINT: + break; + default: + + break; + } + lws_context_destroy(context); +} + +void sigint_handler(int sig) +{ + signal_cb(NULL, sig); +} + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + const char *p; + int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* for LLL_ verbosity above NOTICE to be built into lws, + * lws must have been configured and built with + * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ + /* | LLL_DEBUG */; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal http server eventlib | visit http://localhost:7681\n"); + lwsl_user(" [-s (ssl)] [--uv (libuv)] [--ev (libev)] [--event (libevent)]\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.error_document_404 = "/404.html"; + info.pcontext = &context; + info.protocols = protocols; + info.signal_cb = signal_cb; + + if (lws_cmdline_option(argc, argv, "-s")) { + info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.ssl_cert_filepath = "localhost-100y.cert"; + info.ssl_private_key_filepath = "localhost-100y.key"; + } + + if (lws_cmdline_option(argc, argv, "--uv")) + info.options |= LWS_SERVER_OPTION_LIBUV; + else + if (lws_cmdline_option(argc, argv, "--event")) + info.options |= LWS_SERVER_OPTION_LIBEVENT; + else + if (lws_cmdline_option(argc, argv, "--ev")) + info.options |= LWS_SERVER_OPTION_LIBEV; + else + signal(SIGINT, sigint_handler); + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (!lws_service(context, 0)) + ; + + lwsl_info("calling external context destroy\n"); + lws_context_destroy(context); + + return 0; +} diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/404.html b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/404.html new file mode 100644 index 00000000..1f7ae66e --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/404.html @@ -0,0 +1,9 @@ + + + +
+

404

+ Sorry, that file doesn't exist. + + + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide.zip b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide.zip new file mode 100644 index 00000000..82a66199 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide.zip differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/favicon.ico b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/favicon.ico new file mode 100644 index 00000000..c0cc2e3d Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/favicon.ico differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/http2.png b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/http2.png new file mode 100644 index 00000000..b4129e73 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/http2.png differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/leaf.jpg b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/leaf.jpg new file mode 100644 index 00000000..1a3f46b5 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/leaf.jpg differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/libwebsockets.org-logo.png b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/libwebsockets.org-logo.png new file mode 100644 index 00000000..2060a10c Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/libwebsockets.org-logo.png differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/lws-common.js b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/lws-common.js new file mode 100644 index 00000000..f0c5b92f --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/lws-common.js @@ -0,0 +1,398 @@ +/* + * This section around grayOut came from here: + * http://www.codingforums.com/archive/index.php/t-151720.html + * Assumed public domain + * + * Init like this in your main html script, this also reapplies the gray + * + * lws_gray_out(true,{'zindex':'499'}); + * + * To remove the gray + * + * lws_gray_out(false); + * + */ + +function lws_gray_out(vis, options) { + + var options = options || {}; + var zindex = options.zindex || 50; + var opacity = options.opacity || 70; + var opaque = (opacity / 100); + var bgcolor = options.bgcolor || '#000000'; + var dark = document.getElementById('darkenScreenObject'); + + if (!dark) { + var tbody = document.getElementsByTagName("body")[0]; + var tnode = document.createElement('div'); + tnode.style.position = 'absolute'; + tnode.style.top = '0px'; + tnode.style.left = '0px'; + tnode.style.overflow = 'hidden'; + tnode.style.display ='none'; + tnode.id = 'darkenScreenObject'; + tbody.appendChild(tnode); + dark = document.getElementById('darkenScreenObject'); + } + if (vis) { + dark.style.opacity = opaque; + dark.style.MozOpacity = opaque; + // dark.style.filter ='alpha(opacity='+opacity+')'; + dark.style.zIndex = zindex; + dark.style.backgroundColor = bgcolor; + dark.style.width = gsize(1); + dark.style.height = gsize(0); + dark.style.display ='block'; + addEvent(window, "resize", + function() { + dark.style.height = gsize(0); + dark.style.width = gsize(1); + } + ); + } else { + dark.style.display = 'none'; + removeEvent(window, "resize", + function() { + dark.style.height = gsize(0); + dark.style.width = gsize(1); + } + ); + } +} + +function gsize(ptype) +{ + var h = document.compatMode == 'CSS1Compat' && + !window.opera ? + document.documentElement.clientHeight : + document.body.clientHeight; + var w = document.compatMode == 'CSS1Compat' && + !window.opera ? + document.documentElement.clientWidth : + document.body.clientWidth; + if (document.body && + (document.body.scrollWidth || document.body.scrollHeight)) { + var pageWidth = (w > (t = document.body.scrollWidth)) ? + ("" + w + "px") : ("" + (t) + "px"); + var pageHeight = (h > (t = document.body.scrollHeight)) ? + ("" + h + "px") : ("" + (t) + "px"); + } else if (document.body.offsetWidth) { + var pageWidth = (w > (t = document.body.offsetWidth)) ? + ("" + w + "px") : ("" + (t) + "px"); + var pageHeight =(h > (t = document.body.offsetHeight)) ? + ("" + h + "px") : ("" + (t) + "px"); + } else { + var pageWidth = '100%'; + var pageHeight = '100%'; + } + return (ptype == 1) ? pageWidth : pageHeight; +} + +function addEvent( obj, type, fn ) { + if ( obj.attachEvent ) { + obj['e' + type + fn] = fn; + obj[type+fn] = function() { obj['e' + type+fn]( window.event );} + obj.attachEvent('on' + type, obj[type + fn]); + } else + obj.addEventListener(type, fn, false); +} + +function removeEvent( obj, type, fn ) { + if ( obj.detachEvent ) { + obj.detachEvent('on' + type, obj[type + fn]); + obj[type + fn] = null; + } else + obj.removeEventListener(type, fn, false); +} + +/* + * end of grayOut related stuff + */ + +/* + * lws-meta helpers + */ + +var lws_meta_cmd = { + OPEN_SUBCHANNEL: 0x41, + /**< Client requests to open new subchannel + */ + OPEN_RESULT: 0x42, + /**< Result of client request to open new subchannel */ + CLOSE_NOT: 0x43, + CLOSE_RQ: 0x44, + /**< client requests to close a subchannel */ + WRITE: 0x45, + /**< connection writes something to specific channel index */ + RX: 0x46, +}; + +function new_ws(urlpath, protocol) +{ + if (typeof MozWebSocket != "undefined") + return new MozWebSocket(urlpath, protocol); + + return new WebSocket(urlpath, protocol); +} + +function lws_meta_ws() { + var real; + + var channel_id_to_child; + var pending_children; + var active_children; +} + +function lws_meta_ws_child() { + var onopen; + var onmessage; + var onclose; + + var channel_id; + + var subprotocol; + var suburl; + var cookie; + + var extensions; + + var parent; +} + +lws_meta_ws_child.prototype.send = function(data) +{ + + if (typeof data == "string") { + data = String.fromCharCode(lws_meta_cmd.WRITE) + + String.fromCharCode(this.channel_id) + + data; + + return this.parent.real.send(data); + } + + { + + var ab = new Uint8Array(data.length + 2); + + ab[0] = lws_meta_cmd.WRITE; + ab[1] = this.channel_id; + ab.set(data, 2); + + return this.parent.real.send(ab); + } +} + +lws_meta_ws_child.prototype.close = function(close_code, close_string) +{ + var pkt = new Uint8Array(129), m = 0, pkt1; + + pkt[m++] = lws_meta_cmd.CLOSE_RQ; + pkt[m++] = this.channel_id; + + pkt[m++] = close_string.length + 0x20; + + pkt[m++] = close_code / 256; + pkt[m++] = close_code % 256; + + for (i = 0; i < close_string.length; i++) + pkt[m++] = close_string.charCodeAt(i); + + pkt1 = new Uint8Array(m); + for (n = 0; n < m; n++) + pkt1[n] = pkt[n]; + + this.parent.real.send(pkt1.buffer); +} + +/* make a real ws connection using lws_meta*/ +lws_meta_ws.prototype.new_parent = function(urlpath) +{ + var n, i, m = 0, pkt1; + + this.ordinal = 1; + this.pending_children = []; + this.active_children = []; + this.real = new_ws(urlpath, "lws-meta"); + + this.real.binaryType = 'arraybuffer'; + this.real.myparent = this; + + this.real.onopen = function() { + pkt = new Uint8Array(1024); + var n, i, m = 0, pkt1; + console.log("real open - pending children " + this.myparent.pending_children.length); + for (n = 0; n < this.myparent.pending_children.length; n++) { + + var p = this.myparent.pending_children[n]; + + pkt[m++] = lws_meta_cmd.OPEN_SUBCHANNEL; + for (i = 0; i < p.subprotocol.length; i++) + pkt[m++] = p.subprotocol.charCodeAt(i); + pkt[m++] = 0; + for (i = 0; i < p.suburl.length; i++) + pkt[m++] = p.suburl.charCodeAt(i); + pkt[m++] = 0; + for (i = 0; i < p.cookie.length; i++) + pkt[m++] = p.cookie.charCodeAt(i); + pkt[m++] = 0; + } + + pkt1 = new Uint8Array(m); + for (n = 0; n < m; n++) + pkt1[n] = pkt[n]; + + console.log(this.myparent.pending_children[0].subprotocol); + console.log(pkt1); + + this.send(pkt1.buffer); + } + + + this.real.onmessage = function(msg) { + + if (typeof msg.data != "string") { + var ba = new Uint8Array(msg.data), n = 0; + + while (n < ba.length) { + + switch (ba[n++]) { + case lws_meta_cmd.OPEN_RESULT: + { + var m = 0, cookie = "", protocol = "", ch = 0; + var ws = this.myparent; + /* cookie NUL + * channel index + 0x20 + * protocol NUL + */ + while (ba[n]) + cookie = cookie + String.fromCharCode(ba[n++]); + n++; + ch = ba[n++]; + + while (ba[n]) + protocol = protocol + String.fromCharCode(ba[n++]); + + console.log("open result " + cookie + " " + protocol + " " + ch + " pending len " + ws.pending_children.length); + + for (m = 0; m < ws.pending_children.length; m++) { + if (ws.pending_children[m].cookie == cookie) { + var newchild = ws.pending_children[m]; + + /* found it */ + ws.pending_children[m].channel_id = ch; + /* add to active children array */ + ws.active_children.push(ws.pending_children[m]); + /* remove from pending children array */ + ws.pending_children.splice(m, 1); + + newchild.parent = ws; + newchild.extensions = this.extensions; + + newchild.onopen(); + + console.log("made active " + cookie); + break; + } + } + break; + } + + case lws_meta_cmd.CLOSE_NOT: + { + var code = 0, str = "", ch = 0, m, le; + var ba = new Uint8Array(msg.data); + /* + * BYTE: channel + * BYTE: MSB status code + * BYTE: LSB status code + * BYTES: rest of message is close status string + */ + + ch = ba[n++]; + le = ba[n++] - 0x20; + code = ba[n++] * 256; + code += ba[n++]; + + while (le--) + str += String.fromCharCode(ba[n++]); + + console.log("channel id " + ch + " code " + code + " str " + str + " len " + str.length); + + for (m = 0; m < this.myparent.active_children.length; m++) + if (this.myparent.active_children[m].channel_id == ch) { + var child = this.myparent.active_children[m]; + var ms = new CloseEvent("close", { code:code, reason:str } ); + + /* reply with close ack */ + this.send(msg.data); + + if (child.onclose) + child.onclose(ms); + + this.myparent.active_children.splice(m, 1); + break; + } + + } + } // switch + } + } else { + if (msg.data.charCodeAt(0) == lws_meta_cmd.WRITE ) { + var ch = msg.data.charCodeAt(1), m, ms; + var ws = this.myparent, ms; + + for (m = 0; m < ws.active_children.length; m++) { + if (ws.active_children[m].channel_id == ch) { + ms = new MessageEvent("WebSocket", { data: msg.data.substr(2, msg.data.length - 2) } ); + if (ws.active_children[m].onmessage) + ws.active_children[m].onmessage(ms); + break; + } + } + } + } + } + this.real.onclose = function() { + var ws = this.myparent, m; + for (m = 0; m < ws.active_children.length; m++) { + var child = ws.active_children[m]; + var ms = new CloseEvent("close", { code:1000, reason:"parent closed" } ); + + if (child.onclose) + child.onclose(ms); + } + } + +} + + + +/* make a child connection using existing lws_meta real ws connection */ +lws_meta_ws.prototype.new_ws = function(suburl, protocol) +{ + var ch = new lws_meta_ws_child(); + + ch.suburl = suburl; + ch.subprotocol = protocol; + ch.cookie = "C" + this.ordinal++; + + this.pending_children.push(ch); + + if (this.real.readyState == 1) + this.real.onopen(); + + return ch; +} + + +/* + * end of lws-meta helpers + */ + +function lws_san(s) +{ + if (s.search("<") != -1) + return "invalid string"; + + return s; +} diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/test.html b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/test.html new file mode 100644 index 00000000..91c6dc2e --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/test.html @@ -0,0 +1,858 @@ + + + + + + Minimal Websocket test app + + + + +
+
+ + + +
+ + + + + + + + +
+ + +
+
...
+
+
+Click Here to +have the test server send a big picture by http. +
+
+ +
+ + + +
+
+ + + + + + + + + + + + +
+ Websocket connection not initializeddumb increment-protocol
+The incrementing number is coming from the server at 20Hz and is individual for +each connection to the server... try opening a second browser window. +

+The button sends a message over the websocket link to ask the server +to zero just this connection's number. +
+ + +
+
+
+
+ +
+ + + +
+
+ + + + + + + + + + + + + +
+ Websocket connection not initialized + + lws-mirror-protocol +
+
+Use the mouse to draw on the canvas below -- all other browser windows open +on this page see your drawing in realtime and you can see any of theirs as +well. +

+The lws-mirror protocol doesn't interpret what is being sent to it, it just +re-sends it to every other websocket it has a connection with using that +protocol, including the guy who sent the packet. +

+libwebsockets-test-client joins in by spamming circles on to this shared canvas when +run. +
+
Drawing color: + +
+
+
+
+
+
+ +
+ + + +
+
+ + + + + + + + + + + + + + +
+ +
+ Websocket connection not initialized + Open and close testing
+To help with open and close testing, you can open and close a connection by hand using + the buttons.
+ "Close" closes the connection from the browser with code 3000 + and reason 'Bye!".
+ "Request Server Close" sends a message asking the server to +initiate the close, which it does with code 1001 and reason "Seeya". +
+ +
+
+
+ +
+ + + +
+
+ + + + + + + + + + + + +
+
Websocket connection not initialized
+
+Server Info + +
+This information is sent by the server over a ws[s] link and updated live +whenever the information changes server-side. +
+
+
+
+ +
+ + + +
+
+ + + + + + + + + + + + + + + +
+POST Form testing +
+This tests POST handling in lws. +
+ FORM 1: send with urlencoded POST body args
+
+ Some text: +
+ +
+
+ FORM 2: send with multipart/form-data
+ (can handle file upload, test limited to 100KB)
+
+ Some text: + +
+  
+ +
+
+
+
+
+ +
+
+ +Looking for support? https://libwebsockets.org, https://github.com/warmcat/libwebsockets
+Join the mailing list: https://libwebsockets.org/mailman/listinfo/libwebsockets + +
+ + + + + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/wss-over-h2.png b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/wss-over-h2.png new file mode 100644 index 00000000..1a62d832 Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/wss-over-h2.png differ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md index a663d6e8..4c21fa1a 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md @@ -41,8 +41,8 @@ exits itself. ## usage ``` - $ ./lws-minimal-http-server-libuv-foreign -[2018/03/29 12:19:31:3480] USER: LWS minimal http server libuv + foreign loop | visit http://localhost:7681 + $ ./lws-minimal-http-server-eventlib-foreign +[2018/03/29 12:19:31:3480] USER: LWS minimal http server eventlib + foreign loop | visit http://localhost:7681 [2018/03/29 12:19:31:3724] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 off [2018/03/29 12:19:31:3804] NOTICE: Using foreign event loop... [2018/03/29 12:19:31:3938] USER: Foreign 1Hz timer diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c index 3e807d9c..f31b7bd2 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c @@ -337,7 +337,7 @@ int main(int argc, const char **argv) logs = atoi(p); lws_set_log_level(logs, NULL); - lwsl_user("LWS minimal http server libuv + foreign loop |" + lwsl_user("LWS minimal http server eventlib + foreign loop |" " visit http://localhost:7681\n"); /* @@ -383,8 +383,7 @@ int main(int argc, const char **argv) lwsl_user("\n"); lwsl_user(" Finally close only the timer and signalhandler and\n"); lwsl_user(" exit the loop cleanly\n"); - - lwsl_notice("%s\n", info.ssl_cert_filepath); + lwsl_user("\n"); /* foreign loop specific startup and run */ diff --git a/minimal-examples/http-server/minimal-http-server-eventlib/README.md b/minimal-examples/http-server/minimal-http-server-eventlib/README.md index 873e2502..ecfb733c 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib/README.md +++ b/minimal-examples/http-server/minimal-http-server-eventlib/README.md @@ -1,4 +1,13 @@ -# lws minimal http server libuv +# lws minimal http server eventlib + +This demonstrates a minimal http server that can use any of the event libraries + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +--uv|Use the libuv event library (lws must have been configured with `-DLWS_WITH_LIBUV=1`) +--event|Use the libevent library (lws must have been configured with `-DLWS_WITH_LIBEVENT=1`) +--ev|Use the libev event library (lws must have been configured with `-DLWS_WITH_LIBEV=1`) ## build @@ -9,8 +18,8 @@ ## usage ``` - $ ./lws-minimal-http-server-libuv -[2018/03/04 09:30:02:7986] USER: LWS minimal http server-libuv | visit http://localhost:7681 + $ ./lws-minimal-http-server-eventlib +[2018/03/04 09:30:02:7986] USER: LWS minimal http server-eventlib | visit http://localhost:7681 [2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on ```