1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

minimal-examples: add ws pmd example

This commit is contained in:
Andy Green 2018-03-06 09:39:27 +08:00
parent 4d36bc1f46
commit 388c0677ee
18 changed files with 928 additions and 20 deletions

View file

@ -1,7 +1,7 @@
/*
* ./lib/extension-permessage-deflate.c
*
* Copyright (C) 2016 Andy Green <andy@warmcat.com>
* Copyright (C) 2016 - 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
@ -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;

View file

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

View file

@ -14,6 +14,9 @@
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
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);

View file

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

View file

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

View file

@ -0,0 +1,87 @@
<meta charset="UTF-8">
<html>
<body>
<img src="libwebsockets.org-logo.png"><br>
LWS bulk transfer example</b>.<br>
A large ws message is sent to all browsers open on this page.<br>
<br>
<span id=status>Ws closed</span><br>
<br>
<textarea id=r readonly cols=40 rows=10></textarea><br>
<input type="text" id=m cols=40 rows=1>
<button id=b onclick="sendmsg();">Send</button>
</body>
<script>
function get_appropriate_ws_url(extra_url)
{
var pcol;
var u = document.URL;
/*
* We open the websocket encrypted if this page came on an
* https:// url itself, otherwise unencrypted
*/
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
/* + "/xxx" bit is for IE10 workaround */
return pcol + u[0] + "/" + extra_url;
}
function new_ws(urlpath, protocol)
{
if (typeof MozWebSocket != "undefined")
return new MozWebSocket(urlpath, protocol);
return new WebSocket(urlpath, protocol);
}
ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-pmd-bulk");
try {
ws.onopen = function() {
document.getElementById("m").disabled = 0;
document.getElementById("b").disabled = 0;
document.getElementById("status").textContent = "ws open "+ ws.extensions;
}
ws.onmessage =function got_packet(msg) {
console.log("Received ws message len " + msg.data.length);
document.getElementById("r").value =
document.getElementById("r").value + msg.data + "\n";
document.getElementById("r").scrollTop =
document.getElementById("r").scrollHeight;
}
ws.onclose = function(){
document.getElementById("m").disabled = 1;
document.getElementById("b").disabled = 1;
document.getElementById("status").textContent = "ws closed";
}
} catch(exception) {
alert('<p>Error' + exception);
}
function sendmsg()
{
ws.send(document.getElementById("m").value);
document.getElementById("m").value = "";
}
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -0,0 +1,98 @@
/*
* lws-minimal-ws-server
*
* 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 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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
#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;
}

View file

@ -0,0 +1,224 @@
/*
* ws protocol handler plugin for "lws-minimal-pmd-bulk"
*
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* 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 <libwebsockets.h>
#endif
#include <string.h>
/*
* 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

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,86 @@
<meta charset="UTF-8">
<html>
<body>
<img src="libwebsockets.org-logo.png"><br>
LWS chat <b>minimal ws server example</b>.<br>
Chat is sent to all browsers open on this page.<br>
<br>
<span id=status>Ws closed</span><br>
<br>
<textarea id=r readonly cols=40 rows=10></textarea><br>
<input type="text" id=m cols=40 rows=1>
<button id=b onclick="sendmsg();">Send</button>
</body>
<script>
function get_appropriate_ws_url(extra_url)
{
var pcol;
var u = document.URL;
/*
* We open the websocket encrypted if this page came on an
* https:// url itself, otherwise unencrypted
*/
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
/* + "/xxx" bit is for IE10 workaround */
return pcol + u[0] + "/" + extra_url;
}
function new_ws(urlpath, protocol)
{
if (typeof MozWebSocket != "undefined")
return new MozWebSocket(urlpath, protocol);
return new WebSocket(urlpath, protocol);
}
ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
try {
ws.onopen = function() {
document.getElementById("m").disabled = 0;
document.getElementById("b").disabled = 0;
document.getElementById("status").textContent = "ws open "+ ws.extensions;
}
ws.onmessage =function got_packet(msg) {
document.getElementById("r").value =
document.getElementById("r").value + msg.data + "\n";
document.getElementById("r").scrollTop =
document.getElementById("r").scrollHeight;
}
ws.onclose = function(){
document.getElementById("m").disabled = 1;
document.getElementById("b").disabled = 1;
document.getElementById("status").textContent = "ws closed";
}
} catch(exception) {
alert('<p>Error' + exception);
}
function sendmsg()
{
ws.send(document.getElementById("m").value);
document.getElementById("m").value = "";
}
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -0,0 +1,97 @@
/*
* lws-minimal-ws-server
*
* 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 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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
#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;
}

View file

@ -0,0 +1,194 @@
/*
* ws protocol handler plugin for "lws-minimal"
*
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* 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 <libwebsockets.h>
#endif
#include <string.h>
/* 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

View file

@ -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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
#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);

View file

@ -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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
#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);