From 388c0677ee3de7561c08f1da058d8f4db56bcdba Mon Sep 17 00:00:00 2001 From: Andy Green Date: Tue, 6 Mar 2018 09:39:27 +0800 Subject: [PATCH] minimal-examples: add ws pmd example --- lib/ext/extension-permessage-deflate.c | 29 ++- .../minimal-http-client/minimal-http-client.c | 3 +- .../minimal-http-server/minimal-http-server.c | 16 +- .../minimal-ws-server-pmd-bulk/CMakeLists.txt | 16 ++ .../minimal-ws-server-pmd-bulk/README.md | 21 ++ .../minimal-ws-server-pmd-bulk/index.html | 87 +++++++ .../libwebsockets.org-logo.png | Bin 0 -> 7029 bytes .../minimal-ws-server-pmd-bulk.c | 98 ++++++++ .../protocol_lws_minimal_pmd_bulk.c | 224 ++++++++++++++++++ .../minimal-ws-server-pmd/CMakeLists.txt | 16 ++ .../minimal-ws-server-pmd/README.md | 23 ++ .../minimal-ws-server-pmd/favicon.ico | Bin 0 -> 1406 bytes .../minimal-ws-server-pmd/index.html | 86 +++++++ .../libwebsockets.org-logo.png | Bin 0 -> 7029 bytes .../minimal-ws-server-pmd.c | 97 ++++++++ .../protocol_lws_minimal.c | 194 +++++++++++++++ .../minimal-ws-server.c | 19 +- .../minimal-ws-server/minimal-ws-server.c | 19 +- 18 files changed, 928 insertions(+), 20 deletions(-) create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/CMakeLists.txt create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/README.md create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/index.html create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/libwebsockets.org-logo.png create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/minimal-ws-server-pmd-bulk.c create mode 100644 minimal-examples/minimal-ws-server-pmd-bulk/protocol_lws_minimal_pmd_bulk.c create mode 100644 minimal-examples/minimal-ws-server-pmd/CMakeLists.txt create mode 100644 minimal-examples/minimal-ws-server-pmd/README.md create mode 100644 minimal-examples/minimal-ws-server-pmd/favicon.ico create mode 100644 minimal-examples/minimal-ws-server-pmd/index.html create mode 100644 minimal-examples/minimal-ws-server-pmd/libwebsockets.org-logo.png create mode 100644 minimal-examples/minimal-ws-server-pmd/minimal-ws-server-pmd.c create mode 100644 minimal-examples/minimal-ws-server-pmd/protocol_lws_minimal.c diff --git a/lib/ext/extension-permessage-deflate.c b/lib/ext/extension-permessage-deflate.c index 80a98f663..e0c3773bc 100644 --- a/lib/ext/extension-permessage-deflate.c +++ b/lib/ext/extension-permessage-deflate.c @@ -1,7 +1,7 @@ /* * ./lib/extension-permessage-deflate.c * - * Copyright (C) 2016 Andy Green + * Copyright (C) 2016 - 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 @@ -83,7 +83,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, if (!oa->option_name) break; for (n = 0; n < (int)ARRAY_SIZE(lws_ext_pm_deflate_options); n++) - if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name)) + if (!strcmp(lws_ext_pm_deflate_options[n].name, + oa->option_name)) break; if (n == (int)ARRAY_SIZE(lws_ext_pm_deflate_options)) @@ -123,8 +124,9 @@ lws_extension_callback_pm_deflate(struct lws_context *context, n = (int)wsi->protocol->rx_buffer_size; if (n < 128) { - lwsl_info(" permessage-deflate requires the protocol (%s) to have an RX buffer >= 128\n", - wsi->protocol->name); + lwsl_info(" permessage-deflate requires the protocol " + "(%s) to have an RX buffer >= 128\n", + wsi->protocol->name); return -1; } @@ -186,14 +188,16 @@ lws_extension_callback_pm_deflate(struct lws_context *context, printf("\n"); #endif if (!priv->rx_init) - if (inflateInit2(&priv->rx, -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) { + if (inflateInit2(&priv->rx, + -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) { lwsl_err("%s: iniflateInit failed\n", __func__); return -1; } priv->rx_init = 1; if (!priv->buf_rx_inflated) priv->buf_rx_inflated = lws_malloc(LWS_PRE + 7 + 5 + - (1 << priv->args[PMD_RX_BUF_PWR2]), "pmd rx inflate buf"); + (1 << priv->args[PMD_RX_BUF_PWR2]), + "pmd rx inflate buf"); if (!priv->buf_rx_inflated) { lwsl_err("%s: OOM\n", __func__); return -1; @@ -205,7 +209,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, * rx buffer by the caller, so this assumption is safe while * we block new rx while draining the existing rx */ - if (!priv->rx.avail_in && eff_buf->token && eff_buf->token_len) { + if (!priv->rx.avail_in && eff_buf->token && + eff_buf->token_len) { priv->rx.next_in = (unsigned char *)eff_buf->token; priv->rx.avail_in = eff_buf->token_len; } @@ -266,8 +271,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, priv->rx.next_in = trail; priv->rx.avail_in = sizeof(trail); n = inflate(&priv->rx, Z_SYNC_FLUSH); - lwsl_ext("RX trailer inf returned %d, avi %d, avo %d\n", n, - priv->rx.avail_in, priv->rx.avail_out); + lwsl_ext("RX trailer inf returned %d, avi %d, avo %d\n", + n, priv->rx.avail_in, priv->rx.avail_out); switch (n) { case Z_NEED_DICT: case Z_STREAM_ERROR: @@ -302,7 +307,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, priv->rx_held_valid = 1; } - eff_buf->token_len = lws_ptr_diff(priv->rx.next_out, eff_buf->token); + eff_buf->token_len = lws_ptr_diff(priv->rx.next_out, + eff_buf->token); priv->count_rx_between_fin += eff_buf->token_len; lwsl_ext(" %s: RX leaving with new effbuff len %d, " @@ -343,7 +349,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context, priv->tx_init = 1; if (!priv->buf_tx_deflated) priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 + - (1 << priv->args[PMD_TX_BUF_PWR2]), "pmd tx deflate buf"); + (1 << priv->args[PMD_TX_BUF_PWR2]), + "pmd tx deflate buf"); if (!priv->buf_tx_deflated) { lwsl_err("%s: OOM\n", __func__); return -1; diff --git a/minimal-examples/minimal-http-client/minimal-http-client.c b/minimal-examples/minimal-http-client/minimal-http-client.c index 620fc0a18..07fd64613 100644 --- a/minimal-examples/minimal-http-client/minimal-http-client.c +++ b/minimal-examples/minimal-http-client/minimal-http-client.c @@ -84,7 +84,8 @@ int main(int argc, char **argv) struct lws_context *context; int n = 0; - lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER, NULL); + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); lwsl_user("LWS minimal http client\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ diff --git a/minimal-examples/minimal-http-server/minimal-http-server.c b/minimal-examples/minimal-http-server/minimal-http-server.c index ef8f7531e..0e2e29e72 100644 --- a/minimal-examples/minimal-http-server/minimal-http-server.c +++ b/minimal-examples/minimal-http-server/minimal-http-server.c @@ -14,6 +14,9 @@ #include #include +#include + +static int interrupted; static const struct lws_http_mount mount = { /* .mount_next */ NULL, /* linked-list "next" */ @@ -35,17 +38,26 @@ static const struct lws_http_mount mount = { /* .basic_auth_login_file */ NULL, }; +void sigint_handler(int sig) +{ + interrupted = 1; +} + int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_context *context; int n = 0; + signal(SIGINT, sigint_handler); + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; - lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER, NULL); + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); + lwsl_user("LWS minimal http server | visit http://localhost:7681\n"); context = lws_create_context(&info); @@ -54,7 +66,7 @@ int main(int argc, char **argv) return 1; } - while (n >=0) + while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); diff --git a/minimal-examples/minimal-ws-server-pmd-bulk/CMakeLists.txt b/minimal-examples/minimal-ws-server-pmd-bulk/CMakeLists.txt new file mode 100644 index 000000000..1f9b1cc9b --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd-bulk/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8.9) +include(CheckFunctionExists) + +set(SAMP lws-minimal-ws-server-pmd-bulk) +set(SRCS minimal-ws-server-pmd-bulk.c) + +set(CMAKE_REQUIRED_LIBRARIES websockets) + +CHECK_FUNCTION_EXISTS(lws_extension_callback_pm_deflate HAVE_PMD) +if (HAVE_PMD) +else() + message(FATAL_ERROR "LWS need to have been built for extensions") +endif() + +add_executable(${SAMP} ${SRCS}) +target_link_libraries(${SAMP} -lwebsockets) diff --git a/minimal-examples/minimal-ws-server-pmd-bulk/README.md b/minimal-examples/minimal-ws-server-pmd-bulk/README.md new file mode 100644 index 000000000..274dbf988 --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd-bulk/README.md @@ -0,0 +1,21 @@ +# lws minimal ws server + permessage-deflate for bulk traffic + +## build + +``` + $ cmake . && make +``` + +## usage + +``` + $ ./lws-minimal-ws-server-pmd-bulk +[2018/03/04 09:30:02:7986] USER: LWS minimal ws server | 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 in your browser + +One or another kind of bulk ws transfer is made to the browser. + +The ws connection is made via permessage-deflate extension. diff --git a/minimal-examples/minimal-ws-server-pmd-bulk/index.html b/minimal-examples/minimal-ws-server-pmd-bulk/index.html new file mode 100644 index 000000000..07cf2b251 --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd-bulk/index.html @@ -0,0 +1,87 @@ + + + + +
+ + LWS bulk transfer example.
+ A large ws message is sent to all browsers open on this page.
+
+ Ws closed
+
+
+ + + + + + + + + diff --git a/minimal-examples/minimal-ws-server-pmd-bulk/libwebsockets.org-logo.png b/minimal-examples/minimal-ws-server-pmd-bulk/libwebsockets.org-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2060a10c936a0959f2a5c3a6b7fa60ac324f1a95 GIT binary patch literal 7029 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 + * + * 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. + * + * To keep it simple, it serves stuff in the directory it was started in. + * You can change that by changing mount.origin + */ + +#include +#include +#include + +#define LWS_PLUGIN_STATIC +#include "protocol_lws_minimal_pmd_bulk.c" + +static struct lws_protocols protocols[] = { + { "http", lws_callback_http_dummy, 0, 0 }, + LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +static int interrupted; + +static const struct lws_http_mount mount = { + /* .mount_next */ NULL, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .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, +}; + +static const struct lws_extension extensions[] = { + { + "permessage-deflate", + lws_extension_callback_pm_deflate, + "permessage-deflate" + "; client_no_context_takeover" + "; client_max_window_bits" + }, + { NULL, NULL, NULL /* terminator */ } +}; + +void sigint_handler(int sig) +{ + interrupted = 1; +} + +int main(int argc, char **argv) +{ + struct lws_context_creation_info info; + struct lws_context *context; + int n = 0; + + signal(SIGINT, sigint_handler); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.protocols = protocols; + info.extensions = extensions; + info.pt_serv_buf_size = 32 * 1024; + + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); + + lwsl_user("LWS minimal ws server + permessage-deflate | visit http://localhost:7681\n"); + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (n >= 0 && !interrupted) + n = lws_service(context, 1000); + + lws_context_destroy(context); + + return 0; +} diff --git a/minimal-examples/minimal-ws-server-pmd-bulk/protocol_lws_minimal_pmd_bulk.c b/minimal-examples/minimal-ws-server-pmd-bulk/protocol_lws_minimal_pmd_bulk.c new file mode 100644 index 000000000..1ceafe8c9 --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd-bulk/protocol_lws_minimal_pmd_bulk.c @@ -0,0 +1,224 @@ +/* + * ws protocol handler plugin for "lws-minimal-pmd-bulk" + * + * Copyright (C) 2010-2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The protocol shows how to send and receive bulk messages over a ws connection + * that optionally may have the permessage-deflate extension negotiated on it. + */ + +#if !defined (LWS_PLUGIN_STATIC) +#define LWS_DLL +#define LWS_INTERNAL +#include +#endif + +#include + +/* + * We will produce a large ws message either from this text repeated many times, + * or from 0x40 + a 6-bit pseudorandom number + */ + +static const char * const redundant_string = + "No one would have believed in the last years of the nineteenth " + "century that this world was being watched keenly and closely by " + "intelligences greater than man's and yet as mortal as his own; that as " + "men busied themselves about their various concerns they were " + "scrutinised and studied, perhaps almost as narrowly as a man with a " + "microscope might scrutinise the transient creatures that swarm and " + "multiply in a drop of water. With infinite complacency men went to " + "and fro over this globe about their little affairs, serene in their " + "assurance of their empire over matter. It is possible that the " + "infusoria under the microscope do the same. No one gave a thought to " + "the older worlds of space as sources of human danger, or thought of " + "them only to dismiss the idea of life upon them as impossible or " + "improbable. It is curious to recall some of the mental habits of " + "those departed days. At most terrestrial men fancied there might be " + "other men upon Mars, perhaps inferior to themselves and ready to " + "welcome a missionary enterprise. Yet across the gulf of space, minds " + "that are to our minds as ours are to those of the beasts that perish, " + "intellects vast and cool and unsympathetic, regarded this earth with " + "envious eyes, and slowly and surely drew their plans against us. And " + "early in the twentieth century came the great disillusionment. " +; + +/* this reflects the length of the string above */ +#define REPEAT_STRING_LEN 1337 +/* this is the total size of the ws message we will send */ +#define MESSAGE_SIZE (100 * REPEAT_STRING_LEN) +/* this is how much we will send each time the connection is writable */ +#define MESSAGE_CHUNK_SIZE (1 * 1024) + + +/* one of these is created for each client connecting to us */ + +struct per_session_data__minimal_pmd_bulk { + struct per_session_data__minimal_pmd_bulk *pss_list; + struct lws *wsi; + int position; /* byte position we got up to sending the message */ + uint64_t rng; +}; + +/* one of these is created for each vhost our protocol is used with */ + +struct per_vhost_data__minimal_pmd_bulk { + struct lws_context *context; + struct lws_vhost *vhost; + const struct lws_protocols *protocol; + + /* linked-list of live pss */ + struct per_session_data__minimal_pmd_bulk *pss_list; +}; + +static int +callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct per_session_data__minimal_pmd_bulk **ppss, *pss = + (struct per_session_data__minimal_pmd_bulk *)user; + struct per_vhost_data__minimal_pmd_bulk *vhd = + (struct per_vhost_data__minimal_pmd_bulk *) + lws_protocol_vh_priv_get(lws_get_vhost(wsi), + lws_get_protocol(wsi)); + uint8_t buf[LWS_PRE + MESSAGE_CHUNK_SIZE], *p; + uint32_t oldest; + int n, m, s, msg_flag = LWS_WRITE_CONTINUATION; + + switch (reason) { + case LWS_CALLBACK_PROTOCOL_INIT: + vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), + lws_get_protocol(wsi), + sizeof(struct per_vhost_data__minimal_pmd_bulk)); + vhd->context = lws_get_context(wsi); + vhd->protocol = lws_get_protocol(wsi); + vhd->vhost = lws_get_vhost(wsi); + break; + + case LWS_CALLBACK_ESTABLISHED: + /* add ourselves to the list of live pss held in the vhd */ + pss->pss_list = vhd->pss_list; + vhd->pss_list = pss; + pss->wsi = wsi; + pss->position = 0; + pss->rng = 4; + lws_callback_on_writable(wsi); + break; + + case LWS_CALLBACK_CLOSED: + /* remove our closing pss from the list of live pss */ + lws_start_foreach_llp(struct per_session_data__minimal_pmd_bulk **, + ppss, vhd->pss_list) { + if (*ppss == pss) { + *ppss = pss->pss_list; + break; + } + } lws_end_foreach_llp(ppss, pss_list); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + + if (pss->position == MESSAGE_SIZE) + break; + + if (pss->position == 0) + msg_flag = LWS_WRITE_TEXT; + + /* fill up one chunk's worth of message content */ + + p = &buf[LWS_PRE]; + n = MESSAGE_CHUNK_SIZE; + if (n > MESSAGE_SIZE - pss->position) + n = MESSAGE_SIZE - pss->position; + /* + * select between producing compressible repeated text, + * or uncompressible PRNG output + */ +#if 0 + while (n) { + m = pss->position % REPEAT_STRING_LEN; + s = REPEAT_STRING_LEN - m; + if (s > n) + s = n; + memcpy(p, &redundant_string[m], s); + pss->position += s; + p += s; + n -= s; + } +#else + pss->position += n; + while (n--) { + pss->rng ^= pss->rng << 21; + pss->rng ^= pss->rng >> 35; + pss->rng ^= pss->rng << 4; + *p++ = 0x40 + ((pss->rng >> (n & 15)) & 0x3f); + } +#endif + if (pss->position != MESSAGE_SIZE) /* if not the end, no FIN */ + msg_flag |= LWS_WRITE_NO_FIN; + + n = lws_ptr_diff(p, &buf[LWS_PRE]); + m = lws_write(wsi, &buf[LWS_PRE], n, msg_flag); + lwsl_notice("write done\n"); + if (m < n) { + lwsl_err("ERROR %d writing to di socket\n", n); + return -1; + } + if (pss->position != MESSAGE_SIZE) /* if more to do... */ + lws_callback_on_writable(wsi); + break; + + case LWS_CALLBACK_RECEIVE: + break; + + default: + break; + } + + return 0; +} + +#define LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK \ + { \ + "lws-minimal-pmd-bulk", \ + callback_minimal_pmd_bulk, \ + sizeof(struct per_session_data__minimal_pmd_bulk), \ + 4096, \ + 0, NULL, 0 \ + } + +#if !defined (LWS_PLUGIN_STATIC) + +/* boilerplate needed if we are built as a dynamic plugin */ + +static const struct lws_protocols protocols[] = { + LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK +}; + +LWS_EXTERN LWS_VISIBLE int +init_protocol_minimal_pmd_bulk(struct lws_context *context, + struct lws_plugin_capability *c) +{ + if (c->api_magic != LWS_PLUGIN_API_MAGIC) { + lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, + c->api_magic); + return 1; + } + + c->protocols = protocols; + c->count_protocols = ARRAY_SIZE(protocols); + c->extensions = NULL; + c->count_extensions = 0; + + return 0; +} + +LWS_EXTERN LWS_VISIBLE int +destroy_protocol_minimal_pmd_bulk(struct lws_context *context) +{ + return 0; +} +#endif diff --git a/minimal-examples/minimal-ws-server-pmd/CMakeLists.txt b/minimal-examples/minimal-ws-server-pmd/CMakeLists.txt new file mode 100644 index 000000000..4d07b7b11 --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8.9) +include(CheckFunctionExists) + +set(SAMP lws-minimal-ws-server-pmd) +set(SRCS minimal-ws-server-pmd.c) + +set(CMAKE_REQUIRED_LIBRARIES websockets) + +CHECK_FUNCTION_EXISTS(lws_extension_callback_pm_deflate HAVE_PMD) +if (HAVE_PMD) +else() + message(FATAL_ERROR "LWS need to have been built for extensions") +endif() + +add_executable(${SAMP} ${SRCS}) +target_link_libraries(${SAMP} -lwebsockets) diff --git a/minimal-examples/minimal-ws-server-pmd/README.md b/minimal-examples/minimal-ws-server-pmd/README.md new file mode 100644 index 000000000..468f74f97 --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd/README.md @@ -0,0 +1,23 @@ +# lws minimal ws server + permessage-deflate + +## build + +``` + $ cmake . && make +``` + +## usage + +``` + $ ./lws-minimal-ws-server +[2018/03/04 09:30:02:7986] USER: LWS minimal ws server | 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 on multiple browser windows + +Text you type in any browser window is sent to all of them. + +For simplicity of this example, only one line of text is cached at the server. + +The ws connection is made via permessage-deflate extension. diff --git a/minimal-examples/minimal-ws-server-pmd/favicon.ico b/minimal-examples/minimal-ws-server-pmd/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c0cc2e3dff34012ba3d4a7848a7ed17579788ec5 GIT binary patch literal 1406 zcmZQzU<5(|0R}M0U}azs1F|%L7$l?s#Ec9aKoZP=&`9i!<^REA8>%80(yxAC$j<-A zkb5S8;qL6446ipNFl>5#fuVR6L=8goC~GtXMnhmYga9MSfQgBTk&TUw5$JocUP63y z3phA97+G0a8QIy{!BT|y==xb$SQt4uIT@LmnZZ(o_~`mk`Tv1M8w?+DXJCL~kQj^& JqOtKoVgQl$ETjMc literal 0 HcmV?d00001 diff --git a/minimal-examples/minimal-ws-server-pmd/index.html b/minimal-examples/minimal-ws-server-pmd/index.html new file mode 100644 index 000000000..74750344e --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd/index.html @@ -0,0 +1,86 @@ + + + + +
+ + LWS chat minimal ws server example.
+ Chat is sent to all browsers open on this page.
+
+ Ws closed
+
+
+ + + + + + + + + diff --git a/minimal-examples/minimal-ws-server-pmd/libwebsockets.org-logo.png b/minimal-examples/minimal-ws-server-pmd/libwebsockets.org-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2060a10c936a0959f2a5c3a6b7fa60ac324f1a95 GIT binary patch literal 7029 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 + * + * 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. + * + * To keep it simple, it serves stuff in the directory it was started in. + * You can change that by changing mount.origin + */ + +#include +#include +#include + +#define LWS_PLUGIN_STATIC +#include "protocol_lws_minimal.c" + +static struct lws_protocols protocols[] = { + { "http", lws_callback_http_dummy, 0, 0 }, + LWS_PLUGIN_PROTOCOL_MINIMAL, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +static int interrupted; + +static const struct lws_http_mount mount = { + /* .mount_next */ NULL, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .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, +}; + +static const struct lws_extension extensions[] = { + { + "permessage-deflate", + lws_extension_callback_pm_deflate, + "permessage-deflate" + "; client_no_context_takeover" + "; client_max_window_bits" + }, + { NULL, NULL, NULL /* terminator */ } +}; + +void sigint_handler(int sig) +{ + interrupted = 1; +} + +int main(int argc, char **argv) +{ + struct lws_context_creation_info info; + struct lws_context *context; + int n = 0; + + signal(SIGINT, sigint_handler); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.protocols = protocols; + info.extensions = extensions; + + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); + + lwsl_user("LWS minimal ws server + permessage-deflate | visit http://localhost:7681\n"); + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (n >= 0 && !interrupted) + n = lws_service(context, 1000); + + lws_context_destroy(context); + + return 0; +} diff --git a/minimal-examples/minimal-ws-server-pmd/protocol_lws_minimal.c b/minimal-examples/minimal-ws-server-pmd/protocol_lws_minimal.c new file mode 100644 index 000000000..87c2df2bb --- /dev/null +++ b/minimal-examples/minimal-ws-server-pmd/protocol_lws_minimal.c @@ -0,0 +1,194 @@ +/* + * ws protocol handler plugin for "lws-minimal" + * + * Copyright (C) 2010-2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This version holds a single message at a time, which may be lost if a new + * message comes. See the minimal-ws-server-ring sample for the same thing + * but using an lws_ring ringbuffer to hold up to 8 messages at a time. + */ + +#if !defined (LWS_PLUGIN_STATIC) +#define LWS_DLL +#define LWS_INTERNAL +#include +#endif + +#include + +/* one of these created for each message */ + +struct msg { + void *payload; /* is malloc'd */ + size_t len; +}; + +/* one of these is created for each client connecting to us */ + +struct per_session_data__minimal { + struct per_session_data__minimal *pss_list; + struct lws *wsi; + int last; /* the last message number we sent */ +}; + +/* one of these is created for each vhost our protocol is used with */ + +struct per_vhost_data__minimal { + struct lws_context *context; + struct lws_vhost *vhost; + const struct lws_protocols *protocol; + + struct per_session_data__minimal *pss_list; /* linked-list of live pss*/ + + struct msg amsg; /* the one pending message... */ + int current; /* the current message number we are caching */ +}; + +/* destroys the message when everyone has had a copy of it */ + +static void +__minimal_destroy_message(void *_msg) +{ + struct msg *msg = _msg; + + free(msg->payload); + msg->payload = NULL; + msg->len = 0; +} + +static int +callback_minimal(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct per_session_data__minimal **ppss, *pss = + (struct per_session_data__minimal *)user; + struct per_vhost_data__minimal *vhd = + (struct per_vhost_data__minimal *) + lws_protocol_vh_priv_get(lws_get_vhost(wsi), + lws_get_protocol(wsi)); + uint32_t oldest; + int n, m; + + switch (reason) { + case LWS_CALLBACK_PROTOCOL_INIT: + vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), + lws_get_protocol(wsi), + sizeof(struct per_vhost_data__minimal)); + vhd->context = lws_get_context(wsi); + vhd->protocol = lws_get_protocol(wsi); + vhd->vhost = lws_get_vhost(wsi); + break; + + case LWS_CALLBACK_ESTABLISHED: + /* add ourselves to the list of live pss held in the vhd */ + pss->pss_list = vhd->pss_list; + vhd->pss_list = pss; + pss->wsi = wsi; + pss->last = vhd->current; + break; + + case LWS_CALLBACK_CLOSED: + /* remove our closing pss from the list of live pss */ + lws_start_foreach_llp(struct per_session_data__minimal **, + ppss, vhd->pss_list) { + if (*ppss == pss) { + *ppss = pss->pss_list; + break; + } + } lws_end_foreach_llp(ppss, pss_list); + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + if (!vhd->amsg.payload) + break; + + if (pss->last == vhd->current) + break; + + /* notice we allowed for LWS_PRE in the payload already */ + m = lws_write(wsi, vhd->amsg.payload + LWS_PRE, vhd->amsg.len, + LWS_WRITE_TEXT); + if (m < vhd->amsg.len) { + lwsl_err("ERROR %d writing to di socket\n", n); + return -1; + } + + pss->last = vhd->current; + break; + + case LWS_CALLBACK_RECEIVE: + if (vhd->amsg.payload) + __minimal_destroy_message(&vhd->amsg); + + vhd->amsg.len = len; + /* notice we over-allocate by LWS_PRE */ + vhd->amsg.payload = malloc(LWS_PRE + len); + if (!vhd->amsg.payload) { + lwsl_user("OOM: dropping\n"); + break; + } + + memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len); + vhd->current++; + + /* + * let everybody know we want to write something on them + * as soon as they are ready + */ + lws_start_foreach_llp(struct per_session_data__minimal **, + ppss, vhd->pss_list) { + lws_callback_on_writable((*ppss)->wsi); + } lws_end_foreach_llp(ppss, pss_list); + break; + + default: + break; + } + + return 0; +} + +#define LWS_PLUGIN_PROTOCOL_MINIMAL \ + { \ + "lws-minimal", \ + callback_minimal, \ + sizeof(struct per_session_data__minimal), \ + 128, \ + 0, NULL, 0 \ + } + +#if !defined (LWS_PLUGIN_STATIC) + +/* boilerplate needed if we are built as a dynamic plugin */ + +static const struct lws_protocols protocols[] = { + LWS_PLUGIN_PROTOCOL_MINIMAL +}; + +LWS_EXTERN LWS_VISIBLE int +init_protocol_minimal(struct lws_context *context, + struct lws_plugin_capability *c) +{ + if (c->api_magic != LWS_PLUGIN_API_MAGIC) { + lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, + c->api_magic); + return 1; + } + + c->protocols = protocols; + c->count_protocols = ARRAY_SIZE(protocols); + c->extensions = NULL; + c->count_extensions = 0; + + return 0; +} + +LWS_EXTERN LWS_VISIBLE int +destroy_protocol_minimal(struct lws_context *context) +{ + return 0; +} +#endif diff --git a/minimal-examples/minimal-ws-server-ring/minimal-ws-server.c b/minimal-examples/minimal-ws-server-ring/minimal-ws-server.c index 77789bbac..dcc805dae 100644 --- a/minimal-examples/minimal-ws-server-ring/minimal-ws-server.c +++ b/minimal-examples/minimal-ws-server-ring/minimal-ws-server.c @@ -6,7 +6,8 @@ * 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. + * This demonstrates the most minimal http server you can make with lws, + * with an added websocket chat server using a ringbuffer. * * To keep it simple, it serves stuff in the directory it was started in. * You can change that by changing mount.origin @@ -14,6 +15,7 @@ #include #include +#include #define LWS_PLUGIN_STATIC #include "protocol_lws_minimal.c" @@ -24,6 +26,8 @@ static struct lws_protocols protocols[] = { { NULL, NULL, 0, 0 } /* terminator */ }; +static int interrupted; + static const struct lws_http_mount mount = { /* .mount_next */ NULL, /* linked-list "next" */ /* .mountpoint */ "/", /* mountpoint URL */ @@ -44,18 +48,27 @@ static const struct lws_http_mount mount = { /* .basic_auth_login_file */ NULL, }; +void sigint_handler(int sig) +{ + interrupted = 1; +} + int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_context *context; int n = 0; + signal(SIGINT, sigint_handler); + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; info.protocols = protocols; - lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER, NULL); + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); + lwsl_user("LWS minimal ws server (lws_ring) | visit http://localhost:7681\n"); context = lws_create_context(&info); @@ -64,7 +77,7 @@ int main(int argc, char **argv) return 1; } - while (n >=0) + while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); diff --git a/minimal-examples/minimal-ws-server/minimal-ws-server.c b/minimal-examples/minimal-ws-server/minimal-ws-server.c index 0f7ef0f91..56245bab4 100644 --- a/minimal-examples/minimal-ws-server/minimal-ws-server.c +++ b/minimal-examples/minimal-ws-server/minimal-ws-server.c @@ -6,7 +6,8 @@ * 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. + * This demonstrates the most minimal http server you can make with lws, + * with an added websocket chat server. * * To keep it simple, it serves stuff in the directory it was started in. * You can change that by changing mount.origin @@ -14,6 +15,7 @@ #include #include +#include #define LWS_PLUGIN_STATIC #include "protocol_lws_minimal.c" @@ -24,6 +26,8 @@ static struct lws_protocols protocols[] = { { NULL, NULL, 0, 0 } /* terminator */ }; +static int interrupted; + static const struct lws_http_mount mount = { /* .mount_next */ NULL, /* linked-list "next" */ /* .mountpoint */ "/", /* mountpoint URL */ @@ -44,18 +48,27 @@ static const struct lws_http_mount mount = { /* .basic_auth_login_file */ NULL, }; +void sigint_handler(int sig) +{ + interrupted = 1; +} + int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_context *context; int n = 0; + signal(SIGINT, sigint_handler); + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; info.protocols = protocols; - lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER, NULL); + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER + /* | LLL_INFO */ /* | LLL_DEBUG */, NULL); + lwsl_user("LWS minimal ws server | visit http://localhost:7681\n"); context = lws_create_context(&info); @@ -64,7 +77,7 @@ int main(int argc, char **argv) return 1; } - while (n >=0) + while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context);