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

refactor: clean out test-apps

This commit is contained in:
Andy Green 2018-04-28 14:11:39 +08:00
parent 8d213f8295
commit d05b408cde
13 changed files with 422 additions and 2010 deletions

View file

@ -1611,8 +1611,8 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
#
if (NOT LWS_WITHOUT_TEST_SERVER)
create_test_app(test-server "test-apps/test-server.c"
"test-apps/test-server-http.c"
"test-apps/test-server-dumb-increment.c"
""
""
""
""
"")
@ -1640,8 +1640,8 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
AND LWS_WITH_LIBEV)
create_test_app(test-server-libev
"test-apps/test-server-libev.c"
"test-apps/test-server-http.c"
"test-apps/test-server-dumb-increment.c"
""
""
""
""
"")
@ -1654,7 +1654,7 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
AND LWS_WITH_LIBUV)
create_test_app(test-server-libuv
"test-apps/test-server-libuv.c"
"test-apps/test-server-http.c"
""
""
""
""
@ -1664,8 +1664,8 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
AND LWS_WITH_LIBEVENT)
create_test_app(test-server-libevent
"test-apps/test-server-libevent.c"
"test-apps/test-server-http.c"
"test-apps/test-server-dumb-increment.c"
""
""
""
""
"")
@ -1676,9 +1676,10 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
# test-server-extpoll
#
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL)
create_test_app(test-server-extpoll "test-apps/test-server.c"
"test-apps/test-server-http.c"
"test-apps/test-server-dumb-increment.c"
create_test_app(test-server-extpoll
"test-apps/test-server.c"
""
""
""
""
"")
@ -1755,13 +1756,6 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
create_test_app(test-client "test-apps/test-client.c" "" "" "" "" "")
endif()
#
# test-ping
#
if (NOT LWS_WITHOUT_TEST_PING AND NOT LWS_WITHOUT_SERVER AND NOT LWS_WITHOUT_CLIENT)
create_test_app(test-ping "test-apps/test-ping.c" "" "" "" "" "")
endif()
endif(NOT LWS_WITHOUT_CLIENT)

View file

@ -501,7 +501,7 @@ drain_extension:
#else
n = 0;
#endif
lwsl_notice("post inflate ebuf len %d\n", ebuf.len);
lwsl_debug("post inflate ebuf len %d\n", ebuf.len);
if (rx_draining_ext && !ebuf.len) {
lwsl_debug(" --- ending drain on 0 read result\n");

View file

@ -1,7 +1,7 @@
/*
* ws protocol handler plugin for "dumb increment"
*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
* 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.
@ -26,79 +26,51 @@
#include <string.h>
#define DUMB_PERIOD 50
#define DUMB_PERIOD_US 50000
struct per_vhost_data__dumb_increment {
uv_timer_t timeout_watcher;
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
};
struct per_session_data__dumb_increment {
struct pss__dumb_increment {
int number;
};
static void
uv_timeout_cb_dumb_increment(uv_timer_t *w
#if UV_VERSION_MAJOR == 0
, int status
#endif
)
{
struct per_vhost_data__dumb_increment *vhd = lws_container_of(w,
struct per_vhost_data__dumb_increment, timeout_watcher);
lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
}
struct vhd__dumb_increment {
const unsigned int *options;
};
static int
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__dumb_increment *pss =
(struct per_session_data__dumb_increment *)user;
struct per_vhost_data__dumb_increment *vhd =
(struct per_vhost_data__dumb_increment *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
unsigned char buf[LWS_PRE + 20];
unsigned char *p = &buf[LWS_PRE];
struct pss__dumb_increment *pss = (struct pss__dumb_increment *)user;
struct vhd__dumb_increment *vhd =
(struct vhd__dumb_increment *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
uint8_t buf[LWS_PRE + 20], *p = &buf[LWS_PRE];
const struct lws_protocol_vhost_options *opt;
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__dumb_increment));
vhd->context = lws_get_context(wsi);
vhd->protocol = lws_get_protocol(wsi);
vhd->vhost = lws_get_vhost(wsi);
uv_timer_init(lws_uv_getloop(vhd->context, 0),
&vhd->timeout_watcher);
lws_libuv_static_refcount_add((uv_handle_t *)&vhd->timeout_watcher,
vhd->context);
uv_timer_start(&vhd->timeout_watcher,
uv_timeout_cb_dumb_increment, DUMB_PERIOD, DUMB_PERIOD);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
lws_get_protocol(wsi),
sizeof(struct vhd__dumb_increment));
if (!vhd)
break;
lwsl_notice("di: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
uv_timer_stop(&vhd->timeout_watcher);
uv_close((uv_handle_t *)&vhd->timeout_watcher,
lws_libuv_static_refcount_del);
return -1;
if ((opt = lws_pvo_search(
(const struct lws_protocol_vhost_options *)in,
"options")))
vhd->options = (unsigned int *)opt->value;
break;
case LWS_CALLBACK_ESTABLISHED:
pss->number = 0;
lws_set_timer_usecs(wsi, 3 * LWS_USEC_PER_SEC);
if (!vhd->options || !((*vhd->options) & 1))
lws_set_timer_usecs(wsi, DUMB_PERIOD_US);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%d", pss->number++);
n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%d",
pss->number++);
m = lws_write(wsi, p, n, LWS_WRITE_TEXT);
if (m < n) {
lwsl_err("ERROR %d writing to di socket\n", n);
@ -120,8 +92,11 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
break;
case LWS_CALLBACK_TIMER:
lwsl_info("%s: LWS_CALLBACK_TIMER: %p\n", __func__, wsi);
lws_set_timer_usecs(wsi, 3 * LWS_USEC_PER_SEC);
if (!vhd->options || !((*vhd->options) & 1)) {
lws_callback_on_writable_all_protocol_vhost(
lws_get_vhost(wsi), lws_get_protocol(wsi));
lws_set_timer_usecs(wsi, DUMB_PERIOD_US);
}
break;
default:
@ -135,7 +110,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
{ \
"dumb-increment-protocol", \
callback_dumb_increment, \
sizeof(struct per_session_data__dumb_increment), \
sizeof(struct pss__dumb_increment), \
10, /* rx buf size must be >= permessage-deflate rx size */ \
0, NULL, 0 \
}

View file

@ -206,7 +206,6 @@ walk_final:
case LWS_CALLBACK_RECEIVE:
lwsl_notice("pmd test: RX len %d\n", (int)len);
puts(in);
break;
case LWS_CALLBACK_CLOSED:

View file

@ -1,570 +0,0 @@
/*
* libwebsockets-test-ping - libwebsockets test floodping
*
* 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 <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include "../lib/libwebsockets.h"
#ifndef _WIN32
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <unistd.h>
#else
#include "gettimeofday.h"
#endif
#ifdef __ANDROID__
#include <termiosh>
#endif
#ifdef __sun
#include <sys/termios.h>
#endif
/*
* this is specified in the 04 standard, control frames can only have small
* payload length styles
*/
#define MAX_PING_PAYLOAD 125
#define MAX_MIRROR_PAYLOAD 4096
#define MAX_PING_CLIENTS 256
#define PING_RINGBUFFER_SIZE 256
static struct lws *ping_wsi[MAX_PING_CLIENTS];
static unsigned int interval_us = 1000000;
static unsigned int size = 64;
static int flood;
static const char *address;
static unsigned char pingbuf[LWS_PRE + MAX_MIRROR_PAYLOAD];
static char peer_name[128];
static unsigned long started;
static int screen_width = 80;
static int use_mirror;
static unsigned int write_options;
static unsigned long rtt_min = 100000000;
static unsigned long rtt_max;
static unsigned long rtt_avg;
static unsigned long global_rx_count;
static unsigned long global_tx_count;
static int clients = 1;
static unsigned long interrupted_time;
struct ping {
unsigned long issue_timestamp;
unsigned long index;
unsigned int seen;
};
struct per_session_data__ping {
unsigned long long ping_index;
struct ping ringbuffer[PING_RINGBUFFER_SIZE];
int ringbuffer_head;
int ringbuffer_tail;
unsigned long rx_count;
};
/*
* uses the ping pong protocol features to provide an equivalent for the
* ping utility for 04+ websockets
*/
enum demo_protocols {
PROTOCOL_LWS_MIRROR,
/* always last */
DEMO_PROTOCOL_COUNT
};
static int
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__ping *psd = user;
struct timeval tv;
unsigned char *p;
unsigned long iv;
int match = 0;
unsigned long long l;
int shift;
int n;
switch (reason) {
case LWS_CALLBACK_CLOSED:
fprintf(stderr, "LWS_CALLBACK_CLOSED on %p\n", (void *)wsi);
/* remove closed guy */
for (n = 0; n < clients; n++)
if (ping_wsi[n] == wsi) {
clients--;
while (n < clients) {
ping_wsi[n] = ping_wsi[n + 1];
n++;
}
}
break;
case LWS_CALLBACK_CLIENT_ESTABLISHED:
psd->rx_count = 0;
psd->ping_index = 1;
psd->ringbuffer_head = 0;
psd->ringbuffer_tail = 0;
/*
* start the ball rolling,
* LWS_CALLBACK_CLIENT_WRITEABLE will come next service
*/
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
gettimeofday(&tv, NULL);
iv = (tv.tv_sec * 1000000) + tv.tv_usec;
psd->rx_count++;
shift = 56;
p = in;
l = 0;
while (shift >= 0) {
l |= ((lws_intptr_t)*p++) << shift;
shift -= 8;
}
/* find it in the ringbuffer, look backwards from head */
n = psd->ringbuffer_head;
while (!match) {
if (psd->ringbuffer[n].index == l) {
psd->ringbuffer[n].seen++;
match = 1;
continue;
}
if (n == psd->ringbuffer_tail) {
match = -1;
continue;
}
if (n == 0)
n = PING_RINGBUFFER_SIZE - 1;
else
n--;
}
if (match < 1) {
if (!flood)
fprintf(stderr, "%d bytes from %s: req=%ld "
"time=(unknown)\n", (int)len, address,
(long)l);
else
fprintf(stderr, "\b \b");
break;
}
if (psd->ringbuffer[n].seen > 1)
fprintf(stderr, "DUP! ");
if ((iv - psd->ringbuffer[n].issue_timestamp) < rtt_min)
rtt_min = iv - psd->ringbuffer[n].issue_timestamp;
if ((iv - psd->ringbuffer[n].issue_timestamp) > rtt_max)
rtt_max = iv - psd->ringbuffer[n].issue_timestamp;
rtt_avg += iv - psd->ringbuffer[n].issue_timestamp;
global_rx_count++;
if (!flood)
fprintf(stderr, "%d bytes from %s: req=%ld "
"time=%lu.%lums\n", (int)len, address, (long)l,
(iv - psd->ringbuffer[n].issue_timestamp) / 1000,
((iv - psd->ringbuffer[n].issue_timestamp) / 100) % 10);
else
fprintf(stderr, "\b \b");
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
shift = 56;
p = &pingbuf[LWS_PRE];
/* 64-bit ping index in network byte order */
while (shift >= 0) {
*p++ = (unsigned char)(psd->ping_index >> shift);
shift -= 8;
}
while ((unsigned int)(p - &pingbuf[LWS_PRE]) < size)
*p++ = 0;
gettimeofday(&tv, NULL);
psd->ringbuffer[psd->ringbuffer_head].issue_timestamp =
(tv.tv_sec * 1000000) + tv.tv_usec;
psd->ringbuffer[psd->ringbuffer_head].index = (unsigned long)psd->ping_index++;
psd->ringbuffer[psd->ringbuffer_head].seen = 0;
if (psd->ringbuffer_head == PING_RINGBUFFER_SIZE - 1)
psd->ringbuffer_head = 0;
else
psd->ringbuffer_head++;
/* snip any re-used tail so we keep to the ring length */
if (psd->ringbuffer_tail == psd->ringbuffer_head) {
if (psd->ringbuffer_tail == PING_RINGBUFFER_SIZE - 1)
psd->ringbuffer_tail = 0;
else
psd->ringbuffer_tail++;
}
global_tx_count++;
if (use_mirror)
n = lws_write(wsi,
&pingbuf[LWS_PRE],
size, write_options | LWS_WRITE_BINARY);
else
n = lws_write(wsi,
&pingbuf[LWS_PRE],
size, write_options | LWS_WRITE_PING);
if (n < 0)
return -1;
if (n < (int)size) {
lwsl_err("Partial write\n");
return -1;
}
if (flood &&
(int)(psd->ping_index - psd->rx_count) < (screen_width - 1))
fprintf(stderr, ".");
break;
default:
break;
}
return 0;
}
/* list of supported protocols and callbacks */
static struct lws_protocols protocols[] = {
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof (struct per_session_data__ping),
},
{
NULL, NULL, 0/* end of list */
}
};
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 */ }
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 't' },
{ "interval", required_argument, NULL, 'i' },
{ "size", required_argument, NULL, 's' },
{ "protocol", required_argument, NULL, 'n' },
{ "flood", no_argument, NULL, 'f' },
{ "mirror", no_argument, NULL, 'm' },
{ "replicate", required_argument, NULL, 'r' },
{ "killmask", no_argument, NULL, 'k' },
{ "version", required_argument, NULL, 'v' },
{ NULL, 0, 0, 0 }
};
#ifndef _WIN32
static void
signal_handler(int sig, siginfo_t *si, void *v)
{
struct timeval tv;
gettimeofday(&tv, NULL);
interrupted_time = (tv.tv_sec * 1000000) + tv.tv_usec;
}
#endif
int main(int argc, char **argv)
{
int n = 0;
int port = 7681;
int use_ssl = 0;
struct lws_context *context;
char protocol_name[256], ads_port[300];
char ip[30];
#ifndef _WIN32
struct sigaction sa;
struct winsize w;
#endif
struct timeval tv;
unsigned long oldus = 0;
unsigned long l;
int ietf_version = -1;
struct lws_context_creation_info info;
struct lws_client_connect_info i;
memset(&info, 0, sizeof info);
if (argc < 2)
goto usage;
while (n >= 0) {
n = getopt_long(argc, argv, "v:kr:hmfts:n:i:p:d:", options, NULL);
if (n < 0)
continue;
switch (n) {
case 'd':
lws_set_log_level(atoi(optarg), NULL);
break;
case 'm':
use_mirror = 1;
break;
case 't':
use_ssl = 2; /* 2 = allow selfsigned */
break;
case 'p':
port = atoi(optarg);
break;
case 'n':
lws_strncpy(protocol_name, optarg, sizeof protocol_name);
protocols[PROTOCOL_LWS_MIRROR].name = protocol_name;
break;
case 'i':
interval_us = (unsigned int)(1000000.0 * atof(optarg));
break;
case 's':
size = atoi(optarg);
break;
case 'f':
flood = 1;
break;
case 'r':
clients = atoi(optarg);
if (clients > MAX_PING_CLIENTS || clients < 1) {
fprintf(stderr, "Max clients supported = %d\n",
MAX_PING_CLIENTS);
return 1;
}
break;
case 'k':
write_options = LWS_WRITE_CLIENT_IGNORE_XOR_MASK;
break;
case 'v':
ietf_version = atoi(optarg);
break;
case 'h':
goto usage;
}
}
if (!use_mirror) {
if (size > MAX_PING_PAYLOAD) {
fprintf(stderr, "Max ping opcode payload size %d\n",
MAX_PING_PAYLOAD);
return 1;
}
} else {
if (size > MAX_MIRROR_PAYLOAD) {
fprintf(stderr, "Max mirror payload size %d\n",
MAX_MIRROR_PAYLOAD);
return 1;
}
}
#ifndef _WIN32
if (isatty(STDOUT_FILENO))
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
if (w.ws_col > 0)
screen_width = w.ws_col;
#endif
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
info.extensions = exts;
info.gid = -1;
info.uid = -1;
if (use_ssl)
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
context = lws_create_context(&info);
if (context == NULL) {
fprintf(stderr, "Creating libwebsocket context failed\n");
return 1;
}
/* create client websockets using dumb increment protocol */
address = argv[optind];
lws_snprintf(ads_port, sizeof(ads_port), "%s:%u",
address, port & 65535);
lwsl_notice("Connecting to %s...\n", ads_port);
memset(&i, 0, sizeof(i));
i.context = context;
i.address = address;
i.port = port;
i.ssl_connection = use_ssl;
i.path = "/";
i.host = ads_port;
i.origin = ads_port;
i.protocol = protocols[PROTOCOL_LWS_MIRROR].name;
i.ietf_version_or_minus_one = ietf_version;
for (n = 0; n < clients; n++) {
ping_wsi[n] = lws_client_connect_via_info(&i);
if (ping_wsi[n] == NULL) {
lwsl_err("client %d failed to connect\n", n);
return 1;
}
}
lws_get_peer_addresses(ping_wsi[0], lws_get_socket_fd(ping_wsi[0]),
peer_name, sizeof peer_name, ip, sizeof ip);
lwsl_notice("libwebsockets test server ping - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
fprintf(stderr, "Websocket PING %s (%s) %d bytes of data.\n",
peer_name, ip, size);
#ifndef _WIN32
/* set the ^C handler */
sa.sa_sigaction = signal_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
#endif
gettimeofday(&tv, NULL);
started = (tv.tv_sec * 1000000) + tv.tv_usec;
/* service loop */
n = 0;
while (n >= 0) {
gettimeofday(&tv, NULL);
l = (tv.tv_sec * 1000000) + tv.tv_usec;
/* servers can hang up on us */
if (clients == 0) {
n = -1;
continue;
}
if (!interrupted_time) {
if ((l - oldus) > interval_us) {
for (n = 0; n < clients; n++)
lws_callback_on_writable(ping_wsi[n]);
oldus = l;
}
} else
/* allow time for in-flight pongs to come */
if ((l - interrupted_time) > 250000) {
n = -1;
continue;
}
if (!interval_us)
n = lws_service(context, 0);
else
n = lws_service(context, 1);
}
/* stats */
if (global_rx_count && global_tx_count)
fprintf(stderr, "\n--- %s websocket ping statistics "
"using %d connections ---\n"
"%lu packets transmitted, %lu received, "
"%lu%% packet loss, time %ldms\n"
"rtt min/avg/max = %0.3f/%0.3f/%0.3f ms\n"
"payload bandwidth average %0.3f KiBytes/sec\n",
peer_name, clients, global_tx_count, global_rx_count,
((global_tx_count - global_rx_count) * 100) / global_tx_count,
(l - started) / 1000,
((double)rtt_min) / 1000.0,
((double)rtt_avg / global_rx_count) / 1000.0,
((double)rtt_max) / 1000.0,
((double)global_rx_count * (double)size) /
((double)(l - started) / 1000000.0) / 1024.0);
lws_context_destroy(context);
return 0;
usage:
fprintf(stderr, "Usage: libwebsockets-test-ping "
"<server address> [--port=<p>] "
"[--ssl] [--interval=<float sec>] "
"[--size=<bytes>] "
"[--protocol=<protocolname>] "
"[--mirror] "
"[--replicate=clients>] "
"[--version <version>] "
"[-d <log bitfield> ]"
"\n");
return 1;
}

View file

@ -1,106 +0,0 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2010-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"
#if defined(LWS_ROLE_WS)
/* dumb_increment protocol */
int
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
unsigned char buf[LWS_PRE + 512];
struct per_session_data__dumb_increment *pss =
(struct per_session_data__dumb_increment *)user;
unsigned char *p = &buf[LWS_PRE];
int n, m;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
pss->number = 0;
/* just to test the timer api */
lws_set_timer_usecs(wsi, 3 * LWS_USEC_PER_SEC);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
n = sprintf((char *)p, "%d", pss->number++);
m = lws_write(wsi, p, n, LWS_WRITE_TEXT);
if (m < n) {
lwsl_err("ERROR %d writing to di socket\n", n);
return -1;
}
if (close_testing && pss->number == 50) {
lwsl_info("close tesing limit, closing\n");
return -1;
}
break;
case LWS_CALLBACK_RECEIVE:
// if (len < 6)
// break;
lwsl_hexdump_notice(in, len);
if (strncmp((const char *)in, "reset\n", 6) == 0)
pss->number = 0;
if (strncmp((const char *)in, "closeme\n", 8) == 0) {
lwsl_notice("dumb_inc: closing as requested\n");
lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY,
(unsigned char *)"seeya", 5);
return -1;
}
break;
case LWS_CALLBACK_TIMER:
lwsl_notice("%s: LWS_CALLBACK_TIMER: %p\n", __func__, wsi);
lws_set_timer_usecs(wsi, 3 * LWS_USEC_PER_SEC);
break;
/*
* this just demonstrates how to use the protocol filter. If you won't
* study and reject connections based on header content, you don't need
* to handle this callback
*/
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
dump_handshake_info(wsi);
/* you could return non-zero here and kill the connection */
break;
/*
* this just demonstrates how to handle
* LWS_CALLBACK_WS_PEER_INITIATED_CLOSE and extract the peer's close
* code and auxiliary data. You can just not handle it if you don't
* have a use for this.
*/
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
lwsl_notice("LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len %lu\n",
(unsigned long)len);
for (n = 0; n < (int)len; n++)
lwsl_notice(" %d: 0x%02X\n", n,
((unsigned char *)in)[n]);
break;
default:
break;
}
return 0;
}
#endif

View file

@ -1,822 +0,0 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2010-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"
/*
* 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
*/
#if defined(LWS_WITH_TLS) && defined(LWS_HAVE_SSL_CTX_set1_param)
/* location of the certificate revocation list */
extern char crl_path[1024];
#endif
extern int debug_level;
enum demo_protocols {
/* always first */
PROTOCOL_HTTP = 0,
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
/* always last */
DEMO_PROTOCOL_COUNT
};
/*
* We take a strict whitelist approach to stop ../ attacks
*/
struct serveable {
const char *urlpath;
const char *mimetype;
};
/*
* this is just an example of parsing handshake headers, you don't need this
* in your code unless you will filter allowing connections by the header
* content
*/
void
dump_handshake_info(struct lws *wsi)
{
int n = 0, len;
char buf[256];
const unsigned char *c;
do {
c = lws_token_to_string(n);
if (!c) {
n++;
continue;
}
len = lws_hdr_total_length(wsi, n);
if (!len || len > (int)sizeof(buf) - 1) {
n++;
continue;
}
lws_hdr_copy(wsi, buf, sizeof buf, n);
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, " %s = %s\n", (char *)c, buf);
n++;
} while (c);
}
const char * get_mimetype(const char *file)
{
int n = (int)strlen(file);
if (n < 5)
return NULL;
if (!strcmp(&file[n - 4], ".ico"))
return "image/x-icon";
if (!strcmp(&file[n - 4], ".png"))
return "image/png";
if (!strcmp(&file[n - 5], ".html"))
return "text/html";
if (!strcmp(&file[n - 4], ".css"))
return "text/css";
if (!strcmp(&file[n - 3], ".js"))
return "text/javascript";
return NULL;
}
static const char * const param_names[] = {
"text",
"send",
"file",
"upload",
};
enum enum_param_names {
EPN_TEXT,
EPN_SEND,
EPN_FILE,
EPN_UPLOAD,
};
static int
file_upload_cb(void *data, const char *name, const char *filename,
char *buf, int len, enum lws_spa_fileupload_states state)
{
struct per_session_data__http *pss =
(struct per_session_data__http *)data;
int n;
(void)n;
switch (state) {
case LWS_UFS_OPEN:
lws_strncpy(pss->filename, filename, sizeof(pss->filename));
/* we get the original filename in @filename arg, but for
* simple demo use a fixed name so we don't have to deal with
* attacks */
pss->post_fd = (lws_filefd_type)(long long)open("/tmp/post-file",
O_CREAT | O_TRUNC | O_RDWR, 0600);
break;
case LWS_UFS_FINAL_CONTENT:
case LWS_UFS_CONTENT:
if (len) {
pss->file_length += len;
/* if the file length is too big, drop it */
if (pss->file_length > 100000)
return 1;
n = write((int)(long long)pss->post_fd, buf, len);
lwsl_info("%s: write %d says %d\n", __func__, len, n);
}
if (state == LWS_UFS_CONTENT)
break;
close((int)(long long)pss->post_fd);
pss->post_fd = LWS_INVALID_FILE;
break;
}
return 0;
}
/* this protocol server (always the first one) handles HTTP,
*
* Some misc callbacks that aren't associated with a protocol also turn up only
* here on the first protocol server.
*/
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
void *in, size_t len)
{
struct per_session_data__http *pss =
(struct per_session_data__http *)user;
unsigned char buffer[4096 + LWS_PRE];
lws_filepos_t amount, file_len, sent;
char leaf_path[1024];
const char *mimetype;
char *other_headers;
unsigned char *end, *start;
struct timeval tv;
unsigned char *p;
#ifndef LWS_NO_CLIENT
struct per_session_data__http *pss1;
struct lws *wsi1;
#endif
char buf[256];
char b64[64];
int n, m;
#ifdef EXTERNAL_POLL
struct lws_pollargs *pa = (struct lws_pollargs *)in;
#endif
switch (reason) {
case LWS_CALLBACK_HTTP:
lwsl_info("lws_http_serve: %s\n", (const char *)in);
if (debug_level & LLL_INFO) {
dump_handshake_info(wsi);
/* dump the individual URI Arg parameters */
n = 0;
while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
lwsl_notice("URI Arg %d: %s\n", ++n, buf);
}
if (lws_get_peer_simple(wsi, buf, sizeof(buf)))
lwsl_info("HTTP connect from %s\n", buf);
}
if (len < 1) {
lws_return_http_status(wsi,
HTTP_STATUS_BAD_REQUEST, NULL);
goto try_to_reuse;
}
#if !defined(LWS_NO_CLIENT) && defined(LWS_WITH_TLS)
if (!strncmp(in, "/proxytest", 10)) {
struct lws_client_connect_info i;
char *rootpath = "/git/";
const char *p = (const char *)in;
if (lws_get_child(wsi))
break;
pss->client_finished = 0;
memset(&i, 0, sizeof(i));
i.context = lws_get_context(wsi);
i.address = "libwebsockets.org";
i.port = 443;
i.ssl_connection = 1;
if (p[10])
i.path = (char *)in + 10;
else
i.path = rootpath;
i.host = i.address;
i.origin = NULL;
i.method = "GET";
i.parent_wsi = wsi;
i.uri_replace_from = "libwebsockets.org/git/";
i.uri_replace_to = "/proxytest/";
if (!lws_client_connect_via_info(&i)) {
lwsl_err("proxy connect fail\n");
break;
}
break;
}
#endif
#if 1
/* this example server has no concept of directories */
if (strchr((const char *)in + 1, '/')) {
lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
goto try_to_reuse;
}
#endif
/* if a legal POST URL, let it continue and accept data */
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
n = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_POST_URI);
if (n < 0)
return -1;
if (strcmp(buf, "/formtest")) {
lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
return -1;
}
return 0;
}
/* check for the "send a big file by hand" example case */
if (!strcmp((const char *)in, "/leaf.jpg")) {
lws_fop_flags_t flags = LWS_O_RDONLY;
if (strlen(resource_path) > sizeof(leaf_path) - 10)
return -1;
sprintf(leaf_path, "%s/leaf.jpg", resource_path);
/* well, let's demonstrate how to send the hard way */
p = buffer + LWS_PRE;
end = p + sizeof(buffer) - LWS_PRE;
pss->fop_fd = lws_vfs_file_open(
lws_get_fops(lws_get_context(wsi)),
leaf_path, &flags);
if (!pss->fop_fd) {
lwsl_err("failed to open file %s\n", leaf_path);
return -1;
}
file_len = lws_vfs_get_length(pss->fop_fd);
/*
* we will send a big jpeg file, but it could be
* anything. Set the Content-Type: appropriately
* so the browser knows what to do with it.
*
* Notice we use the APIs to build the header, which
* will do the right thing for HTTP 1/1.1 and HTTP2
* depending on what connection it happens to be working
* on
*/
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
(unsigned char *)"libwebsockets",
13, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"image/jpeg",
10, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi,
file_len, &p,
end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
/*
* send the http headers...
* this won't block since it's the first payload sent
* on the connection since it was established
* (too small for partial)
*
* Notice they are sent using LWS_WRITE_HTTP_HEADERS
* which also means you can't send body too in one step,
* this is mandated by changes in HTTP2
*/
*p = '\0';
lwsl_info("%s\n", buffer + LWS_PRE);
n = lws_write(wsi, buffer + LWS_PRE,
p - (buffer + LWS_PRE),
LWS_WRITE_HTTP_HEADERS);
if (n < 0) {
lws_vfs_file_close(&pss->fop_fd);
return -1;
}
/*
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
*/
lws_callback_on_writable(wsi);
break;
}
/* if not, send a file the easy way */
if (!strncmp(in, "/cgit-data/", 11)) {
in = (char *)in + 11;
strcpy(buf, "/usr/share/cgit");
} else
strcpy(buf, resource_path);
if (strcmp(in, "/")) {
if (*((const char *)in) != '/')
strcat(buf, "/");
strncat(buf, in, sizeof(buf) - strlen(buf) - 1);
} else /* default file to serve */
strcat(buf, "/test.html");
buf[sizeof(buf) - 1] = '\0';
/* refuse to serve files we don't understand */
mimetype = get_mimetype(buf);
if (!mimetype) {
lwsl_err("Unknown mimetype for %s\n", buf);
lws_return_http_status(wsi,
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unknown Mimetype");
return -1;
}
/* demonstrates how to set a cookie on / */
other_headers = leaf_path;
p = (unsigned char *)leaf_path;
if (!strcmp((const char *)in, "/") &&
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
/* this isn't very unguessable but it'll do for us */
gettimeofday(&tv, NULL);
n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
(unsigned int)tv.tv_sec,
(unsigned int)tv.tv_usec);
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)b64, n, &p,
(unsigned char *)leaf_path + sizeof(leaf_path)))
return 1;
}
#if !defined(LWS_WITH_HTTP2)
if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi,
(unsigned char *)
"Strict-Transport-Security:",
(unsigned char *)
"max-age=15768000 ; "
"includeSubDomains", 36, &p,
(unsigned char *)leaf_path +
sizeof(leaf_path)))
return 1;
#endif
n = lws_ptr_diff(p, leaf_path);
n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
if (n < 0)
return -1; /* error*/
/*
* notice that the sending of the file completes asynchronously,
* we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
* it's done. That's the case even if we just completed the
* send, so wait for that.
*/
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
((char *)in)[len] = '\0';
lwsl_info("rx %d '%s'\n", (int)len, (char *)in);
break;
case LWS_CALLBACK_HTTP_BODY:
lwsl_info("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len);
/* create the POST argument parser if not already existing */
if (!pss->spa) {
pss->spa = lws_spa_create(wsi, param_names,
ARRAY_SIZE(param_names), 1024,
file_upload_cb, pss);
if (!pss->spa)
return -1;
pss->filename[0] = '\0';
pss->file_length = 0;
}
/* let it parse the POST data */
if (lws_spa_process(pss->spa, in, (int)len))
return -1;
break;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
/*
* the whole of the sent body arrived,
* respond to the client with a redirect to show the
* results
*/
/* call to inform no more payload data coming */
lws_spa_finalize(pss->spa);
p = (unsigned char *)pss->result + LWS_PRE;
end = p + sizeof(pss->result) - LWS_PRE - 1;
p += sprintf((char *)p,
"<html><body><h1>Form results (after urldecoding)</h1>"
"<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>");
for (n = 0; n < (int)ARRAY_SIZE(param_names); n++)
p += lws_snprintf((char *)p, end - p,
"<tr><td><b>%s</b></td><td>%d</td><td>%s</td></tr>",
param_names[n],
lws_spa_get_length(pss->spa, n),
lws_spa_get_string(pss->spa, n));
p += lws_snprintf((char *)p, end - p, "</table><br><b>filename:</b> %s, <b>length</b> %ld",
pss->filename, pss->file_length);
p += lws_snprintf((char *)p, end - p, "</body></html>");
pss->result_len = lws_ptr_diff(p, pss->result + LWS_PRE);
p = buffer + LWS_PRE;
start = p;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"text/html", 9, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return 1;
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
lwsl_debug("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n");
/* called when our wsi user_space is going to be destroyed */
if (pss->spa) {
lws_spa_destroy(pss->spa);
pss->spa = NULL;
}
break;
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
goto try_to_reuse;
case LWS_CALLBACK_HTTP_WRITEABLE:
lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE: %p\n", wsi);
if (pss->client_finished)
return -1;
if (!lws_get_child(wsi) && !pss->fop_fd && !pss->result_len)
goto try_to_reuse;
#ifndef LWS_NO_CLIENT
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
char *px = buf + LWS_PRE;
int lenx = sizeof(buf) - LWS_PRE;
/*
* our sink is writeable and our source has something
* to read. So read a lump of source material of
* suitable size to send or what's available, whichever
* is the smaller.
*/
pss->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
wsi1 = lws_get_child(wsi);
if (!wsi1)
break;
if (lws_http_client_read(wsi1, &px, &lenx) < 0)
return -1;
if (pss->client_finished)
return -1;
break;
}
if (lws_get_child(wsi))
break;
#endif
/*
* we can send more of whatever it is we were sending
*/
if (pss->result_len) {
/* the result from the form */
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
pss->result_len, LWS_WRITE_HTTP);
pss->result_len = 0;
if (n < 0)
return 1;
goto try_to_reuse;
}
sent = 0;
do {
/* we'd like the send this much */
n = sizeof(buffer) - LWS_PRE;
/* but if the peer told us he wants less, we can adapt */
m = (int)lws_get_peer_write_allowance(wsi);
/* -1 means not using a protocol that has this info */
if (m == 0)
/* right now, peer can't handle anything */
goto later;
if (m != -1 && m < n)
/* he couldn't handle that much */
n = m;
n = lws_vfs_file_read(pss->fop_fd,
&amount, buffer + LWS_PRE, n);
/* problem reading, close conn */
if (n < 0) {
lwsl_err("problem reading file\n");
goto bail;
}
n = (int)amount;
/* sent it all, close conn */
if (n == 0)
goto penultimate;
/*
* To support HTTP2, must take care about preamble space
*
* identification of when we send the last payload frame
* is handled by the library itself if you sent a
* content-length header
*/
m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP);
if (m < 0) {
lwsl_err("write failed\n");
/* write failed, close conn */
goto bail;
}
if (m) /* while still active, extend timeout */
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 30);
sent += m;
} while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024));
later:
lws_callback_on_writable(wsi);
break;
penultimate:
lws_vfs_file_close(&pss->fop_fd);
pss->fop_fd = NULL;
goto try_to_reuse;
bail:
lws_vfs_file_close(&pss->fop_fd);
return -1;
/*
* callback for confirming to continue with client IP appear in
* protocol 0 callback since no websocket protocol has been agreed
* yet. You can just ignore this if you won't filter on client IP
* since the default unhandled callback return is 0 meaning let the
* connection continue.
*/
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
/* if we returned non-zero from here, we kill the connection */
break;
#ifndef LWS_NO_CLIENT
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
char ctype[64], ctlen = 0;
lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n");
p = buffer + LWS_PRE;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(lws_get_parent(wsi), HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(lws_get_parent(wsi),
WSI_TOKEN_HTTP_SERVER,
(unsigned char *)"libwebsockets",
13, &p, end))
return 1;
ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE);
if (ctlen > 0) {
if (lws_add_http_header_by_token(lws_get_parent(wsi),
WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)ctype, ctlen, &p, end))
return 1;
}
#if 0
if (lws_add_http_header_content_length(lws_get_parent(wsi),
file_len, &p, end))
return 1;
#endif
if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
return 1;
*p = '\0';
lwsl_info("%s\n", buffer + LWS_PRE);
n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE,
p - (buffer + LWS_PRE),
LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return -1;
break; }
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
//lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
return -1;
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi);
assert(lws_get_parent(wsi));
if (!lws_get_parent(wsi))
break;
pss1 = lws_wsi_user(lws_get_parent(wsi));
pss1->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
lws_callback_on_writable(lws_get_parent(wsi));
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", (int)len);
assert(lws_get_parent(wsi));
m = lws_write(lws_get_parent(wsi), (unsigned char *)in,
len, LWS_WRITE_HTTP);
if (m < 0)
return -1;
break;
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
//lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
assert(lws_get_parent(wsi));
if (!lws_get_parent(wsi))
break;
pss1 = lws_wsi_user(lws_get_parent(wsi));
pss1->client_finished = 1;
break;
#endif
/*
* callbacks for managing the external poll() array appear in
* protocol 0 callback
*/
case LWS_CALLBACK_LOCK_POLL:
/*
* lock mutex to protect pollfd state
* called before any other POLL related callback
* if protecting wsi lifecycle change, len == 1
*/
test_server_lock((int)len);
break;
case LWS_CALLBACK_UNLOCK_POLL:
/*
* unlock mutex to protect pollfd state when
* called after any other POLL related callback
* if protecting wsi lifecycle change, len == 1
*/
test_server_unlock((int)len);
break;
#ifdef EXTERNAL_POLL
case LWS_CALLBACK_ADD_POLL_FD:
if (count_pollfds >= max_poll_elements) {
lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
return 1;
}
fd_lookup[pa->fd] = count_pollfds;
pollfds[count_pollfds].fd = pa->fd;
pollfds[count_pollfds].events = pa->events;
pollfds[count_pollfds++].revents = 0;
break;
case LWS_CALLBACK_DEL_POLL_FD:
if (!--count_pollfds)
break;
m = fd_lookup[pa->fd];
/* have the last guy take up the vacant slot */
pollfds[m] = pollfds[count_pollfds];
fd_lookup[pollfds[count_pollfds].fd] = m;
break;
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
pollfds[fd_lookup[pa->fd]].events = pa->events;
break;
#endif
case LWS_CALLBACK_GET_THREAD_ID:
/*
* if you will call "lws_callback_on_writable"
* from a different thread, return the caller thread ID
* here so lws can use this information to work out if it
* should signal the poll() loop to exit and restart early
*/
/* return pthread_getthreadid_np(); */
break;
#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
/* Verify the client certificate */
if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) {
int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user);
int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user);
const char* msg = X509_verify_cert_error_string(err);
lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth);
return 1;
}
break;
#if defined(LWS_HAVE_SSL_CTX_set1_param) && !defined(LWS_WITH_MBEDTLS)
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
if (crl_path[0]) {
/* Enable CRL checking */
X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new();
X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);
SSL_CTX_set1_param((SSL_CTX*)user, param);
X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user);
X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM);
X509_VERIFY_PARAM_free(param);
if (n != 1) {
char errbuf[256];
n = ERR_get_error();
lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n);
return 1;
}
}
break;
#endif
#endif
default:
break;
}
return 0;
/* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
try_to_reuse:
if (lws_http_transaction_completed(wsi))
return -1;
return 0;
}

View file

@ -1,7 +1,7 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2011-2016 Andy Green <andy@warmcat.com>
* Copyright (C) 2011-2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
@ -17,7 +17,10 @@
* may be proprietary. So unlike the library itself, they are licensed
* Public Domain.
*/
#include "test-server.h"
#include <libwebsockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int close_testing;
int max_poll_elements;
@ -35,67 +38,20 @@ char crl_path[1024] = "";
#endif
#define LWS_PLUGIN_STATIC
#include "../plugins/protocol_dumb_increment.c"
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
/* 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,
PROTOCOL_LWS_STATUS,
/* always last */
DEMO_PROTOCOL_COUNT
};
#include "../plugins/protocol_post_demo.c"
/* 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, /* rx buf size must be >= permessage-deflate rx size
* dumb-increment only sends very small packets, so we set
* this accordingly. If your protocol will send bigger
* things, adjust this to match */
},
{ "http-only", lws_callback_http_dummy, 0, 0, },
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_POST_DEMO,
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -105,14 +61,85 @@ static const struct lws_extension exts[] = {
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 */ }
};
/*
* mount handlers for sections of the URL space
*/
static const struct lws_http_mount mount_ziptest = {
NULL, /* linked-list pointer to next*/
"/ziptest", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH"/candide.zip", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* origin points to a callback */
8, /* strlen("/ziptest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_http_mount mount_post = {
(struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
/*
* mount a filesystem directory into the URL space at /
* point it to our /usr/share directory with our assets in
* stuff from here is autoserved by the library
*/
static const struct lws_http_mount mount = {
(struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/
"/", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
"test.html", /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* mount type is a directory in a filesystem */
1, /* strlen("/"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
/* 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)
@ -148,13 +175,6 @@ void signal_cb(struct ev_loop *loop, struct ev_signal* watcher, int revents)
}
}
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' },
@ -178,15 +198,11 @@ int main(int argc, char **argv)
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
@ -264,12 +280,6 @@ int main(int argc, char **argv)
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 stderr */
lws_set_log_level(debug_level, NULL);
@ -281,6 +291,7 @@ int main(int argc, char **argv)
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.mounts = &mount;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
@ -325,17 +336,11 @@ int main(int argc, char **argv)
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
lwsl_notice("libwebsockets-test-server exited cleanly\n");
return 0;
}

View file

@ -17,7 +17,10 @@
* may be proprietary. So unlike the library itself, they are licensed
* Public Domain.
*/
#include "test-server.h"
#include <libwebsockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int close_testing;
int max_poll_elements;
@ -35,79 +38,30 @@ char crl_path[1024] = "";
#endif
#define LWS_PLUGIN_STATIC
#include "../plugins/protocol_dumb_increment.c"
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
/* 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
};
#include "../plugins/protocol_post_demo.c"
/* 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_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
{ NULL, NULL, 0, 0 } /* terminator */
/* first protocol must always be HTTP handler */
{ "http-only", lws_callback_http_dummy, 0, 0, },
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_POST_DEMO,
{ 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 */ }
{
"permessage-deflate",
lws_extension_callback_pm_deflate,
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
},
{ NULL, NULL, NULL /* terminator */ }
};
/* this shows how to override the lws file operations. You don't need
@ -139,12 +93,81 @@ void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
event_base_loopbreak(event_base_loop);
}
static void
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
{
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
}
/*
* mount handlers for sections of the URL space
*/
static const struct lws_http_mount mount_ziptest = {
NULL, /* linked-list pointer to next*/
"/ziptest", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH"/candide.zip", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* origin points to a callback */
8, /* strlen("/ziptest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_http_mount mount_post = {
(struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
/*
* mount a filesystem directory into the URL space at /
* point it to our /usr/share directory with our assets in
* stuff from here is autoserved by the library
*/
static const struct lws_http_mount mount = {
(struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/
"/", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
"test.html", /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* mount type is a directory in a filesystem */
1, /* strlen("/"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
@ -170,15 +193,11 @@ int main(int argc, char **argv)
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
struct event *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
@ -259,23 +278,18 @@ int main(int argc, char **argv)
evsignal_add(signals[n], NULL);
}
#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);
/* tell the library what debug level to emit and to send it to stderr */
lws_set_log_level(debug_level, NULL);
lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
printf("Using resource path \"%s\"\n", resource_path);
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.mounts = &mount;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
@ -325,17 +339,11 @@ int main(int argc, char **argv)
// Initialize the LWS with libevent loop
lws_event_initloop(context, event_base_loop, 0);
timeout_watcher = event_new(event_base_loop, -1, EV_PERSIST, ev_timeout_cb, NULL);
struct timeval tv = {0, 50000};
evtimer_add(timeout_watcher, &tv);
event_base_dispatch(event_base_loop);
lws_context_destroy(context);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32
closelog();
#endif
lwsl_notice("libwebsockets-test-server exited cleanly\n");
return 0;
}

View file

@ -19,8 +19,10 @@
* MA 02110-1301 USA
*/
#define DI_HANDLED_BY_PLUGIN
#include "test-server.h"
#include <libwebsockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <uv.h>
int close_testing;
@ -51,50 +53,21 @@ void test_server_unlock(int care)
#include "../plugins/protocol_dumb_increment.c"
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
#include "../plugins/protocol_post_demo.c"
#endif
/*
* 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,
PROTOCOL_LWS_STATUS,
/* 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 */
},
{ "http-only", lws_callback_http_dummy, 0, 0, },
#if defined(LWS_ROLE_WS)
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_POST_DEMO,
#endif
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -106,11 +79,6 @@ static const struct lws_extension exts[] = {
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 */ }
};
@ -129,6 +97,81 @@ void signal_cb(uv_signal_t *watcher, int signum)
lws_libuv_stop(context);
}
/*
* mount handlers for sections of the URL space
*/
static const struct lws_http_mount mount_ziptest = {
NULL, /* linked-list pointer to next*/
"/ziptest", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH"/candide.zip", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* origin points to a callback */
8, /* strlen("/ziptest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_http_mount mount_post = {
(struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
/*
* mount a filesystem directory into the URL space at /
* point it to our /usr/share directory with our assets in
* stuff from here is autoserved by the library
*/
static const struct lws_http_mount mount = {
(struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/
"/", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
"test.html", /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* mount type is a directory in a filesystem */
1, /* strlen("/"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
@ -300,13 +343,14 @@ int main(int argc, char **argv)
lws_set_log_level(debug_level, NULL);
lwsl_notice("libwebsockets test server libuv - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
lwsl_info("Using resource path \"%s\"\n", resource_path);
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.mounts = &mount;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;

View file

@ -111,11 +111,6 @@ static const struct lws_extension exts[] = {
lws_extension_callback_pm_deflate,
"permessage-deflate"
},
{
"deflate-frame",
lws_extension_callback_pm_deflate,
"deflate_frame"
},
{ NULL, NULL, NULL /* terminator */ }
};

View file

@ -18,7 +18,10 @@
* Public Domain.
*/
#include "test-server.h"
#include <libwebsockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int close_testing;
int max_poll_elements;
@ -33,6 +36,7 @@ volatile int force_exit = 0, dynamic_vhost_enable = 0;
struct lws_vhost *dynamic_vhost;
struct lws_context *context;
struct lws_plat_file_ops fops_plat;
static int test_options;
/* http server gets files from this path */
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
@ -69,72 +73,21 @@ char crl_path[1024] = "";
#if defined(LWS_ROLE_WS)
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
#include "../plugins/protocol_dumb_increment.c"
#include "../plugins/protocol_post_demo.c"
#endif
/* 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
*
* lws-status: informs connected browsers of who else is
* connected.
*/
enum demo_protocols {
/* always first */
PROTOCOL_HTTP = 0,
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
PROTOCOL_LWS_META,
/* 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 */
},
{ "http-only", lws_callback_http_dummy, 0, 0, },
#if defined(LWS_ROLE_WS)
{
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10, /* rx buf size must be >= permessage-deflate rx size
* dumb-increment only sends very small packets, so we set
* this accordingly. If your protocol will send bigger
* things, adjust this to match */
},
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_POST_DEMO,
#endif
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -191,15 +144,98 @@ static const struct lws_extension exts[] = {
lws_extension_callback_pm_deflate,
"permessage-deflate"
},
{
"deflate-frame",
lws_extension_callback_pm_deflate,
"deflate_frame"
},
{ NULL, NULL, NULL /* terminator */ }
};
/*
* mount handlers for sections of the URL space
*/
static const struct lws_http_mount mount_ziptest = {
NULL, /* linked-list pointer to next*/
"/ziptest", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH"/candide.zip", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* origin points to a callback */
8, /* strlen("/ziptest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_http_mount mount_post = {
(struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
/*
* mount a filesystem directory into the URL space at /
* point it to our /usr/share directory with our assets in
* stuff from here is autoserved by the library
*/
static const struct lws_http_mount mount = {
(struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/
"/", /* mountpoint in URL namespace on this vhost */
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
"test.html", /* default filename if none given */
NULL,
NULL,
NULL,
NULL,
0,
0,
0,
0,
0,
0,
LWSMPRO_FILE, /* mount type is a directory in a filesystem */
1, /* strlen("/"), ie length of the mountpoint */
NULL,
{ NULL, NULL } // sentinel
};
static const struct lws_protocol_vhost_options pvo_options = {
NULL,
NULL,
"options", /* pvo name */
(void *)&test_options /* pvo value */
};
static const struct lws_protocol_vhost_options pvo = {
NULL, /* "next" pvo linked-list */
&pvo_options, /* "child" pvo linked-list */
"dumb-increment-protocol", /* protocol name we belong to on this vhost */
"" /* ignored */
};
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
@ -233,7 +269,9 @@ int main(int argc, char **argv)
struct lws_context_creation_info info;
struct lws_vhost *vhost;
char interface_name[128] = "";
unsigned int ms, oldms = 0;
#ifdef EXTERNAL_POLL
unsigned int ms;
#endif
const char *iface = NULL;
char cert_path[1024] = "";
char key_path[1024] = "";
@ -243,18 +281,9 @@ int main(int argc, char **argv)
int pp_secs = 0;
int opts = 0;
int n = 0;
#ifndef _WIN32
/* LOG_PERROR is not POSIX standard, and may not be portable */
#ifdef __sun
int syslog_options = LOG_PID;
#else
int syslog_options = LOG_PID | LOG_PERROR;
#endif
#endif
#ifndef LWS_NO_DAEMONIZE
int daemonize = 0;
#endif
char no_dumb_send = 0;
/*
* take care to zero down the info struct, he contains random garbaage
@ -289,7 +318,8 @@ int main(int argc, char **argv)
debug_level = atoi(optarg);
break;
case 'n':
no_dumb_send = 1;
/* no dumb increment send */
test_options |= 1;
break;
case 's':
use_ssl = 1;
@ -380,17 +410,11 @@ int main(int argc, char **argv)
signal(SIGUSR1, sighandler);
#endif
#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 */
/* tell the library what debug level to emit and to send it to stderr */
lws_set_log_level(debug_level, NULL);
lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2017 Andy Green <andy@warmcat.com>\n");
lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
printf("Using resource path \"%s\"\n", resource_path);
#ifdef EXTERNAL_POLL
@ -432,7 +456,6 @@ int main(int argc, char **argv)
}
info.gid = gid;
info.uid = uid;
info.max_http_header_pool = 256;
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
info.extensions = exts;
info.timeout_secs = 5;
@ -449,6 +472,7 @@ int main(int argc, char **argv)
"!DHE-RSA-AES256-SHA256:"
"!AES256-GCM-SHA384:"
"!AES256-SHA256";
info.mounts = &mount;
info.ip_limit_ah = 24; /* for testing */
info.ip_limit_wsi = 105; /* for testing */
@ -462,6 +486,8 @@ int main(int argc, char **argv)
return -1;
}
info.pvo = &pvo;
vhost = lws_create_vhost(context, &info);
if (!vhost) {
lwsl_err("vhost creation failed\n");
@ -504,20 +530,12 @@ int main(int argc, char **argv)
* as soon as it can take more packets (usually immediately)
*/
ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
if ((ms - oldms) > 50) {
if (!no_dumb_send)
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
oldms = ms;
}
#ifdef EXTERNAL_POLL
/*
* this represents an existing server's single poll action
* which also includes libwebsocket sockets
*/
ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
n = poll(pollfds, count_pollfds, 50);
if (n < 0)
continue;
@ -580,9 +598,5 @@ done:
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32
closelog();
#endif
return 0;
}

View file

@ -1,124 +0,0 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2010-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.
*/
#if defined(_WIN32) && defined(EXTERNAL_POLL)
#if (WINVER < 0x0600)
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0600
#define _WIN32_WINNT WINVER
#endif
#define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout))
#endif
#include "lws_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include "../lib/libwebsockets.h"
#ifdef _WIN32
#include <io.h>
#include "gettimeofday.h"
#else
#include <syslog.h>
#include <sys/time.h>
#include <unistd.h>
#endif
extern int close_testing;
extern int max_poll_elements;
#ifdef EXTERNAL_POLL
extern struct lws_pollfd *pollfds;
extern int *fd_lookup;
extern int count_pollfds;
#endif
extern volatile int force_exit;
extern struct lws_context *context;
extern char *resource_path;
#if defined(LWS_WITH_TLS) && defined(LWS_HAVE_SSL_CTX_set1_param)
extern char crl_path[1024];
#endif
extern void test_server_lock(int care);
extern void test_server_unlock(int care);
#ifndef __func__
#define __func__ __FUNCTION__
#endif
struct per_session_data__http {
lws_fop_fd_t fop_fd;
#ifdef LWS_WITH_CGI
struct lws_cgi_args args;
#endif
#if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT)
int reason_bf;
#endif
unsigned int client_finished:1;
struct lws_spa *spa;
char result[500 + LWS_PRE];
int result_len;
char filename[256];
long file_length;
lws_filefd_type post_fd;
};
/*
* one of these is auto-created for each connection and a pointer to the
* appropriate instance is passed to the callback in the user parameter
*
* for this example protocol we use it to individualize the count for each
* connection.
*/
#if !defined(DI_HANDLED_BY_PLUGIN)
struct per_session_data__dumb_increment {
int number;
};
#endif
extern int
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
void *in, size_t len);
#if !defined(DI_HANDLED_BY_PLUGIN)
extern int
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
#endif
extern void
dump_handshake_info(struct lws *wsi);