From e9739ed2031ccdc5f774b9e4f65940c9007f8912 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 7 Mar 2011 21:40:59 +0000 Subject: [PATCH] introduce fraggle test app Signed-off-by: Andy Green --- libwebsockets-api-doc.html | 14 +- test-server/Makefile.am | 6 +- test-server/Makefile.in | 35 ++++- test-server/test-fraggle.c | 318 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 365 insertions(+), 8 deletions(-) create mode 100644 test-server/test-fraggle.c diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html index d3c83d7..80e8504 100644 --- a/libwebsockets-api-doc.html +++ b/libwebsockets-api-doc.html @@ -553,14 +553,16 @@ which will then open the websockets connection. libwebsockets_serve_http_file makes it very simple to send back a file to the client. -

LWS_CALLBACK_CLIENT_WRITEABLE

+

LWS_CALLBACK_SERVER_WRITEABLE

-if you call +If you call libwebsocket_callback_on_writable on a connection, you will -get this callback coming when the connection socket is able to -accept another write packet without blocking. If it already -was able to take another packet without blocking, you'll get -this callback at the next call to the service loop function. +get one of these callbacks coming when the connection socket +is able to accept another write packet without blocking. +If it already was able to take another packet without blocking, +you'll get this callback at the next call to the service loop +function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE +and servers get LWS_CALLBACK_SERVER_WRITEABLE.

LWS_CALLBACK_FILTER_NETWORK_CONNECTION

diff --git a/test-server/Makefile.am b/test-server/Makefile.am index a28fe1d..84f3bf1 100644 --- a/test-server/Makefile.am +++ b/test-server/Makefile.am @@ -1,15 +1,19 @@ -bin_PROGRAMS=libwebsockets-test-server libwebsockets-test-client libwebsockets-test-server-extpoll +bin_PROGRAMS=libwebsockets-test-server libwebsockets-test-client libwebsockets-test-server-extpoll libwebsockets-test-fraggle libwebsockets_test_server_SOURCES=test-server.c libwebsockets_test_server_LDADD=-L../lib -lwebsockets libwebsockets_test_client_SOURCES=test-client.c libwebsockets_test_client_LDADD=-L../lib -lwebsockets libwebsockets_test_server_extpoll_SOURCES=test-server-extpoll.c libwebsockets_test_server_extpoll_LDADD=-L../lib -lwebsockets +libwebsockets_test_fraggle_SOURCES=test-fraggle.c +libwebsockets_test_fraggle_LDADD=-L../lib -lwebsockets libwebsockets_test_server_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" libwebsockets_test_client_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" libwebsockets_test_server_extpoll_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_test_fraggle_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" + if NOPING else diff --git a/test-server/Makefile.in b/test-server/Makefile.in index 2a9c7dc..7f02435 100644 --- a/test-server/Makefile.in +++ b/test-server/Makefile.in @@ -36,7 +36,8 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = libwebsockets-test-server$(EXEEXT) \ libwebsockets-test-client$(EXEEXT) \ - libwebsockets-test-server-extpoll$(EXEEXT) $(am__EXEEXT_1) + libwebsockets-test-server-extpoll$(EXEEXT) \ + libwebsockets-test-fraggle$(EXEEXT) $(am__EXEEXT_1) @NOPING_FALSE@am__append_1 = libwebsockets-test-ping subdir = test-server DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in @@ -60,6 +61,15 @@ libwebsockets_test_client_LINK = $(LIBTOOL) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libwebsockets_test_client_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ +am_libwebsockets_test_fraggle_OBJECTS = \ + libwebsockets_test_fraggle-test-fraggle.$(OBJEXT) +libwebsockets_test_fraggle_OBJECTS = \ + $(am_libwebsockets_test_fraggle_OBJECTS) +libwebsockets_test_fraggle_DEPENDENCIES = +libwebsockets_test_fraggle_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ am__libwebsockets_test_ping_SOURCES_DIST = test-ping.c @NOPING_FALSE@am_libwebsockets_test_ping_OBJECTS = \ @NOPING_FALSE@ libwebsockets_test_ping-test-ping.$(OBJEXT) @@ -101,10 +111,12 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libwebsockets_test_client_SOURCES) \ + $(libwebsockets_test_fraggle_SOURCES) \ $(libwebsockets_test_ping_SOURCES) \ $(libwebsockets_test_server_SOURCES) \ $(libwebsockets_test_server_extpoll_SOURCES) DIST_SOURCES = $(libwebsockets_test_client_SOURCES) \ + $(libwebsockets_test_fraggle_SOURCES) \ $(am__libwebsockets_test_ping_SOURCES_DIST) \ $(libwebsockets_test_server_SOURCES) \ $(libwebsockets_test_server_extpoll_SOURCES) @@ -231,9 +243,12 @@ libwebsockets_test_client_SOURCES = test-client.c libwebsockets_test_client_LDADD = -L../lib -lwebsockets libwebsockets_test_server_extpoll_SOURCES = test-server-extpoll.c libwebsockets_test_server_extpoll_LDADD = -L../lib -lwebsockets +libwebsockets_test_fraggle_SOURCES = test-fraggle.c +libwebsockets_test_fraggle_LDADD = -L../lib -lwebsockets libwebsockets_test_server_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" libwebsockets_test_client_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" libwebsockets_test_server_extpoll_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" +libwebsockets_test_fraggle_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" @NOPING_FALSE@libwebsockets_test_ping_SOURCES = test-ping.c @NOPING_FALSE@libwebsockets_test_ping_LDADD = -L../lib -lwebsockets @NOPING_FALSE@libwebsockets_test_ping_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" @@ -317,6 +332,9 @@ clean-binPROGRAMS: libwebsockets-test-client$(EXEEXT): $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_DEPENDENCIES) @rm -f libwebsockets-test-client$(EXEEXT) $(libwebsockets_test_client_LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS) +libwebsockets-test-fraggle$(EXEEXT): $(libwebsockets_test_fraggle_OBJECTS) $(libwebsockets_test_fraggle_DEPENDENCIES) + @rm -f libwebsockets-test-fraggle$(EXEEXT) + $(libwebsockets_test_fraggle_LINK) $(libwebsockets_test_fraggle_OBJECTS) $(libwebsockets_test_fraggle_LDADD) $(LIBS) libwebsockets-test-ping$(EXEEXT): $(libwebsockets_test_ping_OBJECTS) $(libwebsockets_test_ping_DEPENDENCIES) @rm -f libwebsockets-test-ping$(EXEEXT) $(libwebsockets_test_ping_LINK) $(libwebsockets_test_ping_OBJECTS) $(libwebsockets_test_ping_LDADD) $(LIBS) @@ -334,6 +352,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_client-test-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_ping-test-ping.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server-test-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server_extpoll-test-server-extpoll.Po@am__quote@ @@ -373,6 +392,20 @@ libwebsockets_test_client-test-client.obj: test-client.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi` +libwebsockets_test_fraggle-test-fraggle.o: test-fraggle.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -MT libwebsockets_test_fraggle-test-fraggle.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo -c -o libwebsockets_test_fraggle-test-fraggle.o `test -f 'test-fraggle.c' || echo '$(srcdir)/'`test-fraggle.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-fraggle.c' object='libwebsockets_test_fraggle-test-fraggle.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_fraggle-test-fraggle.o `test -f 'test-fraggle.c' || echo '$(srcdir)/'`test-fraggle.c + +libwebsockets_test_fraggle-test-fraggle.obj: test-fraggle.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -MT libwebsockets_test_fraggle-test-fraggle.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo -c -o libwebsockets_test_fraggle-test-fraggle.obj `if test -f 'test-fraggle.c'; then $(CYGPATH_W) 'test-fraggle.c'; else $(CYGPATH_W) '$(srcdir)/test-fraggle.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Tpo $(DEPDIR)/libwebsockets_test_fraggle-test-fraggle.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-fraggle.c' object='libwebsockets_test_fraggle-test-fraggle.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_fraggle_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_fraggle-test-fraggle.obj `if test -f 'test-fraggle.c'; then $(CYGPATH_W) 'test-fraggle.c'; else $(CYGPATH_W) '$(srcdir)/test-fraggle.c'; fi` + libwebsockets_test_ping-test-ping.o: test-ping.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_ping_CFLAGS) $(CFLAGS) -MT libwebsockets_test_ping-test-ping.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo -c -o libwebsockets_test_ping-test-ping.o `test -f 'test-ping.c' || echo '$(srcdir)/'`test-ping.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libwebsockets_test_ping-test-ping.Tpo $(DEPDIR)/libwebsockets_test_ping-test-ping.Po diff --git a/test-server/test-fraggle.c b/test-server/test-fraggle.c new file mode 100644 index 0000000..fe75c4d --- /dev/null +++ b/test-server/test-fraggle.c @@ -0,0 +1,318 @@ +/* + * libwebsockets-test-fraggle - random fragmentation test + * + * Copyright (C) 2010-2011 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "../lib/libwebsockets.h" + +#define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server" + +static int client; + +enum demo_protocols { + PROTOCOL_FRAGGLE, + + /* always last */ + DEMO_PROTOCOL_COUNT +}; + +/* fraggle protocol */ + +/* + * 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. + */ + +struct per_session_data__fraggle { + int packets_left; + int total_message; + unsigned long sum; + int rx_state; +}; + +static int +callback_fraggle(struct libwebsocket_context * context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + int n; + unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2048 + + LWS_SEND_BUFFER_POST_PADDING]; + struct per_session_data__fraggle *psf = user; + int chunk; + int write_mode = LWS_WRITE_CONTINUATION; + unsigned long sum; + unsigned char *p = (unsigned char *)in; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + fprintf(stderr, "server sees client connect\n"); + psf->packets_left = -1; + /* start the ball rolling */ + libwebsocket_callback_on_writable(context, wsi); + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + fprintf(stderr, "client connects to server\n"); + /* next guy will be start of new message */ + psf->rx_state = 0; + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + switch (psf->rx_state) { + case 2: + sum = p[0] << 24; + sum |= p[1] << 16; + sum |= p[2] << 8; + sum |= p[3]; + if (sum == psf->sum) + fprintf(stderr, "EOM received %d correctly " + "from %d fragments\n", + psf->total_message, psf->packets_left); + else + fprintf(stderr, "**** ERROR at EOM: " + "length %d, rx sum = 0x%lX, " + "server says it sent 0x%lX\n", + psf->total_message, psf->sum, sum); + /* next guy will be start of new message */ + psf->rx_state = 0; + break; + case 0: + /* expect the start of the message */ + psf->rx_state = 1; + psf->sum = 0; + psf->total_message = 0; + psf->packets_left = 0; +// fprintf(stderr, "starting receiving a message\n"); + /* fallthru */ + + case 1: + for (n = 0; n < len; n++) + psf->sum += p[n]; + + psf->total_message += len; + psf->packets_left++; + + if (libwebsocket_is_final_fragment(wsi)) + /* + * next guy will be server's + * computed checksum + */ + psf->rx_state = 2; + break; + } + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + + if (psf->packets_left == 0) { + /* reached the end */ + fprintf(stderr, "Spamming session over, " + "len = %d. sum = 0x%lX\n", + psf->total_message, psf->sum); + + buf[LWS_SEND_BUFFER_PRE_PADDING + 0] = psf->sum >> 24; + buf[LWS_SEND_BUFFER_PRE_PADDING + 1] = psf->sum >> 16; + buf[LWS_SEND_BUFFER_PRE_PADDING + 2] = psf->sum >> 8; + buf[LWS_SEND_BUFFER_PRE_PADDING + 3] = psf->sum; + + n = libwebsocket_write(wsi, (unsigned char *) + &buf[LWS_SEND_BUFFER_PRE_PADDING], 4, LWS_WRITE_TEXT); + + libwebsocket_callback_on_writable(context, wsi); + + psf->packets_left--; + break; + } + + if (psf->packets_left < 1) { + /* start a new blob */ + + psf->packets_left = (random() % 1024) + 1; + fprintf(stderr, "Spamming %d random fragments\n", + psf->packets_left); + psf->sum = 0; + psf->total_message = 0; + write_mode = LWS_WRITE_BINARY; + } + + chunk = (random() % 2000) + 1; + psf->total_message += chunk; + + libwebsockets_get_random(context, + &buf[LWS_SEND_BUFFER_PRE_PADDING], chunk); + for (n = 0; n < chunk; n++) + psf->sum += buf[LWS_SEND_BUFFER_PRE_PADDING + n]; + + psf->packets_left--; + if (psf->packets_left) + write_mode |= LWS_WRITE_NO_FIN; + + n = libwebsocket_write(wsi, (unsigned char *) + &buf[LWS_SEND_BUFFER_PRE_PADDING], chunk, write_mode); + + libwebsocket_callback_on_writable(context, wsi); + break; + + + /* because we are protocols[0] ... */ + + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + if (strcmp(in, "deflate-stream") == 0) + fprintf(stderr, "denied deflate-stream extension\n"); + return 1; + break; + + default: + break; + } + + return 0; +} + + + +/* list of supported protocols and callbacks */ + +static struct libwebsocket_protocols protocols[] = { + { + "fraggle-protocol", + callback_fraggle, + sizeof(struct per_session_data__fraggle), + }, + { + NULL, NULL, 0 /* End of list */ + } +}; + +static struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "port", required_argument, NULL, 'p' }, + { "ssl", no_argument, NULL, 's' }, + { "killmask", no_argument, NULL, 'k' }, + { "interface", required_argument, NULL, 'i' }, + { "client", no_argument, NULL, 'c' }, + { NULL, 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + int n = 0; + const char *cert_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; + const char *key_path = + LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; + int port = 7681; + int use_ssl = 0; + struct libwebsocket_context *context; + int opts = 0; + char interface_name[128] = ""; + const char * interface = NULL; + struct libwebsocket *wsi; + const char *address; + int server_port = port; + + fprintf(stderr, "libwebsockets test fraggle\n" + "(C) Copyright 2010-2011 Andy Green " + "licensed under LGPL2.1\n"); + + while (n >= 0) { + n = getopt_long(argc, argv, "ci:khsp:", options, NULL); + if (n < 0) + continue; + switch (n) { + case 's': + use_ssl = 1; + break; + case 'k': + opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; + break; + case 'p': + port = atoi(optarg); + server_port = port; + break; + case 'i': + strncpy(interface_name, optarg, sizeof interface_name); + interface_name[(sizeof interface_name) - 1] = '\0'; + interface = interface_name; + break; + case 'c': + client = 1; + fprintf(stderr, " Client mode\n"); + break; + case 'h': + fprintf(stderr, "Usage: test-server " + "[--port=

] [--ssl]\n"); + exit(1); + } + } + + if (client) { + server_port = CONTEXT_PORT_NO_LISTEN; + if (optind >= argc) { + fprintf(stderr, "Must give address of server\n"); + return 1; + } + } + + if (!use_ssl) + cert_path = key_path = NULL; + + context = libwebsocket_create_context(server_port, interface, protocols, + libwebsocket_internal_extensions, + cert_path, key_path, -1, -1, opts); + if (context == NULL) { + fprintf(stderr, "libwebsocket init failed\n"); + return -1; + } + + if (client) { + address = argv[optind]; + fprintf(stderr, "Connecting to %s:%u\n", address, port); + wsi = libwebsocket_client_connect(context, address, + port, use_ssl, "/", address, + "origin", protocols[PROTOCOL_FRAGGLE].name, + -1); + if (wsi == NULL) { + fprintf(stderr, "Client connect to server failed\n"); + goto bail; + } + } + + n = 0; + while (!n) + n = libwebsocket_service(context, 50); + +bail: + libwebsocket_context_destroy(context); + + return 0; +} -- 2.7.4