From: Andy Green Date: Tue, 15 Jan 2013 04:39:48 +0000 (+0800) Subject: merge test server extpoll into test server X-Git-Tag: upstream/1.7.3~1153 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a50dd1af40c4cb6add355a1ff7db2637361e650b;p=platform%2Fupstream%2Flibwebsockets.git merge test server extpoll into test server the -extpoll version of the test server was starting to rot compared to the test-server.c it was originally based on. This patch deletes the -extpoll.c version and instead has the test-server.c source built two different ways in the makefile, once with the define EXTERNAL_POLL which forces non-fork mode and enables the "by hand" pollfd array handling. The resulting binary of that is still called libwebsockets-test-server-extpoll. Another problem was that the pollfd array length needs to match MAX_CLIENTS, that now happens during the build. Signed-off-by: Andy Green --- diff --git a/test-server/Makefile.am b/test-server/Makefile.am index 42ab913..de08a1d 100644 --- a/test-server/Makefile.am +++ b/test-server/Makefile.am @@ -1,18 +1,22 @@ 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_CFLAGS= libwebsockets_test_server_LDADD=-L../lib -lwebsockets -lz libwebsockets_test_client_SOURCES=test-client.c +libwebsockets_test_client_CFLAGS= libwebsockets_test_client_LDADD=-L../lib -lwebsockets -lz -libwebsockets_test_server_extpoll_SOURCES=test-server-extpoll.c +libwebsockets_test_server_extpoll_SOURCES=test-server.c +libwebsockets_test_server_extpoll_CFLAGS=$(AM_CFLAGS) -DEXTERNAL_POLL libwebsockets_test_server_extpoll_LDADD=-L../lib -lwebsockets -lz libwebsockets_test_fraggle_SOURCES=test-fraggle.c +libwebsockets_test_fraggle_CFLAGS= libwebsockets_test_fraggle_LDADD=-L../lib -lwebsockets -lz if MINGW -libwebsockets_test_server_CFLAGS= -w -I../win32port/win32helpers -libwebsockets_test_client_CFLAGS= -w -I../win32port/win32helpers -libwebsockets_test_server_extpoll_CFLAGS= -w -I../win32port/win32helpers -libwebsockets_test_fraggle_CFLAGS= -w -I../win32port/win32helpers +libwebsockets_test_server_CFLAGS+= -w -I../win32port/win32helpers +libwebsockets_test_client_CFLAGS+= -w -I../win32port/win32helpers +libwebsockets_test_server_extpoll_CFLAGS+= -w -I../win32port/win32helpers +libwebsockets_test_fraggle_CFLAGS+= -w -I../win32port/win32helpers libwebsockets_test_server_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz libwebsockets_test_client_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz @@ -20,10 +24,10 @@ libwebsockets_test_server_extpoll_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lg libwebsockets_test_fraggle_LDADD+= -lm -luser32 -ladvapi32 -lkernel32 -lgcc -lws2_32 -lz else -libwebsockets_test_server_CFLAGS= -Werror -libwebsockets_test_client_CFLAGS= -Werror -libwebsockets_test_server_extpoll_CFLAGS= -Werror -libwebsockets_test_fraggle_CFLAGS= -Werror +libwebsockets_test_server_CFLAGS+= -Werror +libwebsockets_test_client_CFLAGS+= -Werror +libwebsockets_test_server_extpoll_CFLAGS+= -Werror +libwebsockets_test_fraggle_CFLAGS+= -Werror endif libwebsockets_test_server_CFLAGS+= -Wall -std=gnu99 -pedantic -DINSTALL_DATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\" diff --git a/test-server/test-server-extpoll.c b/test-server/test-server-extpoll.c deleted file mode 100644 index 5025f4d..0000000 --- a/test-server/test-server-extpoll.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * libwebsockets-test-server-extpoll - libwebsockets external poll loop sample - * - * This acts the same as libwebsockets-test-server but works with the poll - * loop taken out of libwebsockets and into this app. It's an example of how - * you can integrate libwebsockets polling into an app that already has its - * own poll loop. - * - * 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 -#ifdef __MINGW32__ -#include "../win32port/win32helpers/websock-w32.h" -#else -#ifdef __MINGW64__ -#include "../win32port/win32helpers/websock-w32.h" -#else -#include -#endif -#endif - -#include "../lib/libwebsockets.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 - */ - -#define MAX_POLL_ELEMENTS 100 -struct pollfd pollfds[100]; -int count_pollfds = 0; - - - -enum demo_protocols { - /* always first */ - PROTOCOL_HTTP = 0, - - PROTOCOL_DUMB_INCREMENT, - PROTOCOL_LWS_MIRROR, - - /* always last */ - DEMO_PROTOCOL_COUNT -}; - - -#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" - -/* this protocol server (always the first one) just knows how to do HTTP */ - -static int callback_http(struct libwebsocket_context * this, - struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, void *user, - void *in, size_t len) -{ - int n; - char client_name[128]; - char client_ip[128]; - - switch (reason) { - case LWS_CALLBACK_HTTP: - fprintf(stderr, "serving HTTP URI %s\n", (char *)in); - - if (in && strcmp(in, "/favicon.ico") == 0) { - if (libwebsockets_serve_http_file(wsi, - LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon")) - fprintf(stderr, "Failed to send favicon\n"); - break; - } - - /* send the script... when it runs it'll start websockets */ - - if (libwebsockets_serve_http_file(wsi, - LOCAL_RESOURCE_PATH"/test.html", "text/html")) - fprintf(stderr, "Failed to send HTTP file\n"); - /* we are done with this connnection */ - 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 uhandled callback return is 0 meaning let the - * connection continue. - */ - - case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: - - libwebsockets_get_peer_addresses((int)(long)user, client_name, - sizeof(client_name), client_ip, sizeof(client_ip)); - - fprintf(stderr, "Received network connect from %s (%s)\n", - client_name, client_ip); - - /* if we returned non-zero from here, we kill the connection */ - break; - - /* - * callbacks for managing the external poll() array appear in - * protocol 0 callback - */ - - case LWS_CALLBACK_ADD_POLL_FD: - pollfds[count_pollfds].fd = (int)(long)user; - pollfds[count_pollfds].events = (int)len; - pollfds[count_pollfds++].revents = 0; - break; - - case LWS_CALLBACK_DEL_POLL_FD: - for (n = 0; n < count_pollfds; n++) { - if (pollfds[n].fd != (int)(long)user) - continue; - /* - * swap the end guy into our vacant slot... - * works ok if n is the end guy - */ - pollfds[n] = pollfds[count_pollfds - 1]; - pollfds[count_pollfds - 1].fd = -1; - count_pollfds--; - break; - } - break; - - case LWS_CALLBACK_SET_MODE_POLL_FD: - for (n = 0; n < count_pollfds; n++) - if (pollfds[n].fd == (int)(long)user) - pollfds[n].events |= (int)(long)len; - break; - - case LWS_CALLBACK_CLEAR_MODE_POLL_FD: - for (n = 0; n < count_pollfds; n++) - if (pollfds[n].fd == (int)(long)user) - pollfds[n].events &= ~(int)(long)len; - break; - - default: - break; - } - - return 0; -} - -/* - * 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 - */ - -static void -dump_handshake_info(struct lws_tokens *lwst) -{ - int n; - static const char *token_names[] = { - [WSI_TOKEN_GET_URI] = "GET URI", - [WSI_TOKEN_HOST] = "Host", - [WSI_TOKEN_CONNECTION] = "Connection", - [WSI_TOKEN_KEY1] = "key 1", - [WSI_TOKEN_KEY2] = "key 2", - [WSI_TOKEN_PROTOCOL] = "Protocol", - [WSI_TOKEN_UPGRADE] = "Upgrade", - [WSI_TOKEN_ORIGIN] = "Origin", - [WSI_TOKEN_DRAFT] = "Draft", - [WSI_TOKEN_CHALLENGE] = "Challenge", - - /* new for 04 */ - [WSI_TOKEN_KEY] = "Key", - [WSI_TOKEN_VERSION] = "Version", - [WSI_TOKEN_SWORIGIN] = "Sworigin", - - /* new for 05 */ - [WSI_TOKEN_EXTENSIONS] = "Extensions", - - /* client receives these */ - [WSI_TOKEN_ACCEPT] = "Accept", - [WSI_TOKEN_NONCE] = "Nonce", - [WSI_TOKEN_HTTP] = "Http", - [WSI_TOKEN_MUXURL] = "MuxURL", - }; - - for (n = 0; n < WSI_TOKEN_COUNT; n++) { - if (lwst[n].token == NULL) - continue; - - fprintf(stderr, " %s = %s\n", token_names[n], lwst[n].token); - } -} - -/* dumb_increment 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__dumb_increment { - int number; -}; - -static int -callback_dumb_increment(struct libwebsocket_context * this, - 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 + 512 + - LWS_SEND_BUFFER_POST_PADDING]; - unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; - struct per_session_data__dumb_increment *pss = user; - - switch (reason) { - - case LWS_CALLBACK_ESTABLISHED: - pss->number = 0; - break; - - /* - * in this protocol, we just use the broadcast action as the chance to - * send our own connection-specific data and ignore the broadcast info - * that is available in the 'in' parameter - */ - - case LWS_CALLBACK_BROADCAST: - n = sprintf((char *)p, "%d", pss->number++); - n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); - if (n < 0) { - fprintf(stderr, "ERROR %d writing to socket\n", n); - return 1; - } - break; - - case LWS_CALLBACK_RECEIVE: - fprintf(stderr, "rx %d\n", (int)len); - if (len < 6) - break; - if (strcmp(in, "reset\n") == 0) - pss->number = 0; - 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((struct lws_tokens *)(long)user); - /* you could return non-zero here and kill the connection */ - break; - - default: - break; - } - - return 0; -} - - -/* lws-mirror_protocol */ - -#define MAX_MESSAGE_QUEUE 64 - -struct per_session_data__lws_mirror { - struct libwebsocket *wsi; - int ringbuffer_tail; -}; - -struct a_message { - void *payload; - size_t len; -}; - -static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; -static int ringbuffer_head; - - -static int -callback_lws_mirror(struct libwebsocket_context * this, - struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, - void *user, void *in, size_t len) -{ - int n; - struct per_session_data__lws_mirror *pss = user; - - switch (reason) { - - case LWS_CALLBACK_ESTABLISHED: - pss->ringbuffer_tail = ringbuffer_head; - pss->wsi = wsi; - libwebsocket_callback_on_writable(this, wsi); - break; - - case LWS_CALLBACK_SERVER_WRITEABLE: - - if (pss->ringbuffer_tail != ringbuffer_head) { - - n = libwebsocket_write(wsi, (unsigned char *) - ringbuffer[pss->ringbuffer_tail].payload + - LWS_SEND_BUFFER_PRE_PADDING, - ringbuffer[pss->ringbuffer_tail].len, - LWS_WRITE_TEXT); - - if (n < 0) { - fprintf(stderr, "ERROR %d writing to socket\n", n); - exit(1); - } - - if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) - pss->ringbuffer_tail = 0; - else - pss->ringbuffer_tail++; - - if (((ringbuffer_head - pss->ringbuffer_tail) % - MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15)) - libwebsocket_rx_flow_control(wsi, 1); - - libwebsocket_callback_on_writable(this, wsi); - - } - break; - - case LWS_CALLBACK_BROADCAST: - n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT); - if (n < 0) - fprintf(stderr, "mirror write failed\n"); - break; - - case LWS_CALLBACK_RECEIVE: - - if (ringbuffer[ringbuffer_head].payload) - free(ringbuffer[ringbuffer_head].payload); - - ringbuffer[ringbuffer_head].payload = - malloc(LWS_SEND_BUFFER_PRE_PADDING + len + - LWS_SEND_BUFFER_POST_PADDING); - ringbuffer[ringbuffer_head].len = len; - memcpy((char *)ringbuffer[ringbuffer_head].payload + - LWS_SEND_BUFFER_PRE_PADDING, in, len); - if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) - ringbuffer_head = 0; - else - ringbuffer_head++; - - if (((ringbuffer_head - pss->ringbuffer_tail) % - MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) - libwebsocket_rx_flow_control(wsi, 0); - - libwebsocket_callback_on_writable_all_protocol( - libwebsockets_get_protocol(wsi)); - 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((struct lws_tokens *)(long)user); - /* you could return non-zero here and kill the connection */ - break; - - default: - break; - } - - return 0; -} - - -/* list of supported protocols and callbacks */ - -static struct libwebsocket_protocols protocols[] = { - /* first protocol must always be HTTP handler */ - - { - "http-only", /* name */ - callback_http, /* callback */ - 0 /* per_session_data_size */ - }, - { - "dumb-increment-protocol", - callback_dumb_increment, - sizeof(struct per_session_data__dumb_increment), - }, - { - "lws-mirror-protocol", - callback_lws_mirror, - sizeof(struct per_session_data__lws_mirror) - }, - { - NULL, NULL, 0 /* End of list */ - } -}; - -static struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "debug", required_argument, NULL, 'd' }, - { "port", required_argument, NULL, 'p' }, - { "ssl", no_argument, NULL, 's' }, - { "killmask", no_argument, NULL, 'k' }, - { "interface", required_argument, NULL, 'i' }, - { 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"; - unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 + - LWS_SEND_BUFFER_POST_PADDING]; - int port = 7681; - int use_ssl = 0; - struct libwebsocket_context *context; - int opts = 0; - unsigned int oldus = 0; - char interface_name[128] = ""; - const char *interface_ptr = NULL; - - fprintf(stderr, "libwebsockets test server with external poll()\n" - "(C) Copyright 2010-2011 Andy Green " - "licensed under LGPL2.1\n"); - - while (n >= 0) { - n = getopt_long(argc, argv, "i:khsp:d:", options, NULL); - if (n < 0) - continue; - switch (n) { - case 'd': - lws_set_log_level(atoi(optarg), NULL); - break; - case 's': - use_ssl = 1; - break; - case 'k': - opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK; - break; - case 'p': - port = atoi(optarg); - break; - case 'i': - strncpy(interface_name, optarg, sizeof interface_name); - interface_name[(sizeof interface_name) - 1] = '\0'; - interface_ptr = interface_name; - break; - case 'h': - fprintf(stderr, "Usage: test-server " - "[--port=

] [--ssl] " - "[-d ]\n"); - exit(1); - } - } - - if (!use_ssl) - cert_path = key_path = NULL; - - context = libwebsocket_create_context(port, interface_ptr, protocols, - libwebsocket_internal_extensions, - cert_path, key_path, NULL, -1, -1, - opts, NULL); - if (context == NULL) { - fprintf(stderr, "libwebsocket init failed\n"); - return -1; - } - - buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x'; - - /* - * This is an example of an existing application's explicit poll() - * loop that libwebsockets can integrate with. - */ - - while (1) { - struct timeval tv; - - /* - * this represents an existing server's single poll action - * which also includes libwebsocket sockets - */ - - n = poll(pollfds, count_pollfds, 25); - if (n < 0) - goto done; - - if (n) - for (n = 0; n < count_pollfds; n++) - if (pollfds[n].revents) - /* - * returns immediately if the fd does not - * match anything under libwebsockets - * control - */ - if (libwebsocket_service_fd(context, - &pollfds[n])) - goto done; - - /* do our broadcast periodically */ - - gettimeofday(&tv, NULL); - - /* - * This broadcasts to all dumb-increment-protocol connections - * at 20Hz. - * - * We're just sending a character 'x', in these examples the - * callbacks send their own per-connection content. - * - * You have to send something with nonzero length to get the - * callback actions delivered. - * - * We take care of pre-and-post padding allocation. - */ - - if (((unsigned int)tv.tv_usec - oldus) > 50000) { - libwebsockets_broadcast( - &protocols[PROTOCOL_DUMB_INCREMENT], - &buf[LWS_SEND_BUFFER_PRE_PADDING], 1); - oldus = tv.tv_usec; - } - } - -done: - libwebsocket_context_destroy(context); - - return 0; -} diff --git a/test-server/test-server.c b/test-server/test-server.c index 5bda5b1..7593546 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -30,6 +30,17 @@ static int close_testing; +#ifdef EXTERNAL_POLL +#define LWS_NO_FORK +#ifndef MAX_CLIENTS +#define MAX_POLL_ELEMENTS 100 +#else +#define MAX_POLL_ELEMENTS (MAX_CLIENTS) +#endif +struct pollfd pollfds[MAX_POLL_ELEMENTS]; +int count_pollfds = 0; +#endif + /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server @@ -68,6 +79,9 @@ static int callback_http(struct libwebsocket_context *context, { char client_name[128]; char client_ip[128]; +#ifdef EXTERNAL_POLL + int n; +#endif switch (reason) { case LWS_CALLBACK_HTTP: @@ -108,6 +122,48 @@ static int callback_http(struct libwebsocket_context *context, /* if we returned non-zero from here, we kill the connection */ break; +#ifdef EXTERNAL_POLL + /* + * callbacks for managing the external poll() array appear in + * protocol 0 callback + */ + + case LWS_CALLBACK_ADD_POLL_FD: + if (count_pollfds == MAX_POLL_ELEMENTS) + return 1; + + pollfds[count_pollfds].fd = (int)(long)user; + pollfds[count_pollfds].events = (int)len; + pollfds[count_pollfds++].revents = 0; + break; + + case LWS_CALLBACK_DEL_POLL_FD: + for (n = 0; n < count_pollfds; n++) { + if (pollfds[n].fd != (int)(long)user) + continue; + /* + * swap the end guy into our vacant slot... + * works ok if n is the end guy + */ + pollfds[n] = pollfds[count_pollfds - 1]; + pollfds[count_pollfds - 1].fd = -1; + count_pollfds--; + break; + } + break; + + case LWS_CALLBACK_SET_MODE_POLL_FD: + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].fd == (int)(long)user) + pollfds[n].events |= (int)(long)len; + break; + + case LWS_CALLBACK_CLEAR_MODE_POLL_FD: + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].fd == (int)(long)user) + pollfds[n].events &= ~(int)(long)len; + break; +#endif default: break; } @@ -506,8 +562,32 @@ int main(int argc, char **argv) * immediately and quickly. Negative return means we are * in process of closing */ +#ifdef EXTERNAL_POLL + + /* + * this represents an existing server's single poll action + * which also includes libwebsocket sockets + */ + n = poll(pollfds, count_pollfds, 50); + if (n < 0) + continue; + + if (n) + for (n = 0; n < count_pollfds; n++) + if (pollfds[n].revents) + /* + * returns immediately if the fd does not + * match anything under libwebsockets + * control + */ + if (libwebsocket_service_fd(context, + &pollfds[n]) < 0) + goto done; + +#else n = libwebsocket_service(context, 50); +#endif } #else @@ -551,6 +631,9 @@ int main(int argc, char **argv) } #endif +#ifdef EXTERNAL_POLL +done: +#endif libwebsocket_context_destroy(context);