diff --git a/minimal-examples/http-server/README.md b/minimal-examples/http-server/README.md index 7e964c55..1ecfeebe 100644 --- a/minimal-examples/http-server/README.md +++ b/minimal-examples/http-server/README.md @@ -4,7 +4,8 @@ minimal-http-server-dynamic|Serves both static and dynamically generated http co minimal-http-server-form-get|Process a GET form minimal-http-server-form-post-file|Process a multipart POST form with file transfer minimal-http-server-form-post|Process a POST form (no file transfer) -minimal-http-server-libuv|Same as minimal-http-server but libuv event loop +minimal-http-server-libuv-foreign|Same as minimal-http-server but lws uses a foreign libuv event loop +minimal-http-server-libuv|Same as minimal-http-server but lws uses its own libuv event loop minimal-http-server-multivhost|Same as minimal-http-server but three different vhosts minimal-http-server-smp|Multiple service threads minimal-http-server-tls|Serves a directory over http/1 or http/2 with TLS (SSL), custom 404 handler diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-libuv-foreign/CMakeLists.txt new file mode 100644 index 00000000..87f1ac3c --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-minimal-http-server-libuv-foreign) +set(SRCS minimal-http-server-libuv-foreign.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_WITH_LIBUV 1 requirements) +require_lws_config(LWS_WITHOUT_SERVER 0 requirements) + +CHECK_C_SOURCE_COMPILES("#include \n#include \nint main(void) {\n#if (UV_VERSION_MAJOR > 0)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_RECENT_LIBUV) +if (NOT HAS_RECENT_LIBUV) + if (LWS_WITH_MINIMAL_EXAMPLES) + message("libuv is too old (pre- 1.0)") + else() + message(FATAL_ERROR "libuv is too old (pre- 1.0)") + endif() + set(requirements 0) +endif() + +if (requirements) + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared uv) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets uv) + endif() +endif() diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md b/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md new file mode 100644 index 00000000..3b823d66 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md @@ -0,0 +1,31 @@ +# lws minimal http server libuv foreign + +This demonstrates having lws take part in a libuv loop owned by +something else, with its own objects running in the loop. + +Lws can join the loop, and clean up perfectly after itself. + +## build + +``` + $ cmake . && make +``` + +## 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 +[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 +[2018/03/29 12:19:32:4011] USER: Foreign 1Hz timer +[2018/03/29 12:19:33:4024] USER: Foreign 1Hz timer +^C[2018/03/29 12:19:33:8868] NOTICE: Signal 2 caught, exiting... +[2018/03/29 12:19:33:8963] USER: main: starting exit cleanup... +[2018/03/29 12:19:33:9064] USER: main: lws context destroyed: cleaning the foreign loop +[2018/03/29 12:19:33:9108] USER: main: exiting... +``` + +Visit http://localhost:7681 + diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c b/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c new file mode 100644 index 00000000..3da9d0cb --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c @@ -0,0 +1,155 @@ +/* + * lws-minimal-http-server-libuv-foreign + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates the most minimal http server you can make with lws that + * uses a libuv event loop created outside lws. It shows how lws can + * participate in someone else's event loop and clean up after itself. + * + * 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 + +static struct lws_context *context; + +static const struct lws_http_mount mount = { + /* .mount_next */ NULL, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ "./mount-origin", /* serve from dir */ + /* .def */ "index.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(uv_signal_t *watcher, int signum) +{ + lwsl_notice("Signal %d caught, exiting...\n", watcher->signum); + + switch (watcher->signum) { + case SIGTERM: + case SIGINT: + break; + default: + signal(SIGABRT, SIG_DFL); + abort(); + break; + } + lws_libuv_stop(context); +} + +/* this logs once a second to show that the foreign loop assets are working */ + +static void timer_cb(uv_timer_t *t) +{ + lwsl_user("Foreign 1Hz timer\n"); +} + +static void lws_uv_close_cb(uv_handle_t *handle) +{ +} + +static void lws_uv_walk_cb(uv_handle_t *handle, void *arg) +{ + lwsl_info("%s: closing foreign loop asset: %p (type %d)\n", + __func__, handle, handle->type); + uv_close(handle, lws_uv_close_cb); +} + +int main(int argc, char **argv) +{ + struct lws_context_creation_info info; + uv_timer_t timer_outer; + uv_loop_t loop; + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.error_document_404 = "/404.html"; + info.options = LWS_SERVER_OPTION_LIBUV; + + lws_set_log_level(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 */, NULL); + + lwsl_user("LWS minimal http server libuv + foreign loop |" + " visit http://localhost:7681\n"); + + uv_loop_init(&loop); + + uv_timer_init(&loop, &timer_outer); + uv_timer_start(&timer_outer, timer_cb, 0, 1000); + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + lws_uv_sigint_cfg(context, 1, signal_cb); + + if (lws_uv_initloop(context, &loop, 0)) { + lwsl_err("lws_uv_initloop failed\n"); + + goto bail; + } + + lws_libuv_run(context, 0); + +bail: + lwsl_user("%s: starting exit cleanup...\n", __func__); + + /* cleanup the lws part */ + + lws_context_destroy(context); + lws_context_destroy2(context); + + /* cleanup the foreign loop part */ + + lwsl_user("%s: lws context destroyed: cleaning the foreign loop\n", + __func__); + + /* + * Instead of walking to close all the foreign assets, it's also + * fine to close them individually instead as below + */ + // uv_timer_stop(&timer_outer); + // uv_close((uv_handle_t*)&timer_outer, NULL); + + /* close every foreign loop asset unconditionally */ + uv_walk(&loop, lws_uv_walk_cb, NULL); + + /* let it run until everything completed close */ + uv_run(&loop, UV_RUN_DEFAULT); + + /* nothing left in the foreign loop, destroy it */ + + uv_loop_close(&loop); + + lwsl_user("%s: exiting...\n", __func__); + + return 0; +} diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/404.html b/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/404.html new file mode 100644 index 00000000..1f7ae66e --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/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-libuv-foreign/mount-origin/favicon.ico b/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/favicon.ico new file mode 100644 index 00000000..c0cc2e3d Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/favicon.ico differ diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/index.html new file mode 100644 index 00000000..31a6dfaf --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/index.html @@ -0,0 +1,13 @@ + + + +
+ + Hello from the minimal http server libuv foreign loop example. +
+ The timer messages in the console are coming from
+ a timer on the libuv loop set up before the lws context
+ started using it. + + + diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/libwebsockets.org-logo.png b/minimal-examples/http-server/minimal-http-server-libuv-foreign/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-libuv-foreign/mount-origin/libwebsockets.org-logo.png differ