mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00

This gets the libuv stuff plumbed in and working. Currently it's only workable for some service thread, and there is an isolated valgrind problem left ==28425== 128 bytes in 1 blocks are definitely lost in loss record 3 of 3 ==28425== at 0x4C28C50: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==28425== by 0x4C2AB1E: realloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==28425== by 0x58BBB27: maybe_resize (core.c:748) ==28425== by 0x58BBB27: uv__io_start (core.c:787) ==28425== by 0x58C1B80: uv__signal_loop_once_init (signal.c:225) ==28425== by 0x58C1B80: uv_signal_init (signal.c:260) ==28425== by 0x58BF7A6: uv_loop_init (loop.c:66) ==28425== by 0x4157F5: lws_uv_initloop (libuv.c:89) ==28425== by 0x405536: main (test-server-libuv.c:284) libuv wants to sign off on all libuv 'handles' that will close, and callback to do the close confirmation asynchronously. The wsi close function is adapted when libuv is in use to work with libuv accordingly and exit the uv loop the number of remaining wsi is zero. Signed-off-by: Andy Green <andy.green@linaro.org>
367 lines
9.3 KiB
C
367 lines
9.3 KiB
C
/*
|
|
* libwebsockets-test-server - libwebsockets test implementation
|
|
*
|
|
* Copyright (C) 2011-2016 Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*
|
|
* The person who associated a work with this deed has dedicated
|
|
* the work to the public domain by waiving all of his or her rights
|
|
* to the work worldwide under copyright law, including all related
|
|
* and neighboring rights, to the extent allowed by law. You can copy,
|
|
* modify, distribute and perform the work, even for commercial purposes,
|
|
* all without asking permission.
|
|
*
|
|
* The test apps are intended to be adapted for use in your code, which
|
|
* may be proprietary. So unlike the library itself, they are licensed
|
|
* Public Domain.
|
|
*/
|
|
#include "test-server.h"
|
|
|
|
int close_testing;
|
|
int max_poll_elements;
|
|
int debug_level = 7;
|
|
volatile int force_exit = 0;
|
|
struct lws_context *context;
|
|
struct lws_plat_file_ops fops_plat;
|
|
|
|
/* http server gets files from this path */
|
|
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
|
char *resource_path = LOCAL_RESOURCE_PATH;
|
|
|
|
/*
|
|
* libev dumps their hygeine problems on their users blaming compiler
|
|
* http://lists.schmorp.de/pipermail/libev/2008q4/000442.html
|
|
*/
|
|
|
|
#if EV_MINPRI == EV_MAXPRI
|
|
# define _ev_set_priority(ev, pri) ((ev), (pri))
|
|
#else
|
|
# define _ev_set_priority(ev, pri) { \
|
|
ev_watcher *evw = (ev_watcher *)(void *)ev; \
|
|
evw->priority = pri; \
|
|
}
|
|
#endif
|
|
|
|
#define _ev_init(ev,cb_) { \
|
|
ev_watcher *evw = (ev_watcher *)(void *)ev; \
|
|
\
|
|
evw->active = evw->pending = 0; \
|
|
_ev_set_priority((ev), 0); \
|
|
ev_set_cb((ev), cb_); \
|
|
}
|
|
|
|
#define _ev_timer_init(ev, cb, after, _repeat) { \
|
|
ev_watcher_time *evwt = (ev_watcher_time *)(void *)ev; \
|
|
\
|
|
_ev_init(ev, cb); \
|
|
evwt->at = after; \
|
|
(ev)->repeat = _repeat; \
|
|
}
|
|
|
|
/* singlethreaded version --> no locks */
|
|
|
|
void test_server_lock(int care)
|
|
{
|
|
}
|
|
void test_server_unlock(int care)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* This demo server shows how to use libwebsockets for one or more
|
|
* websocket protocols in the same server
|
|
*
|
|
* It defines the following websocket protocols:
|
|
*
|
|
* dumb-increment-protocol: once the socket is opened, an incrementing
|
|
* ascii string is sent down it every 50ms.
|
|
* If you send "reset\n" on the websocket, then
|
|
* the incrementing number is reset to 0.
|
|
*
|
|
* lws-mirror-protocol: copies any received packet to every connection also
|
|
* using this protocol, including the sender
|
|
*/
|
|
|
|
enum demo_protocols {
|
|
/* always first */
|
|
PROTOCOL_HTTP = 0,
|
|
|
|
PROTOCOL_DUMB_INCREMENT,
|
|
PROTOCOL_LWS_MIRROR,
|
|
|
|
/* always last */
|
|
DEMO_PROTOCOL_COUNT
|
|
};
|
|
|
|
/* list of supported protocols and callbacks */
|
|
|
|
static struct lws_protocols protocols[] = {
|
|
/* first protocol must always be HTTP handler */
|
|
|
|
{
|
|
"http-only", /* name */
|
|
callback_http, /* callback */
|
|
sizeof (struct per_session_data__http), /* per_session_data_size */
|
|
0, /* max frame size / rx buffer */
|
|
},
|
|
{
|
|
"dumb-increment-protocol",
|
|
callback_dumb_increment,
|
|
sizeof(struct per_session_data__dumb_increment),
|
|
10,
|
|
},
|
|
{
|
|
"lws-mirror-protocol",
|
|
callback_lws_mirror,
|
|
sizeof(struct per_session_data__lws_mirror),
|
|
128,
|
|
},
|
|
{ NULL, NULL, 0, 0 } /* terminator */
|
|
};
|
|
|
|
static const struct lws_extension exts[] = {
|
|
{
|
|
"permessage-deflate",
|
|
lws_extension_callback_pm_deflate,
|
|
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
|
},
|
|
{
|
|
"deflate-frame",
|
|
lws_extension_callback_pm_deflate,
|
|
"deflate_frame"
|
|
},
|
|
{ NULL, NULL, NULL /* terminator */ }
|
|
};
|
|
|
|
/* this shows how to override the lws file operations. You don't need
|
|
* to do any of this unless you have a reason (eg, want to serve
|
|
* compressed files without decompressing the whole archive)
|
|
*/
|
|
static lws_filefd_type
|
|
test_server_fops_open(struct lws *wsi, const char *filename,
|
|
unsigned long *filelen, int flags)
|
|
{
|
|
lws_filefd_type n;
|
|
|
|
/* call through to original platform implementation */
|
|
n = fops_plat.open(wsi, filename, filelen, flags);
|
|
|
|
lwsl_notice("%s: opening %s, ret %ld, len %lu\n", __func__, filename,
|
|
(long)n, *filelen);
|
|
|
|
return n;
|
|
}
|
|
|
|
void signal_cb(struct ev_loop *loop, struct ev_signal* watcher, int revents)
|
|
{
|
|
lwsl_notice("Signal caught, exiting...\n");
|
|
force_exit = 1;
|
|
switch (watcher->signum) {
|
|
case SIGTERM:
|
|
case SIGINT:
|
|
ev_break(loop, EVBREAK_ALL);
|
|
break;
|
|
default:
|
|
signal(SIGABRT, SIG_DFL);
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ev_timeout_cb (EV_P_ ev_timer *w, int revents)
|
|
{
|
|
lws_callback_on_writable_all_protocol(context,
|
|
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
|
}
|
|
|
|
static struct option options[] = {
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "debug", required_argument, NULL, 'd' },
|
|
{ "port", required_argument, NULL, 'p' },
|
|
{ "ssl", no_argument, NULL, 's' },
|
|
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
|
{ "interface", required_argument, NULL, 'i' },
|
|
{ "closetest", no_argument, NULL, 'c' },
|
|
{ "libev", no_argument, NULL, 'e' },
|
|
#ifndef LWS_NO_DAEMONIZE
|
|
{ "daemonize", no_argument, NULL, 'D' },
|
|
#endif
|
|
{ "resource_path", required_argument, NULL, 'r' },
|
|
{ NULL, 0, 0, 0 }
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
|
|
struct ev_signal signals[ARRAY_SIZE(sigs)];
|
|
struct ev_loop *loop = ev_default_loop(0);
|
|
struct lws_context_creation_info info;
|
|
char interface_name[128] = "";
|
|
const char *iface = NULL;
|
|
ev_timer timeout_watcher;
|
|
char cert_path[1024];
|
|
char key_path[1024];
|
|
int use_ssl = 0;
|
|
int opts = 0;
|
|
int n = 0;
|
|
#ifndef _WIN32
|
|
int syslog_options = LOG_PID | LOG_PERROR;
|
|
#endif
|
|
#ifndef LWS_NO_DAEMONIZE
|
|
int daemonize = 0;
|
|
#endif
|
|
|
|
/*
|
|
* take care to zero down the info struct, he contains random garbaage
|
|
* from the stack otherwise
|
|
*/
|
|
memset(&info, 0, sizeof info);
|
|
info.port = 7681;
|
|
|
|
while (n >= 0) {
|
|
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
|
if (n < 0)
|
|
continue;
|
|
switch (n) {
|
|
case 'e':
|
|
opts |= LWS_SERVER_OPTION_LIBEV;
|
|
break;
|
|
#ifndef LWS_NO_DAEMONIZE
|
|
case 'D':
|
|
daemonize = 1;
|
|
#ifndef _WIN32
|
|
syslog_options &= ~LOG_PERROR;
|
|
#endif
|
|
break;
|
|
#endif
|
|
case 'd':
|
|
debug_level = atoi(optarg);
|
|
break;
|
|
case 's':
|
|
use_ssl = 1;
|
|
break;
|
|
case 'a':
|
|
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
|
break;
|
|
case 'p':
|
|
info.port = atoi(optarg);
|
|
break;
|
|
case 'i':
|
|
strncpy(interface_name, optarg, sizeof interface_name);
|
|
interface_name[(sizeof interface_name) - 1] = '\0';
|
|
iface = interface_name;
|
|
break;
|
|
case 'c':
|
|
close_testing = 1;
|
|
fprintf(stderr, " Close testing mode -- closes on "
|
|
"client after 50 dumb increments"
|
|
"and suppresses lws_mirror spam\n");
|
|
break;
|
|
case 'r':
|
|
resource_path = optarg;
|
|
printf("Setting resource path to \"%s\"\n", resource_path);
|
|
break;
|
|
case 'h':
|
|
fprintf(stderr, "Usage: test-server "
|
|
"[--port=<p>] [--ssl] "
|
|
"[-d <log bitfield>] "
|
|
"[--resource_path <path>]\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
|
/*
|
|
* normally lock path would be /var/lock/lwsts or similar, to
|
|
* simplify getting started without having to take care about
|
|
* permissions or running as root, set to /tmp/.lwsts-lock
|
|
*/
|
|
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
|
fprintf(stderr, "Failed to daemonize\n");
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
|
|
_ev_init(&signals[n], signal_cb);
|
|
ev_signal_set(&signals[n], sigs[n]);
|
|
ev_signal_start(loop, &signals[n]);
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
/* we will only try to log things according to our debug_level */
|
|
setlogmask(LOG_UPTO (LOG_DEBUG));
|
|
openlog("lwsts", syslog_options, LOG_DAEMON);
|
|
#endif
|
|
|
|
/* tell the library what debug level to emit and to send it to syslog */
|
|
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
|
|
|
lwsl_notice("libwebsockets test server libev - license LGPL2.1+SLE\n");
|
|
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
|
|
|
|
printf("Using resource path \"%s\"\n", resource_path);
|
|
|
|
info.iface = iface;
|
|
info.protocols = protocols;
|
|
info.extensions = exts;
|
|
|
|
info.ssl_cert_filepath = NULL;
|
|
info.ssl_private_key_filepath = NULL;
|
|
|
|
if (use_ssl) {
|
|
if (strlen(resource_path) > sizeof(cert_path) - 32) {
|
|
lwsl_err("resource path too long\n");
|
|
return -1;
|
|
}
|
|
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
|
|
resource_path);
|
|
if (strlen(resource_path) > sizeof(key_path) - 32) {
|
|
lwsl_err("resource path too long\n");
|
|
return -1;
|
|
}
|
|
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
|
|
resource_path);
|
|
|
|
info.ssl_cert_filepath = cert_path;
|
|
info.ssl_private_key_filepath = key_path;
|
|
}
|
|
info.gid = -1;
|
|
info.uid = -1;
|
|
info.max_http_header_pool = 1;
|
|
info.options = opts | LWS_SERVER_OPTION_LIBEV;
|
|
|
|
context = lws_create_context(&info);
|
|
if (context == NULL) {
|
|
lwsl_err("libwebsocket init failed\n");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* this shows how to override the lws file operations. You don't need
|
|
* to do any of this unless you have a reason (eg, want to serve
|
|
* compressed files without decompressing the whole archive)
|
|
*/
|
|
/* stash original platform fops */
|
|
fops_plat = *(lws_get_fops(context));
|
|
/* override the active fops */
|
|
lws_get_fops(context)->open = test_server_fops_open;
|
|
|
|
lws_ev_initloop(context, loop, 0);
|
|
|
|
_ev_timer_init(&timeout_watcher, ev_timeout_cb, 0.05, 0.05);
|
|
ev_timer_start(loop, &timeout_watcher);
|
|
ev_run(loop, 0);
|
|
|
|
lws_context_destroy(context);
|
|
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
|
|
|
#ifndef _WIN32
|
|
closelog();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|