hrtimer: add support for libevent and libev

This commit is contained in:
Andy Green 2018-05-02 18:35:58 +08:00
parent 9cce1874b0
commit a01ad0dd20
32 changed files with 1943 additions and 79 deletions

2
.gitignore vendored
View file

@ -47,3 +47,5 @@ libwebsockets.pc
build/
*.swp
doc
/build2/
/build3/

View file

@ -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);
}

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* 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,
};

View file

@ -23,9 +23,19 @@
#include <ev.h>
#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 {

View file

@ -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 = {

View file

@ -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 {

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* 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);
}
}

View file

@ -24,6 +24,11 @@
#include <uv.h>
/*
* 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

View file

@ -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;

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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 <libwebsockets.h>\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()

View file

@ -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 <loglevel>|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

View file

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
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
e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
-----END CERTIFICATE-----

View file

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
-----END PRIVATE KEY-----

View file

@ -0,0 +1,186 @@
/*
* lws-minimal-http-server-eventlib
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* 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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
#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;
}

View file

@ -0,0 +1,9 @@
<meta charset="UTF-8">
<html>
<body>
<img src="libwebsockets.org-logo.png"><br>
<h1>404</h1>
Sorry, that file doesn't exist.
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -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;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -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

View file

@ -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 */

View file

@ -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 <loglevel>|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
```