X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=test-server%2Ftest-client.c;h=b35260db57420e3e5f0e3016c039ceeb451e1ee9;hb=a19ff9b24d39b524b1f47a9e94b3b8d5b1e8970e;hp=734aab20b5a0a6925f20d2933fe6af47d4168137;hpb=b6e6ebeece2cb279c23fb1749fda08362fc0f912;p=platform%2Fupstream%2Flibwebsockets.git diff --git a/test-server/test-client.c b/test-server/test-client.c index 734aab2..b35260d 100644 --- a/test-server/test-client.c +++ b/test-server/test-client.c @@ -1,33 +1,44 @@ /* * libwebsockets-test-client - libwebsockets test implementation * - * Copyright (C) 2011 Andy Green + * Copyright (C) 2011-2016 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 file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. * - * 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. + * 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. * - * 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 + * 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 #include -#include #include #include - +#include + +#ifdef _WIN32 +#define random rand +#include "gettimeofday.h" +#else +#include +#include +#include +#endif #include "../lib/libwebsockets.h" -#include + +static int deny_deflate, deny_mux, longlived, mirror_lifetime; +static struct lws *wsi_dumb, *wsi_mirror; +static volatile int force_exit; +static unsigned int opts; /* * This demo shows how to connect multiple websockets simultaneously to a @@ -52,18 +63,67 @@ enum demo_protocols { }; -/* dumb_increment protocol */ +/* + * dumb_increment protocol + * + * since this also happens to be protocols[0], some callbacks that are not + * bound to a specific protocol also turn up here. + */ static int -callback_dumb_increment(struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, - void *user, void *in, size_t len) +callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) { + char *buf = (char *)in; + switch (reason) { + case LWS_CALLBACK_CLIENT_ESTABLISHED: + lwsl_info("dumb: LWS_CALLBACK_CLIENT_ESTABLISHED\n"); + break; + + case LWS_CALLBACK_CLOSED: + lwsl_notice("dumb: LWS_CALLBACK_CLOSED\n"); + wsi_dumb = NULL; + break; + case LWS_CALLBACK_CLIENT_RECEIVE: ((char *)in)[len] = '\0'; - fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); + lwsl_info("rx %d '%s'\n", (int)len, (char *)in); + break; + + /* because we are protocols[0] ... */ + + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + if (wsi == wsi_dumb) { + lwsl_err("dumb: LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); + wsi_dumb = NULL; + } + if (wsi == wsi_mirror) { + lwsl_err("mirror: LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); + wsi_mirror = NULL; + } + break; + + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + if ((strcmp(in, "deflate-stream") == 0) && deny_deflate) { + lwsl_notice("denied deflate-stream extension\n"); + return 1; + } + if ((strcmp(in, "x-webkit-deflate-frame") == 0)) + return 1; + if ((strcmp(in, "deflate-frame") == 0)) + return 1; + break; + + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: + while (len--) + putchar(*buf++); + break; + + case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: + wsi_dumb = NULL; + force_exit = 1; break; default: @@ -78,53 +138,72 @@ callback_dumb_increment(struct libwebsocket *wsi, static int -callback_lws_mirror(struct libwebsocket *wsi, - enum libwebsocket_callback_reasons reason, - void *user, void *in, size_t len) +callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) { - unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + - LWS_SEND_BUFFER_POST_PADDING]; - int l; + unsigned char buf[LWS_PRE + 4096]; + unsigned int rands[4]; + int l = 0; + int n; switch (reason) { - case LWS_CALLBACK_CLIENT_ESTABLISHED: + lwsl_notice("mirror: LWS_CALLBACK_CLIENT_ESTABLISHED\n"); + + lws_get_random(lws_get_context(wsi), rands, sizeof(rands[0])); + mirror_lifetime = 16384 + (rands[0] & 65535); + /* useful to test single connection stability */ + if (longlived) + mirror_lifetime += 500000; + + lwsl_info("opened mirror connection with " + "%d lifetime\n", mirror_lifetime); + /* + * mirror_lifetime is decremented each send, when it reaches + * zero the connection is closed in the send callback. + * When the close callback comes, wsi_mirror is set to NULL + * so a new connection will be opened + * * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service */ - - libwebsocket_callback_on_writable(wsi); + lws_callback_on_writable(wsi); break; - case LWS_CALLBACK_CLIENT_RECEIVE: -/* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */ + case LWS_CALLBACK_CLOSED: + lwsl_notice("mirror: LWS_CALLBACK_CLOSED mirror_lifetime=%d\n", mirror_lifetime); + wsi_mirror = NULL; break; case LWS_CALLBACK_CLIENT_WRITEABLE: + for (n = 0; n < 1; n++) { + lws_get_random(lws_get_context(wsi), rands, sizeof(rands)); + l += sprintf((char *)&buf[LWS_PRE + l], + "c #%06X %u %u %u;", + rands[0] & 0xffffff, /* colour */ + rands[1] & 511, /* x */ + rands[2] & 255, /* y */ + (rands[3] & 31) + 1); /* radius */ + } - l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], - "c #%06X %d %d %d;", - (int)random() & 0xffffff, - (int)random() % 500, - (int)random() % 250, - (int)random() % 24); - - libwebsocket_write(wsi, - &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT); + n = lws_write(wsi, &buf[LWS_PRE], l, + opts | LWS_WRITE_TEXT); + if (n < 0) + return -1; + if (n < l) { + lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n"); + return -1; + } + mirror_lifetime--; + if (!mirror_lifetime) { + lwsl_info("closing mirror session\n"); + return -1; + } /* get notified as soon as we can write again */ - - libwebsocket_callback_on_writable(wsi); - - /* - * without at least this delay, we choke the browser - * and the connection stalls, despite we now take care about - * flow control - */ - - usleep(200); + lws_callback_on_writable(wsi); break; default: @@ -137,65 +216,139 @@ callback_lws_mirror(struct libwebsocket *wsi, /* list of supported protocols and callbacks */ -static struct libwebsocket_protocols protocols[] = { +static struct lws_protocols protocols[] = { + { + "dumb-increment-protocol,fake-nonexistant-protocol", + callback_dumb_increment, + 0, + 20, + }, + { + "fake-nonexistant-protocol,lws-mirror-protocol", + callback_lws_mirror, + 0, + 128, + }, + { NULL, NULL, 0, 0 } /* end */ +}; - [PROTOCOL_DUMB_INCREMENT] = { - .name = "dumb-increment-protocol", - .callback = callback_dumb_increment, +static const struct lws_extension exts[] = { + { + "permessage-deflate", + lws_extension_callback_pm_deflate, + "permessage-deflate; client_max_window_bits" }, - [PROTOCOL_LWS_MIRROR] = { - .name = "lws-mirror-protocol", - .callback = callback_lws_mirror, + { + "deflate-frame", + lws_extension_callback_pm_deflate, + "deflate_frame" }, - [DEMO_PROTOCOL_COUNT] = { /* end of list */ - .callback = NULL - } + { NULL, NULL, NULL /* terminator */ } }; + + +void sighandler(int sig) +{ + force_exit = 1; +} + static struct option options[] = { { "help", no_argument, NULL, 'h' }, + { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, + { "version", required_argument, NULL, 'v' }, + { "undeflated", no_argument, NULL, 'u' }, + { "nomux", no_argument, NULL, 'n' }, + { "longlived", no_argument, NULL, 'l' }, { NULL, 0, 0, 0 } }; +static int ratelimit_connects(unsigned int *last, unsigned int secs) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + if (tv.tv_sec - (*last) < secs) + return 0; + + *last = tv.tv_sec; + + return 1; +} int main(int argc, char **argv) { - int n = 0; - int port = 7681; - int use_ssl = 0; - struct libwebsocket_context *context; - const char *address = argv[1]; - struct libwebsocket *wsi_dumb; - struct libwebsocket *wsi_mirror; + int n = 0, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1; + unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1; + struct lws_context_creation_info info; + struct lws_client_connect_info i; + struct lws_context *context; + const char *prot, *p; + char path[300]; + memset(&info, 0, sizeof info); - fprintf(stderr, "libwebsockets test client\n" - "(C) Copyright 2010 Andy Green " - "licensed under LGPL2.1\n"); + lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n"); + lwsl_notice("(C) Copyright 2010-2016 Andy Green \n"); if (argc < 2) goto usage; - optind++; - while (n >= 0) { - n = getopt_long(argc, argv, "hsp:", options, NULL); + n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL); if (n < 0) continue; switch (n) { + case 'd': + lws_set_log_level(atoi(optarg), NULL); + break; case 's': use_ssl = 2; /* 2 = allow selfsigned */ break; case 'p': port = atoi(optarg); break; + case 'l': + longlived = 1; + break; + case 'v': + ietf_version = atoi(optarg); + break; + case 'u': + deny_deflate = 1; + break; + case 'n': + deny_mux = 1; + break; case 'h': goto usage; } } + if (optind >= argc) + goto usage; + + signal(SIGINT, sighandler); + + memset(&i, 0, sizeof(i)); + + i.port = port; + if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &p)) + goto usage; + + /* add back the leading / on path */ + path[0] = '/'; + strncpy(path + 1, p, sizeof(path) - 2); + path[sizeof(path) - 1] = '\0'; + i.path = path; + + if (!strcmp(prot, "http") || !strcmp(prot, "ws")) + use_ssl = 0; + if (!strcmp(prot, "https") || !strcmp(prot, "wss")) + use_ssl = 1; + /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, @@ -204,57 +357,76 @@ int main(int argc, char **argv) * For this client-only demo, we tell it to not listen on any port. */ - context = libwebsocket_create_context(CONTEXT_PORT_NO_LISTEN, - protocols, NULL, NULL, -1, -1); + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = protocols; + 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; } + i.context = context; + i.ssl_connection = use_ssl; + i.host = i.address; + i.origin = i.address; + i.ietf_version_or_minus_one = ietf_version; + i.client_exts = exts; - /* create a client websocket using dumb increment protocol */ - - wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl, - "/", "http://host", "origin", - protocols[PROTOCOL_DUMB_INCREMENT].name); - - if (wsi_dumb == NULL) { - fprintf(stderr, "libwebsocket dumb connect failed\n"); - return -1; - } - - /* create a client websocket using mirror protocol */ - - wsi_mirror = libwebsocket_client_connect(context, address, port, - use_ssl, "/", "http://host", "origin", - protocols[PROTOCOL_LWS_MIRROR].name); - - if (wsi_mirror == NULL) { - fprintf(stderr, "libwebsocket dumb connect failed\n"); - return -1; - } - - fprintf(stderr, "Websocket connections opened\n"); + if (!strcmp(prot, "http") || !strcmp(prot, "https")) { + lwsl_notice("using %s mode (non-ws)\n", prot); + i.method = "GET"; + do_ws = 0; + } else + lwsl_notice("using %s mode (ws)\n", prot); /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket + * + * nothing happens until the client websocket connection is + * asynchronously established... calling lws_client_connect() only + * instantiates the connection logically, lws_service() progresses it + * asynchronously. */ - n = 0; - while (n >= 0) - n = libwebsocket_service(context, 1000); - - libwebsocket_client_close(wsi_dumb); - libwebsocket_client_close(wsi_mirror); + while (!force_exit) { + + if (do_ws) { + if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { + lwsl_notice("dumb: connecting\n"); + i.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; + wsi_dumb = lws_client_connect_via_info(&i); + } + + if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { + lwsl_notice("mirror: connecting\n"); + i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; + wsi_mirror = lws_client_connect_via_info(&i); + } + } else + if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { + lwsl_notice("http: connecting\n"); + wsi_dumb = lws_client_connect_via_info(&i); + } + + lws_service(context, 500); + } - libwebsocket_context_destroy(context); + lwsl_err("Exiting\n"); + lws_context_destroy(context); - return 0; + return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " - " [--port=

] " - "[--ssl]\n"); + " [--port=

] " + "[--ssl] [-k] [-v ] " + "[-d ] [-l]\n"); return 1; }