diff --git a/test/compatibility/cpp/libwebsockets/devnull_client.cpp b/test/compatibility/cpp/libwebsockets/devnull_client.cpp new file mode 100644 index 00000000..9d651541 --- /dev/null +++ b/test/compatibility/cpp/libwebsockets/devnull_client.cpp @@ -0,0 +1,189 @@ +/* + * lws-minimal-ws-client + * + * Written in 2010-2019 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates the a minimal ws client using lws. + * + * Original programs connects to https://libwebsockets.org/ and makes a + * wss connection to the dumb-increment protocol there. While + * connected, it prints the numbers it is being sent by + * dumb-increment protocol. + * + * This is modified to make a test client which counts how much messages + * per second can be received. + * + * libwebsockets$ make && ./a.out + * g++ --std=c++14 -I/usr/local/opt/openssl/include devnull_client.cpp -lwebsockets + * messages received: 0 per second 0 total + * [2020/08/02 19:22:21:4774] U: LWS minimal ws client rx [-d ] [--h2] + * [2020/08/02 19:22:21:4814] U: callback_dumb_increment: established + * messages received: 0 per second 0 total + * messages received: 180015 per second 180015 total + * messages received: 172866 per second 352881 total + * messages received: 176177 per second 529058 total + * messages received: 174191 per second 703249 total + * messages received: 193397 per second 896646 total + * messages received: 196385 per second 1093031 total + * messages received: 194593 per second 1287624 total + * messages received: 189484 per second 1477108 total + * messages received: 200825 per second 1677933 total + * messages received: 183542 per second 1861475 total + * ^C[2020/08/02 19:22:33:4450] U: Completed OK + * + */ + +#include +#include +#include + +#include +#include +#include + +static int interrupted; +static struct lws *client_wsi; + +std::atomic receivedCount(0); + +static int +callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + switch (reason) { + + /* because we are protocols[0] ... */ + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", + in ? (char *)in : "(null)"); + client_wsi = NULL; + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + lwsl_user("%s: established\n", __func__); + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + receivedCount++; + break; + + case LWS_CALLBACK_CLIENT_CLOSED: + client_wsi = NULL; + break; + + default: + break; + } + + return lws_callback_http_dummy(wsi, reason, user, in, len); +} + +static const struct lws_protocols protocols[] = { + { + "dumb-increment-protocol", + callback_dumb_increment, + 0, + 0, + }, + { NULL, NULL, 0, 0 } +}; + +static void +sigint_handler(int sig) +{ + interrupted = 1; +} + +int main(int argc, const char **argv) +{ + uint64_t receivedCountTotal(0); + uint64_t receivedCountPerSecs(0); + + auto timer = [&receivedCountTotal, &receivedCountPerSecs] { + while (!interrupted) + { + std::cerr << "messages received: " + << receivedCountPerSecs + << " per second " + << receivedCountTotal + << " total" + << std::endl; + + receivedCountPerSecs = receivedCount - receivedCountTotal; + receivedCountTotal += receivedCountPerSecs; + + auto duration = std::chrono::seconds(1); + std::this_thread::sleep_for(duration); + } + }; + + std::thread t1(timer); + + struct lws_context_creation_info info; + struct lws_client_connect_info i; + struct lws_context *context; + const char *p; + int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* for LLL_ verbosity above NOTICE to be built into lws, lws + * must have been configured with -DCMAKE_BUILD_TYPE=DEBUG + * instead of =RELEASE */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ + /* | LLL_DEBUG */; + + signal(SIGINT, sigint_handler); + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal ws client rx [-d ] [--h2]\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ + info.protocols = protocols; + info.timeout_secs = 10; + + /* + * since we know this lws context is only ever going to be used with + * one client wsis / fds / sockets at a time, let lws know it doesn't + * have to use the default allocations for fd tables up to ulimit -n. + * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we + * will use. + */ + info.fd_limit_per_thread = 1 + 1 + 1; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */ + i.context = context; + i.port = 8008; + i.address = "127.0.0.1"; + i.path = "/"; + i.host = i.address; + i.origin = i.address; + i.protocol = protocols[0].name; /* "dumb-increment-protocol" */ + i.pwsi = &client_wsi; + + if (lws_cmdline_option(argc, argv, "--h2")) + i.alpn = "h2"; + + lws_client_connect_via_info(&i); + + while (n >= 0 && client_wsi && !interrupted) + n = lws_service(context, 0); + + lws_context_destroy(context); + + lwsl_user("Completed %s\n", receivedCount > 10 ? "OK" : "Failed"); + + t1.join(); + + return receivedCount > 10; +}