2 * lws-minimal-ws-client-spam
4 * Written in 2010-2019 by Andy Green <andy@warmcat.com>
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
9 * This demonstrates a ws client that makes continuous mass ws connections
13 #include <libwebsockets.h>
30 static struct lws_context *context;
31 static struct client clients[200];
32 static int interrupted, port = 443, ssl_connection = LCCSCF_USE_SSL;
33 static const char *server_address = "libwebsockets.org",
34 *pro = "lws-mirror-protocol";
35 static int concurrent = 3, conn, tries, est, errors, closed, sent, limit = 15;
42 connect_client(int idx)
44 struct lws_client_connect_info i;
47 lwsl_user("Reached limit... finishing\n");
51 memset(&i, 0, sizeof(i));
55 i.address = server_address;
59 i.ssl_connection = ssl_connection;
61 i.local_protocol_name = pro;
62 i.pwsi = &clients[idx].wsi;
64 clients[idx].state = CLIENT_CONNECTING;
67 if (!lws_client_connect_via_info(&i)) {
68 clients[idx].wsi = NULL;
69 clients[idx].state = CLIENT_IDLE;
78 callback_minimal_spam(struct lws *wsi, enum lws_callback_reasons reason,
79 void *user, void *in, size_t len)
81 struct pss *pss = (struct pss *)user;
82 uint8_t ping[LWS_PRE + 125];
87 case LWS_CALLBACK_PROTOCOL_INIT:
88 for (n = 0; n < concurrent; n++) {
94 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
96 lwsl_err("CLIENT_CONNECTION_ERROR: %s (try %d, est %d, closed %d, err %d)\n",
97 in ? (char *)in : "(null)", tries, est, closed, errors);
98 for (n = 0; n < concurrent; n++) {
99 if (clients[n].wsi == wsi) {
100 clients[n].wsi = NULL;
101 clients[n].state = CLIENT_IDLE;
106 if (tries == closed + errors)
110 /* --- client callbacks --- */
112 case LWS_CALLBACK_CLIENT_ESTABLISHED:
113 lwsl_user("%s: established (try %d, est %d, closed %d, err %d)\n",
114 __func__, tries, est, closed, errors);
117 lws_callback_on_writable(wsi);
120 case LWS_CALLBACK_CLIENT_CLOSED:
122 if (tries == closed + errors)
124 if (tries == limit) {
125 lwsl_user("%s: leaving CLOSED (try %d, est %d, sent %d, closed %d, err %d)\n",
126 __func__, tries, est, sent, closed, errors);
130 for (n = 0; n < concurrent; n++) {
131 if (clients[n].wsi == wsi) {
133 lwsl_user("%s: reopening (try %d, est %d, closed %d, err %d)\n",
134 __func__, tries, est, closed, errors);
139 lwsl_user("CLOSED: can't find client wsi\n");
142 case LWS_CALLBACK_CLIENT_WRITEABLE:
143 n = lws_snprintf((char *)ping + LWS_PRE, sizeof(ping) - LWS_PRE,
144 "hello %d", pss->conn);
146 m = lws_write(wsi, ping + LWS_PRE, n, LWS_WRITE_TEXT);
148 lwsl_err("sending ping failed: %d\n", m);
152 lws_set_timeout(wsi, PENDING_TIMEOUT_USER_OK, LWS_TO_KILL_ASYNC);
159 return lws_callback_http_dummy(wsi, reason, user, in, len);
162 static const struct lws_protocols protocols[] = {
165 callback_minimal_spam,
173 sigint_handler(int sig)
178 int main(int argc, const char **argv)
180 struct lws_context_creation_info info;
182 int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
183 /* for LLL_ verbosity above NOTICE to be built into lws,
184 * lws must have been configured and built with
185 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
186 /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
187 /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
190 signal(SIGINT, sigint_handler);
192 if ((p = lws_cmdline_option(argc, argv, "-d")))
195 lws_set_log_level(logs, NULL);
196 lwsl_user("LWS minimal ws client SPAM\n");
198 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
199 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
200 info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
201 info.protocols = protocols;
202 #if defined(LWS_WITH_MBEDTLS)
204 * OpenSSL uses the system trust store. mbedTLS has to be told which
205 * CA to trust explicitly.
207 info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
210 if ((p = lws_cmdline_option(argc, argv, "--server"))) {
212 ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
215 if ((p = lws_cmdline_option(argc, argv, "--port")))
218 if ((p = lws_cmdline_option(argc, argv, "-l")))
221 if ((p = lws_cmdline_option(argc, argv, "-c")))
222 concurrent = atoi(p);
224 if (lws_cmdline_option(argc, argv, "-n")) {
229 if (concurrent < 0 ||
230 concurrent > (int)LWS_ARRAY_SIZE(clients)) {
231 lwsl_err("%s: -c %d larger than max concurrency %d\n", __func__,
232 concurrent, (int)LWS_ARRAY_SIZE(clients));
238 * since we know this lws context is only ever going to be used with
239 * one client wsis / fds / sockets at a time, let lws know it doesn't
240 * have to use the default allocations for fd tables up to ulimit -n.
241 * It will just allocate for 1 internal and n (+ 1 http2 nwsi) that we
244 info.fd_limit_per_thread = 1 + concurrent + 1;
246 context = lws_create_context(&info);
248 lwsl_err("lws init failed\n");
252 while (n >= 0 && !interrupted)
253 n = lws_service(context, 0);
255 lws_context_destroy(context);
257 if (tries == limit && closed == tries) {
258 lwsl_user("Completed\n");
262 lwsl_err("Failed\n");