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

minimal-examples: http server

This commit is contained in:
Andy Green 2018-03-04 09:39:45 +08:00
parent d39ecd814a
commit cce9711653
25 changed files with 1090 additions and 3 deletions

View file

@ -1276,7 +1276,7 @@ LWS_EXTERN void lws_feature_status_libuv(struct lws_context_creation_info *info)
#define LWS_LIBUV_ENABLED(context) (0)
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
#define lws_feature_status_libuv(_a) \
lwsl_notice("libuv support not compiled in\n")
lwsl_info("libuv support not compiled in\n")
#else
#define lws_feature_status_libuv(_a)
#endif
@ -1307,7 +1307,7 @@ LWS_EXTERN void lws_feature_status_libevent(struct lws_context_creation_info *in
#define LWS_LIBEVENT_ENABLED(context) (0)
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
#define lws_feature_status_libevent(_a) \
lwsl_notice("libevent support not compiled in\n")
lwsl_info("libevent support not compiled in\n")
#else
#define lws_feature_status_libevent(_a)
#endif

View file

@ -1491,7 +1491,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
lws_handle_POLLOUT_event(wsi, pollfd)) {
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
wsi->state = LWSS_FLUSHING_SEND_BEFORE_CLOSE;
lwsl_notice("lws_service_fd: closing\n");
// lwsl_notice("lws_service_fd: closing\n");
/* the write failed... it's had it */
wsi->socket_is_permanently_unusable = 1;
goto close_and_handled;

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.8)
project(lws-minimal-http-client C)
set(SAMP lws-minimal-http-client)
set(SRCS minimal-http-client.c)
add_executable(${SAMP} ${SRCS})
target_link_libraries(${SAMP} -lwebsockets)

View file

@ -0,0 +1,52 @@
# lws minimal http client
## build
```
$ cmake . && make
```
## usage
The application goes to https://warmcat.com and receives the page data.
```
$ ./lws-minimal-http-client
[2018/03/04 14:43:20:8562] USER: LWS minimal http client
[2018/03/04 14:43:20:8571] NOTICE: Creating Vhost 'default' port -1, 1 protocols, IPv6 on
[2018/03/04 14:43:20:8616] NOTICE: created client ssl context for default
[2018/03/04 14:43:20:8617] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
[2018/03/04 14:43:21:1496] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: incoming content length 26520
[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: client connection up
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 974
[2018/03/04 14:43:22:3022] NOTICE: lws_http_client_read: transaction completed says -1
[2018/03/04 14:43:23:3042] USER: Completed
```

View file

@ -0,0 +1,123 @@
/*
* lws-minimal-http-client
*
* 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 a minimal http client using lws.
*
* It visits https://warmcat.com/ and receives the html page there. You
* can dump the page data by changing the #if 0 below.
*/
#include <libwebsockets.h>
#include <string.h>
static struct lws *client_wsi;
static int
callback_http(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
const char *p = in;
switch (reason) {
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
in ? (char *)in : "(null)");
client_wsi = NULL;
break;
/* chunks of chunked content, with header removed */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
#if 0 /* enable to dump the html */
while (len--)
if (*p < 0x7f)
putchar(*p++);
else
putchar('.');
#endif
return 0; /* don't passthru */
/* uninterpreted http content */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
{
char buffer[1024 + LWS_PRE];
char *px = buffer + LWS_PRE;
int lenx = sizeof(buffer) - LWS_PRE;
if (lws_http_client_read(wsi, &px, &lenx) < 0)
return -1;
}
return 0; /* don't passthru */
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
client_wsi = NULL;
break;
default:
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
static const struct lws_protocols protocols[] = {
{
"http",
callback_http,
0,
0,
},
{ NULL, NULL, 0, 0 }
};
int main(int argc, char **argv)
{
struct lws_context_creation_info info;
struct lws_client_connect_info i;
struct lws_context *context;
int n = 0;
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER, NULL);
lwsl_user("LWS minimal http client\n");
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
i.context = context;
i.port = 443;
i.address = "warmcat.com";
i.path = "/";
i.host = i.address;
i.origin = i.address;
i.ssl_connection = 1;
i.method = "GET";
i.protocol = protocols[0].name;
i.pwsi = &client_wsi;
lws_client_connect_via_info(&i);
while (n >= 0 && client_wsi)
n = lws_service(context, 1000);
lws_context_destroy(context);
lwsl_user("Completed\n");
return 0;
}

View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.8)
project(lws-minimal-http-server C)
set(SAMP lws-minimal-http-server)
set(SRCS minimal-http-server.c)
add_executable(${SAMP} ${SRCS})
target_link_libraries(${SAMP} -lwebsockets)

View file

@ -0,0 +1,18 @@
# lws minimal http server
## build
```
$ cmake . && make
```
## usage
```
$ ./lws-minimal-http-server
[2018/03/04 09:30:02:7986] USER: LWS minimal http 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,9 @@
<meta charset="UTF-8">
<html>
<body>
<img src="libwebsockets.org-logo.png"><br>
Hello from the <b>minimal http server example</b>.
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

@ -0,0 +1,63 @@
/*
* lws-minimal-http-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>
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,
};
int main(int argc, char **argv)
{
struct lws_context_creation_info info;
struct lws_context *context;
int n = 0;
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);
lwsl_user("LWS minimal http server | visit http://localhost:7681\n");
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
while (n >=0)
n = lws_service(context, 1000);
lws_context_destroy(context);
return 0;
}

View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8)
project(lws-minimal-ws-server C)
set(SAMP lws-minimal-ws-server)
set(SRCS minimal-ws-server.c)
add_executable(${SAMP} ${SRCS})
target_link_libraries(${SAMP} -lwebsockets)

View file

@ -0,0 +1,21 @@
# lws minimal ws server (lws_ring)
## build
```
$ cmake . && make
```
## usage
```
$ ./lws-minimal-ws-server
[2018/03/04 09:30:02:7986] USER: LWS minimal ws server (lws_ring) | 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.
A ringbuffer holds up to 8 lines of text.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,84 @@
<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>
<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;
}
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;
}
} 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,73 @@
/*
* 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>
#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 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,
};
int main(int argc, char **argv)
{
struct lws_context_creation_info info;
struct lws_context *context;
int n = 0;
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);
lwsl_user("LWS minimal ws server (lws_ring) | visit http://localhost:7681\n");
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
while (n >=0)
n = lws_service(context, 1000);
lws_context_destroy(context);
return 0;
}

View file

@ -0,0 +1,235 @@
/*
* 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 uses an lws_ring ringbuffer to cache up to 8 messages at a time,
* so it's not so easy to lose messages.
*/
#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;
uint32_t tail;
};
/* 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 lws_ring *ring; /* ringbuffer holding unsent messages */
};
/* 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));
const struct msg *pmsg;
struct msg amsg;
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);
vhd->ring = lws_ring_create(sizeof(struct msg), 8,
__minimal_destroy_message);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
lws_ring_destroy(vhd->ring);
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->tail = lws_ring_get_oldest_tail(vhd->ring);
pss->wsi = 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 **,
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:
pmsg = lws_ring_get_element(vhd->ring, &pss->tail);
if (!pmsg)
break;
/* notice we allowed for LWS_PRE in the payload already */
m = lws_write(wsi, pmsg->payload + LWS_PRE, pmsg->len,
LWS_WRITE_TEXT);
if (m < pmsg->len) {
lwsl_err("ERROR %d writing to di socket\n", n);
return -1;
}
n = lws_ring_get_oldest_tail(vhd->ring) == pss->tail;
lws_ring_consume(vhd->ring, &pss->tail, NULL, 1);
if (n) { /* we may have been the oldest tail */
n = 0;
oldest = pss->tail;
lws_start_foreach_llp(
struct per_session_data__minimal **,
ppss, vhd->pss_list) {
m = lws_ring_get_count_waiting_elements(
vhd->ring, &(*ppss)->tail);
if (m > n) {
n = m;
oldest = (*ppss)->tail;
}
} lws_end_foreach_llp(ppss, pss_list);
/* this will delete any entries behind the new oldest */
lws_ring_update_oldest_tail(vhd->ring, oldest);
}
/* more to do? */
if (lws_ring_get_element(vhd->ring, &pss->tail))
/* come back as soon as we can write more */
lws_callback_on_writable((*ppss)->wsi);
break;
case LWS_CALLBACK_RECEIVE:
n = (int)lws_ring_get_count_free_elements(vhd->ring);
if (!n) {
lwsl_user("dropping!\n");
break;
}
amsg.len = len;
/* notice we over-allocate by LWS_PRE */
amsg.payload = malloc(LWS_PRE + len);
if (!amsg.payload) {
lwsl_user("OOM: dropping\n");
break;
}
memcpy((char *)amsg.payload + LWS_PRE, in, len);
if (!lws_ring_insert(vhd->ring, &amsg, 1)) {
__minimal_destroy_message(&amsg);
lwsl_user("dropping!\n");
break;
}
/*
* 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;
case LWS_CALLBACK_TIMER:
lwsl_notice("%s: LWS_CALLBACK_TIMER\n", __func__);
lws_set_timer(wsi, 3);
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

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8)
project(lws-minimal-ws-server C)
set(SAMP lws-minimal-ws-server)
set(SRCS minimal-ws-server.c)
add_executable(${SAMP} ${SRCS})
target_link_libraries(${SAMP} -lwebsockets)

View file

@ -0,0 +1,21 @@
# lws minimal ws server
## 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,83 @@
<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>
<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;
}
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;
}
} 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,73 @@
/*
* 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>
#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 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,
};
int main(int argc, char **argv)
{
struct lws_context_creation_info info;
struct lws_context *context;
int n = 0;
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);
lwsl_user("LWS minimal ws server | visit http://localhost:7681\n");
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
while (n >=0)
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