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:
parent
8d213f8295
commit
d05b408cde
13 changed files with 422 additions and 2010 deletions
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 \
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */ }
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
Loading…
Add table
Reference in a new issue