Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1713592365, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"65094ea5db5f95562d4bb2378da18e10", "oid":{ "oid": "f28a45246e7ea479718ddba5e80deb355b23f5f3", "alias": [ "refs/heads/main"]},"blobname": "test-apps/test-client.c", "blob": "/*\n * libwebsockets-test-client - libwebsockets test implementation\n *\n * Written in 2010-2019 by Andy Green \u003candy@warmcat.com\u003e\n *\n * This file is made available under the Creative Commons CC0 1.0\n * Universal Public Domain Dedication.\n *\n * The person who associated a work with this deed has dedicated\n * the work to the public domain by waiving all of his or her rights\n * to the work worldwide under copyright law, including all related\n * and neighboring rights, to the extent allowed by law. You can copy,\n * modify, distribute and perform the work, even for commercial purposes,\n * all without asking permission.\n *\n * The test apps are intended to be adapted for use in your code, which\n * may be proprietary. So unlike the library itself, they are licensed\n * Public Domain.\n */\n\n#include \u0022lws_config.h\u0022\n\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)\n#include \u003cgetopt.h\u003e\n#endif\n#include \u003cstring.h\u003e\n#include \u003csignal.h\u003e\n\n#ifdef _WIN32\n#define random rand\n#include \u0022gettimeofday.h\u0022\n#else\n#include \u003csyslog.h\u003e\n#include \u003csys/time.h\u003e\n#include \u003cunistd.h\u003e\n#endif\n\n#include \u003clibwebsockets.h\u003e\n\nstruct lws_poly_gen {\n\tuint32_t cyc[2];\n};\n\n#define block_size (3 * 4096)\n\nstatic int deny_deflate, longlived, mirror_lifetime, test_post, once;\nstatic struct lws *wsi_dumb, *wsi_mirror;\nstatic struct lws *wsi_multi[3];\nstatic volatile int force_exit;\nstatic unsigned int opts, rl_multi[3];\nstatic int flag_no_mirror_traffic, justmirror, flag_echo;\nstatic uint32_t count_blocks \u003d 1024, txb, rxb, rx_count, errs;\nstatic struct lws_poly_gen tx \u003d { { 0xabcde, 0x23456789 } },\n\t\t\t rx \u003d { { 0xabcde, 0x23456789 } }\n;\n\n#if defined(LWS_WITH_TLS) \u0026\u0026 defined(LWS_HAVE_SSL_CTX_set1_param)\nchar crl_path[1024] \u003d \u0022\u0022;\n#endif\n\n/*\n * This demo shows how to connect multiple websockets simultaneously to a\n * websocket server (there is no restriction on their having to be the same\n * server just it simplifies the demo).\n *\n * dumb-increment-protocol: we connect to the server and print the number\n *\t\t\t\twe are given\n *\n * lws-mirror-protocol: draws random circles, which are mirrored on to every\n *\t\t\t\tclient (see them being drawn in every browser\n *\t\t\t\tsession also using the test server)\n */\n\nenum demo_protocols {\n\n\tPROTOCOL_DUMB_INCREMENT,\n\tPROTOCOL_LWS_MIRROR,\n\n\t/* always last */\n\tDEMO_PROTOCOL_COUNT\n};\n\nstatic uint8_t\nlws_poly_rand(struct lws_poly_gen *p)\n{\n\tp-\u003ecyc[0] \u003d (p-\u003ecyc[0] \u0026 1) ? (p-\u003ecyc[0] \u003e\u003e 1) ^ 0xb4bcd35c :\n\t\t\t\t p-\u003ecyc[0] \u003e\u003e 1;\n\tp-\u003ecyc[0] \u003d (p-\u003ecyc[0] \u0026 1) ? (p-\u003ecyc[0] \u003e\u003e 1) ^ 0xb4bcd35c :\n\t\t\t\t p-\u003ecyc[0] \u003e\u003e 1;\n\tp-\u003ecyc[1] \u003d (p-\u003ecyc[1] \u0026 1) ? (p-\u003ecyc[1] \u003e\u003e 1) ^ 0x7a5bc2e3 :\n\t\t\t\t p-\u003ecyc[1] \u003e\u003e 1;\n\n\treturn (uint8_t)(p-\u003ecyc[0] ^ p-\u003ecyc[1]);\n}\n\nstatic void show_http_content(const char *p, size_t l)\n{\n\tif (lwsl_visible(LLL_INFO)) {\n\t\twhile (l--)\n\t\t\tif (*p \u003c 0x7f)\n\t\t\t\tputchar(*p++);\n\t\t\telse\n\t\t\t\tputchar('.');\n\t}\n}\n\n\n/*\n * dumb_increment protocol\n *\n * since this also happens to be protocols[0], some callbacks that are not\n * bound to a specific protocol also turn up here.\n */\n\nstatic int\ncallback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,\n\t\t\tvoid *user, void *in, size_t len)\n{\n#if defined(LWS_WITH_TLS)\n\tunion lws_tls_cert_info_results ci;\n#if defined(LWS_HAVE_CTIME_R) \u0026\u0026 !defined(LWS_WITH_NO_LOGS)\n\tchar date[32];\n#endif\n#endif\n\tconst char *which \u003d \u0022http\u0022;\n char which_wsi[50], buf[80 + LWS_PRE];\n\tint n;\n\n\tswitch (reason) {\n\n\tcase LWS_CALLBACK_CLIENT_ESTABLISHED:\n\t\tlwsl_info(\u0022dumb: LWS_CALLBACK_CLIENT_ESTABLISHED\u005cn\u0022);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLOSED:\n\t\tlwsl_notice(\u0022dumb: LWS_CALLBACK_CLOSED\u005cn\u0022);\n\t\twsi_dumb \u003d NULL;\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_RECEIVE:\n\t\t((char *)in)[len] \u003d '\u005c0';\n\t\tlwsl_info(\u0022rx %d '%s'\u005cn\u0022, (int)len, (char *)in);\n\t\tbreak;\n\n\t/* because we are protocols[0] ... */\n\n\tcase LWS_CALLBACK_CLIENT_CONNECTION_ERROR:\n\t\tif (wsi \u003d\u003d wsi_dumb) {\n\t\t\twhich \u003d \u0022dumb\u0022;\n\t\t\twsi_dumb \u003d NULL;\n\t\t}\n\t\tif (wsi \u003d\u003d wsi_mirror) {\n\t\t\twhich \u003d \u0022mirror\u0022;\n\t\t\twsi_mirror \u003d NULL;\n\t\t}\n\n\t\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(wsi_multi); n++)\n\t\t\tif (wsi \u003d\u003d wsi_multi[n]) {\n\t\t\t\tsprintf(which_wsi, \u0022multi %d\u0022, n);\n\t\t\t\twhich \u003d which_wsi;\n\t\t\t\twsi_multi[n] \u003d NULL;\n\t\t\t}\n\n\t\tlwsl_err(\u0022CLIENT_CONNECTION_ERROR: %s: %s\u005cn\u0022, which,\n\t\t\t in ? (char *)in : \u0022(null)\u0022);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:\n\t\tif ((strcmp((const char *)in, \u0022deflate-stream\u0022) \u003d\u003d 0) \u0026\u0026\n\t\t deny_deflate) {\n\t\t\tlwsl_notice(\u0022denied deflate-stream extension\u005cn\u0022);\n\t\t\treturn 1;\n\t\t}\n\t\tif ((strcmp((const char *)in, \u0022x-webkit-deflate-frame\u0022) \u003d\u003d 0))\n\t\t\treturn 1;\n\t\tif ((strcmp((const char *)in, \u0022deflate-frame\u0022) \u003d\u003d 0))\n\t\t\treturn 1;\n\t\tbreak;\n\n\tcase LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:\n\t\tlwsl_notice(\u0022lws_http_client_http_response %d\u005cn\u0022,\n\t\t\t\tlws_http_client_http_response(wsi));\n#if defined(LWS_WITH_TLS)\n\t\tif (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME,\n\t\t\t\t\t \u0026ci, sizeof(ci.ns.name)))\n\t\t\tlwsl_notice(\u0022 Peer Cert CN : %s\u005cn\u0022, ci.ns.name);\n\n\t\tif (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_ISSUER_NAME,\n\t\t\t\t\t \u0026ci, sizeof(ci.ns.name)))\n\t\t\tlwsl_notice(\u0022 Peer Cert issuer : %s\u005cn\u0022, ci.ns.name);\n\n\t\tif (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_FROM,\n\t\t\t\t\t \u0026ci, 0))\n#if defined(LWS_HAVE_CTIME_R)\n\t\t\tlwsl_notice(\u0022 Peer Cert Valid from: %s\u0022,\n\t\t\t\t\t\tctime_r(\u0026ci.time, date));\n#else\n\t\t\tlwsl_notice(\u0022 Peer Cert Valid from: %s\u0022,\n\t\t\t\t\t\tctime(\u0026ci.time));\n#endif\n\t\tif (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_TO,\n\t\t\t\t\t \u0026ci, 0))\n#if defined(LWS_HAVE_CTIME_R)\n\t\t\tlwsl_notice(\u0022 Peer Cert Valid to : %s\u0022,\n\t\t\t\t\t\tctime_r(\u0026ci.time, date));\n#else\n\t\t\tlwsl_notice(\u0022 Peer Cert Valid to : %s\u0022,\n\t\t\t\t\t\tctime(\u0026ci.time));\n#endif\n\t\tif (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_USAGE,\n\t\t\t\t\t \u0026ci, 0))\n\t\t\tlwsl_notice(\u0022 Peer Cert usage bits: 0x%x\u005cn\u0022, ci.usage);\n#endif\n\t\tbreak;\n\n\t/* chunked content */\n\tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:\n\t\tlwsl_notice(\u0022LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: %ld\u005cn\u0022,\n\t\t\t (long)len);\n\t\tshow_http_content(in, len);\n\t\tbreak;\n\n\t/* unchunked content */\n\tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP:\n\t\t{\n\t\t\tchar buffer[1024 + LWS_PRE];\n\t\t\tchar *px \u003d buffer + LWS_PRE;\n\t\t\tint lenx \u003d sizeof(buffer) - LWS_PRE;\n\n\t\t\t/*\n\t\t\t * Often you need to flow control this by something\n\t\t\t * else being writable. In that case call the api\n\t\t\t * to get a callback when writable here, and do the\n\t\t\t * pending client read in the writeable callback of\n\t\t\t * the output.\n\t\t\t *\n\t\t\t * In the case of chunked content, this will call back\n\t\t\t * LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ once per\n\t\t\t * chunk or partial chunk in the buffer, and report\n\t\t\t * zero length back here.\n\t\t\t */\n\t\t\tif (lws_http_client_read(wsi, \u0026px, \u0026lenx) \u003c 0)\n\t\t\t\treturn -1;\n\t\t}\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_WRITEABLE:\n\t\tlwsl_info(\u0022Client wsi %p writable\u005cn\u0022, wsi);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:\n\t\tif (test_post) {\n\t\t\tunsigned char **p \u003d (unsigned char **)in, *end \u003d (*p) + len;\n\n\t\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH,\n\t\t\t\t\t(unsigned char *)\u002229\u0022, 2, p, end))\n\t\t\t\treturn -1;\n\t\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_TYPE,\n\t\t\t\t\t(unsigned char *)\u0022application/x-www-form-urlencoded\u0022,\n\t\t\t\t\t33, p, end))\n\t\t\t\treturn -1;\n\n\t\t\t/* inform lws we have http body to send */\n\t\t\tlws_client_http_body_pending(wsi, 1);\n\t\t\tlws_callback_on_writable(wsi);\n\t\t}\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:\n\t\tstrcpy(buf + LWS_PRE, \u0022text\u003dhello\u0026send\u003dSend+the+form\u0022);\n\t\tn \u003d lws_write(wsi, (unsigned char *)\u0026buf[LWS_PRE],\n\t\t\t strlen(\u0026buf[LWS_PRE]), LWS_WRITE_HTTP);\n\t\tif (n \u003c 0)\n\t\t\treturn -1;\n\t\t/* we only had one thing to send, so inform lws we are done\n\t\t * if we had more to send, call lws_callback_on_writable(wsi);\n\t\t * and just return 0 from callback. On having sent the last\n\t\t * part, call the below api instead.*/\n\t\tlws_client_http_body_pending(wsi, 0);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_COMPLETED_CLIENT_HTTP:\n\t\twsi_dumb \u003d NULL;\n\t\tforce_exit \u003d 1;\n\t\tbreak;\n\n#if defined(LWS_WITH_TLS) \u0026\u0026 defined(LWS_HAVE_SSL_CTX_set1_param) \u0026\u0026 \u005c\n\t!defined(LWS_WITH_MBEDTLS)\n\tcase LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:\n\t\tif (crl_path[0]) {\n\t\t\t/* Enable CRL checking of the server certificate */\n\t\t\tX509_STORE *store;\n\t\t\tX509_LOOKUP *lookup;\n\t\t\tint n;\n\t\t\tX509_VERIFY_PARAM *param \u003d X509_VERIFY_PARAM_new();\n\t\t\tX509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK);\n\t\t\tSSL_CTX_set1_param((SSL_CTX*)user, param);\n\t\t\tstore \u003d SSL_CTX_get_cert_store((SSL_CTX*)user);\n\t\t\tlookup \u003d X509_STORE_add_lookup(store,\n\t\t\t\t\t\t\tX509_LOOKUP_file());\n\t\t\tn \u003d X509_load_cert_crl_file(lookup, crl_path,\n\t\t\t\t\t\t\tX509_FILETYPE_PEM);\n\t\t\tX509_VERIFY_PARAM_free(param);\n\t\t\tif (n !\u003d 1) {\n\t\t\t\tchar errbuf[256];\n\t\t\t\tconst char *es;\n\n\t\t\t\tn \u003d (int)ERR_get_error();\n\t\t\t\tes \u003d ERR_error_string(\n#if defined(LWS_WITH_BORINGSSL)\n\t\t\t\t\t\t\t (uint32_t)\n#else\n\t\t\t\t\t\t\t (unsigned long)\n#endif\n\t\t\t\t\t\t\t n, errbuf);\n\t\t\t\tlwsl_err(\u0022EXTRA_CLIENT_VERIFY_CERTS: \u0022\n\t\t\t\t\t \u0022SSL error: %s (%d)\u005cn\u0022, es, n);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tbreak;\n#endif\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n\n/* lws-mirror_protocol */\n\n\nstatic int\ncallback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,\n\t\t void *user, void *in, size_t len)\n{\n\tunsigned char buf[LWS_PRE + block_size], *p;\n\tunsigned int rands[4];\n\tint l \u003d 0;\n\tint n;\n\n\tswitch (reason) {\n\tcase LWS_CALLBACK_CLIENT_ESTABLISHED:\n\n\t\tlwsl_notice(\u0022mirror: LWS_CALLBACK_CLIENT_ESTABLISHED\u005cn\u0022);\n\n\t\tif (flag_echo) {\n\t\t\trxb \u003d txb \u003d 0;\n\t\t\trx.cyc[0] \u003d tx.cyc[0] \u003d 0xabcde;\n\t\t\trx.cyc[1] \u003d tx.cyc[1] \u003d 0x23456789;\n\n\t\t\tlws_callback_on_writable(wsi);\n\n\t\t\tbreak;\n\t\t}\n\n\t\tlws_get_random(lws_get_context(wsi), rands, sizeof(rands[0]));\n\t\tmirror_lifetime \u003d (int)(16384 + (rands[0] \u0026 65535));\n\t\t/* useful to test single connection stability */\n\t\tif (longlived)\n\t\t\tmirror_lifetime +\u003d 500000;\n\n\t\tlwsl_notice(\u0022opened mirror connection with \u0022\n\t\t\t \u0022%d lifetime\u005cn\u0022, mirror_lifetime);\n\n\t\t/*\n\t\t * mirror_lifetime is decremented each send, when it reaches\n\t\t * zero the connection is closed in the send callback.\n\t\t * When the close callback comes, wsi_mirror is set to NULL\n\t\t * so a new connection will be opened\n\t\t *\n\t\t * start the ball rolling,\n\t\t * LWS_CALLBACK_CLIENT_WRITEABLE will come next service\n\t\t */\n\t\tif (!flag_no_mirror_traffic)\n\t\t\tlws_callback_on_writable(wsi);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_CLOSED:\n\t\tlwsl_notice(\u0022mirror: LWS_CALLBACK_CLOSED mirror_lifetime\u003d%d, \u0022\n\t\t\t \u0022rxb %d, rx_count %d\u005cn\u0022, mirror_lifetime, rxb,\n\t\t\t rx_count);\n\t\twsi_mirror \u003d NULL;\n\t\tif (flag_echo || once)\n\t\t\tforce_exit \u003d 1;\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_WRITEABLE:\n\t\tlwsl_user(\u0022LWS_CALLBACK_CLIENT_WRITEABLE\u005cn\u0022);\n\t\tif (flag_no_mirror_traffic)\n\t\t\treturn 0;\n\n\t\tif (flag_echo) {\n\t\t\tfor (n \u003d 0; n \u003c (int)block_size; n++)\n\t\t\t\tbuf[LWS_PRE + n] \u003d lws_poly_rand(\u0026tx);\n\n\t\t\tn \u003d lws_write(wsi, \u0026buf[LWS_PRE], block_size,\n\t\t\t\t opts | LWS_WRITE_TEXT);\n\t\t\tif (n \u003c 0) {\n\t\t\t\tlwsl_err(\u0022Error sending\u005cn\u0022);\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\ttxb++;\n\t\t\tif (txb !\u003d count_blocks)\n\t\t\t\tlws_callback_on_writable(wsi);\n\t\t\telse {\n\t\t\t\tlwsl_notice(\u0022send completed: %d x %d\u005cn\u0022,\n\t\t\t\t\t count_blocks, block_size);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tfor (n \u003d 0; n \u003c 1; n++) {\n\t\t\tlws_get_random(lws_get_context(wsi), rands,\n\t\t\t\t sizeof(rands));\n\t\t\tl +\u003d sprintf((char *)\u0026buf[LWS_PRE + l],\n\t\t\t\t\t\u0022c #%06X %u %u %u;\u0022,\n\t\t\t\t\trands[0] \u0026 0xffffff,\t/* colour */\n\t\t\t\t\trands[1] \u0026 511,\t\t/* x */\n\t\t\t\t\trands[2] \u0026 255,\t\t/* y */\n\t\t\t\t\t(rands[3] \u0026 31) + 1);\t/* radius */\n\t\t}\n\n\t\tn \u003d (int)lws_write(wsi, \u0026buf[LWS_PRE], (unsigned int)l,\n\t\t\t opts | LWS_WRITE_TEXT);\n\t\tif (n \u003c 0)\n\t\t\treturn -1;\n\t\tif (n \u003c l) {\n\t\t\tlwsl_err(\u0022Partial write LWS_CALLBACK_CLIENT_WRITEABLE\u005cn\u0022);\n\t\t\treturn -1;\n\t\t}\n\t\tif (!justmirror)\n\t\t\tmirror_lifetime--;\n\t\tif (!mirror_lifetime) {\n\t\t\tlwsl_notice(\u0022closing mirror session\u005cn\u0022);\n\t\t\treturn -1;\n\t\t}\n\t\t/* get notified as soon as we can write again */\n\t\tlws_callback_on_writable(wsi);\n\n#if !defined(_WIN32) \u0026\u0026 !defined(WIN32)\n\t\tusleep(50);\n#endif\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLIENT_RECEIVE:\n\t\tif (flag_echo) {\n\t\t\tp \u003d (unsigned char *)in;\n\t\t\tfor (n \u003d 0; n \u003c (int)len; n++)\n\t\t\t\tif (*p++ !\u003d lws_poly_rand(\u0026rx)) {\n\t\t\t\t\tlwsl_err(\u0022mismatch at rxb %d offset %d\u005cn\u0022, (int)rxb + (n / block_size), n % block_size);\n\t\t\t\t\terrs++;\n\t\t\t\t\tforce_exit \u003d 1;\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\trx_count +\u003d (unsigned int)(unsigned long long)len;\n\t\t\twhile (rx_count \u003e\u003d block_size) {\n\t\t\t\trx_count -\u003d block_size;\n\t\t\t\trxb++;\n\t\t\t}\n\t\t\tif (rx_count \u003d\u003d 0 \u0026\u0026 rxb \u003d\u003d count_blocks) {\n\t\t\t\tlwsl_notice(\u0022Everything received: errs %d\u005cn\u0022,\n\t\t\t\t\t errs);\n\t\t\t\tforce_exit \u003d 1;\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstatic int\ncallback_test_raw_client(struct lws *wsi, enum lws_callback_reasons reason,\n\t\t\t void *user, void *in, size_t len)\n{\n\tswitch (reason) {\n\tcase LWS_CALLBACK_RAW_ADOPT:\n\t\tlwsl_notice(\u0022LWS_CALLBACK_RAW_ADOPT\u005cn\u0022);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_RAW_RX:\n\t\tlwsl_notice(\u0022LWS_CALLBACK_RAW_RX %ld\u005cn\u0022, (long)len);\n\t\tputs(in);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_RAW_CLOSE:\n\t\tlwsl_notice(\u0022LWS_CALLBACK_RAW_CLOSE\u005cn\u0022);\n\t\tbreak;\n\n\tcase LWS_CALLBACK_RAW_WRITEABLE:\n\t\tlwsl_notice(\u0022LWS_CALLBACK_RAW_WRITEABLE\u005cn\u0022);\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n/* list of supported protocols and callbacks */\n\nstatic const struct lws_protocols protocols[] \u003d {\n\t{\n\t\t\u0022dumb-increment-protocol\u0022,\n\t\tcallback_dumb_increment,\n\t\t0, 20, 0, NULL, 0\n\t},\n\t{\n\t\t\u0022lws-mirror-protocol\u0022,\n\t\tcallback_lws_mirror,\n\t\t0, 4096, 0, NULL, 0\n\t}, {\n\t\t\u0022lws-test-raw-client\u0022,\n\t\tcallback_test_raw_client,\n\t\t0, 128, 0, NULL, 0\n\t},\n\tLWS_PROTOCOL_LIST_TERM\n};\n\n#if defined(LWS_ROLE_WS) \u0026\u0026 !defined(LWS_WITHOUT_EXTENSIONS)\nstatic const struct lws_extension exts[] \u003d {\n\t{\n\t\t\u0022permessage-deflate\u0022,\n\t\tlws_extension_callback_pm_deflate,\n\t\t\u0022permessage-deflate; client_no_context_takeover\u0022\n\t},\n\t{\n\t\t\u0022deflate-frame\u0022,\n\t\tlws_extension_callback_pm_deflate,\n\t\t\u0022deflate_frame\u0022\n\t},\n\t{ NULL, NULL, NULL /* terminator */ }\n};\n#endif\n\n\nvoid sighandler(int sig)\n{\n\tforce_exit \u003d 1;\n}\n\n#if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)\nstatic struct option options[] \u003d {\n\t{ \u0022help\u0022,\tno_argument,\t\tNULL, 'h' },\n\t{ \u0022debug\u0022, required_argument, NULL, 'd' },\n\t{ \u0022port\u0022,\trequired_argument,\tNULL, 'p' },\n\t{ \u0022ssl\u0022,\tno_argument,\t\tNULL, 's' },\n\t{ \u0022strict-ssl\u0022,\tno_argument,\t\tNULL, 'S' },\n\t{ \u0022version\u0022,\trequired_argument,\tNULL, 'v' },\n\t{ \u0022undeflated\u0022,\tno_argument,\t\tNULL, 'u' },\n\t{ \u0022echo\u0022,\tno_argument,\t\tNULL, 'e' },\n\t{ \u0022multi-test\u0022,\tno_argument,\t\tNULL, 'm' },\n\t{ \u0022nomirror\u0022,\tno_argument,\t\tNULL, 'n' },\n\t{ \u0022justmirror\u0022,\tno_argument,\t\tNULL, 'j' },\n\t{ \u0022longlived\u0022,\tno_argument,\t\tNULL, 'l' },\n\t{ \u0022post\u0022,\tno_argument,\t\tNULL, 'o' },\n\t{ \u0022once\u0022,\tno_argument,\t\tNULL, 'O' },\n\t{ \u0022ssl-cert\u0022, required_argument,\tNULL, 'C' },\n\t{ \u0022ssl-key\u0022, required_argument,\tNULL, 'K' },\n\t{ \u0022ssl-ca\u0022, required_argument,\t\tNULL, 'A' },\n#if defined(LWS_WITH_TLS) \u0026\u0026 defined(LWS_HAVE_SSL_CTX_set1_param)\n\t{ \u0022ssl-crl\u0022, required_argument,\t\tNULL, 'R' },\n#endif\n\t{ NULL, 0, 0, 0 }\n};\n#endif\n\nstatic int ratelimit_connects(unsigned int *last, unsigned int secs)\n{\n\tstruct timeval tv;\n\n\tgettimeofday(\u0026tv, NULL);\n\n\tif ((unsigned long)tv.tv_sec - (unsigned long)(*last) \u003c (unsigned long)secs)\n\t\treturn 0;\n\n\t*last \u003d (unsigned int)tv.tv_sec;\n\n\treturn 1;\n}\n\nint main(int argc, char **argv)\n{\n\tint n \u003d 0, m, ret \u003d 0, port \u003d 7681, use_ssl \u003d 0, ietf_version \u003d -1;\n\tunsigned int rl_dumb \u003d 0, rl_mirror \u003d 0, do_ws \u003d 1, do_multi \u003d 0;\n\tstruct lws_context_creation_info info;\n\tstruct lws_client_connect_info i;\n\tstruct lws_context *context;\n\tconst char *prot, *p;\n\tchar path[300];\n\tchar cert_path[1024] \u003d \u0022\u0022;\n\tchar key_path[1024] \u003d \u0022\u0022;\n\tchar ca_path[1024] \u003d \u0022\u0022;\n\tunsigned long last \u003d lws_now_secs();\n\n\tmemset(\u0026info, 0, sizeof info);\n\n\tlwsl_notice(\u0022libwebsockets test client - license MIT\u005cn\u0022);\n\tlwsl_notice(\u0022(C) Copyright 2010-2018 Andy Green \u003candy@warmcat.com\u003e\u005cn\u0022);\n\n\tif (argc \u003c 2)\n\t\tgoto usage;\n\n\twhile (n \u003e\u003d 0) {\n#if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)\n n \u003d getopt_long(argc, argv, \u0022Sjnuv:hsp:d:lC:K:A:moeO\u0022, options, NULL);\n#else\n n \u003d getopt(argc, argv, \u0022Sjnuv:hsp:d:lC:K:A:moeO\u0022);\n#endif\n\t\tif (n \u003c 0)\n\t\t\tcontinue;\n\t\tswitch (n) {\n\t\tcase 'd':\n\t\t\tlws_set_log_level(atoi(optarg), NULL);\n\t\t\tbreak;\n\t\tcase 's': /* lax SSL, allow selfsigned, skip checking hostname */\n\t\t\tuse_ssl \u003d LCCSCF_USE_SSL |\n\t\t\t\t LCCSCF_ALLOW_SELFSIGNED |\n\t\t\t\t LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;\n\t\t\tbreak;\n\t\tcase 'S': /* Strict SSL, no selfsigned, check server hostname */\n\t\t\tuse_ssl \u003d LCCSCF_USE_SSL;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tport \u003d atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\tflag_echo \u003d 1;\n\t\t\tbreak;\n\t\tcase 'j':\n\t\t\tjustmirror \u003d 1;\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tlonglived \u003d 1;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tietf_version \u003d atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'u':\n\t\t\tdeny_deflate \u003d 1;\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tdo_multi \u003d 1;\n\t\t\tbreak;\n\t\tcase 'o':\n\t\t\ttest_post \u003d 1;\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\tonce \u003d 1;\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tflag_no_mirror_traffic \u003d 1;\n\t\t\tlwsl_notice(\u0022Disabled sending mirror data (for pingpong testing)\u005cn\u0022);\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tlws_strncpy(cert_path, optarg, sizeof(cert_path));\n\t\t\tbreak;\n\t\tcase 'K':\n\t\t\tlws_strncpy(key_path, optarg, sizeof(key_path));\n\t\t\tbreak;\n\t\tcase 'A':\n\t\t\tlws_strncpy(ca_path, optarg, sizeof(ca_path));\n\t\t\tbreak;\n\n#if defined(LWS_WITH_TLS) \u0026\u0026 defined(LWS_HAVE_SSL_CTX_set1_param)\n\t\tcase 'R':\n\t\t\tlws_strncpy(crl_path, optarg, sizeof(crl_path));\n\t\t\tbreak;\n#endif\n\t\tcase 'h':\n\t\t\tgoto usage;\n\t\t}\n\t}\n\n\tif (optind \u003e\u003d argc)\n\t\tgoto usage;\n\n\tsignal(SIGINT, sighandler);\n\n\tmemset(\u0026i, 0, sizeof(i));\n\n\ti.port \u003d port;\n\tif (lws_parse_uri(argv[optind], \u0026prot, \u0026i.address, \u0026i.port, \u0026p))\n\t\tgoto usage;\n\n\t/* add back the leading / on path */\n\tif (p[0] !\u003d '/') {\n\t\tpath[0] \u003d '/';\n\t\tlws_strncpy(path + 1, p, sizeof(path) - 1);\n\t\ti.path \u003d path;\n\t} else\n\t\ti.path \u003d p;\n\n\tif (!strcmp(prot, \u0022http\u0022) || !strcmp(prot, \u0022ws\u0022))\n\t\tuse_ssl \u003d 0;\n\tif (!strcmp(prot, \u0022https\u0022) || !strcmp(prot, \u0022wss\u0022))\n\t\tif (!use_ssl)\n\t\t\tuse_ssl \u003d LCCSCF_USE_SSL;\n\n\tlwsl_debug(\u0022'%s' %p '%s' %p\u005cn\u0022, i.address, i.address, i.path, i.path);\n\n\t/*\n\t * create the websockets context. This tracks open connections and\n\t * knows how to route any traffic and which protocol version to use,\n\t * and if each connection is client or server side.\n\t *\n\t * For this client-only demo, we tell it to not listen on any port.\n\t */\n\n\tinfo.port \u003d CONTEXT_PORT_NO_LISTEN;\n\tinfo.protocols \u003d protocols;\n\tinfo.gid \u003d (gid_t)-1;\n\tinfo.uid \u003d (uid_t)-1;\n#if defined(LWS_ROLE_WS) \u0026\u0026 !defined(LWS_WITHOUT_EXTENSIONS)\n\tinfo.extensions \u003d exts;\n#endif\n\n\t/*\n\t * since we know this lws context is only ever going to be used with\n\t * a few client wsis / fds / sockets at a time, let lws know it doesn't\n\t * have to use the default allocations for fd tables up to ulimit -n.\n\t * It will just allocate for 2 internal and 4 that we might use.\n\t */\n\tinfo.fd_limit_per_thread \u003d 2 + 4;\n\n#if defined(LWS_WITH_TLS)\n\tinfo.options |\u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n#endif\n\n\tinfo.options |\u003d LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;\n#if defined(LWS_WITH_TLS)\n\tif (use_ssl) {\n\t\t/*\n\t\t * If the server wants us to present a valid SSL client certificate\n\t\t * then we can set it up here.\n\t\t */\n\n\t\tif (cert_path[0])\n\t\t\tinfo.client_ssl_cert_filepath \u003d cert_path;\n\t\tif (key_path[0])\n\t\t\tinfo.client_ssl_private_key_filepath \u003d key_path;\n\n\t\t/*\n\t\t * A CA cert and CRL can be used to validate the cert send by the server\n\t\t */\n\t\tif (ca_path[0])\n\t\t\tinfo.client_ssl_ca_filepath \u003d ca_path;\n\n#if defined(LWS_WITH_TLS) \u0026\u0026 defined(LWS_HAVE_SSL_CTX_set1_param)\n\t\telse if (crl_path[0])\n\t\t\tlwsl_notice(\u0022WARNING, providing a CRL requires a CA cert!\u005cn\u0022);\n#endif\n\t}\n\n\tif (use_ssl \u0026 LCCSCF_USE_SSL) {\n\t\tlwsl_notice(\u0022 Using SSL\u005cn\u0022);\n#if defined(LWS_WITH_MBEDTLS)\n\t\tlwsl_notice(\u0022 (NOTE: mbedtls needs to be given the remote\u005cn\u0022);\n\t\tlwsl_notice(\u0022 CA cert to trust (with -A) to validate it)\u005cn\u0022);\n#endif\n\t}\n\telse\n\t\tlwsl_notice(\u0022 SSL disabled\u005cn\u0022);\n\tif (use_ssl \u0026 LCCSCF_ALLOW_SELFSIGNED)\n\t\tlwsl_notice(\u0022 Selfsigned certs allowed\u005cn\u0022);\n\telse\n\t\tlwsl_notice(\u0022 Cert must validate correctly (use -s to allow selfsigned)\u005cn\u0022);\n\tif (use_ssl \u0026 LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)\n\t\tlwsl_notice(\u0022 Skipping peer cert hostname check\u005cn\u0022);\n\telse\n\t\tlwsl_notice(\u0022 Requiring peer cert hostname matches\u005cn\u0022);\n#endif\n\tcontext \u003d lws_create_context(\u0026info);\n\tif (context \u003d\u003d NULL) {\n\t\tfprintf(stderr, \u0022Creating libwebsocket context failed\u005cn\u0022);\n\t\treturn 1;\n\t}\n\n\ti.context \u003d context;\n\ti.ssl_connection \u003d use_ssl;\n\ti.host \u003d i.address;\n\ti.origin \u003d i.address;\n\ti.ietf_version_or_minus_one \u003d ietf_version;\n\n\tif (!strcmp(prot, \u0022http\u0022) || !strcmp(prot, \u0022https\u0022)) {\n\t\tlwsl_notice(\u0022using %s mode (non-ws)\u005cn\u0022, prot);\n\t\tif (test_post) {\n\t\t\ti.method \u003d \u0022POST\u0022;\n\t\t\tlwsl_notice(\u0022POST mode\u005cn\u0022);\n\t\t}\n\t\telse\n\t\t\ti.method \u003d \u0022GET\u0022;\n\t\tdo_ws \u003d 0;\n\t} else\n\t\tif (!strcmp(prot, \u0022raw\u0022)) {\n\t\t\ti.method \u003d \u0022RAW\u0022;\n\t\t\ti.protocol \u003d \u0022lws-test-raw-client\u0022;\n\t\t\tlwsl_notice(\u0022using RAW mode connection\u005cn\u0022);\n\t\t\tdo_ws \u003d 0;\n\t\t} else\n\t\t\tlwsl_notice(\u0022using %s mode (ws)\u005cn\u0022, prot);\n\n\t/*\n\t * sit there servicing the websocket context to handle incoming\n\t * packets, and drawing random circles on the mirror protocol websocket\n\t *\n\t * nothing happens until the client websocket connection is\n\t * asynchronously established... calling lws_client_connect() only\n\t * instantiates the connection logically, lws_service() progresses it\n\t * asynchronously.\n\t */\n\n\tm \u003d 0;\n\twhile (!force_exit) {\n\n\t\tif (do_multi) {\n\t\t\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(wsi_multi); n++) {\n\t\t\t\tif (!wsi_multi[n] \u0026\u0026 ratelimit_connects(\u0026rl_multi[n], 2u)) {\n\t\t\t\t\tlwsl_notice(\u0022dumb %d: connecting\u005cn\u0022, n);\n\t\t\t\t\ti.protocol \u003d protocols[PROTOCOL_DUMB_INCREMENT].name;\n\t\t\t\t\ti.pwsi \u003d \u0026wsi_multi[n];\n\t\t\t\t\tlws_client_connect_via_info(\u0026i);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\n\t\t\tif (do_ws) {\n\t\t\t\tif (!flag_echo \u0026\u0026 !justmirror \u0026\u0026 !wsi_dumb \u0026\u0026 ratelimit_connects(\u0026rl_dumb, 2u)) {\n\t\t\t\t\tlwsl_notice(\u0022dumb: connecting\u005cn\u0022);\n\t\t\t\t\ti.protocol \u003d protocols[PROTOCOL_DUMB_INCREMENT].name;\n\t\t\t\t\ti.pwsi \u003d \u0026wsi_dumb;\n\t\t\t\t\tlws_client_connect_via_info(\u0026i);\n\t\t\t\t}\n\n\t\t\t\tif (!wsi_mirror \u0026\u0026 ratelimit_connects(\u0026rl_mirror, 2u)) {\n\t\t\t\t\tlwsl_notice(\u0022mirror: connecting\u005cn\u0022);\n\t\t\t\t\ti.protocol \u003d protocols[PROTOCOL_LWS_MIRROR].name;\n\t\t\t\t\ti.pwsi \u003d \u0026wsi_mirror;\n\t\t\t\t\twsi_mirror \u003d lws_client_connect_via_info(\u0026i);\n\t\t\t\t}\n\t\t\t} else\n\t\t\t\tif (!wsi_dumb \u0026\u0026 ratelimit_connects(\u0026rl_dumb, 2u)) {\n\t\t\t\t\tlwsl_notice(\u0022http: connecting\u005cn\u0022);\n\t\t\t\t\ti.pwsi \u003d \u0026wsi_dumb;\n\t\t\t\t\tlws_client_connect_via_info(\u0026i);\n\t\t\t\t}\n\t\t}\n\n\t\tlws_service(context, 500);\n\n\t\tif (do_multi) {\n\t\t\tm++;\n\t\t\tif (m \u003d\u003d 10) {\n\t\t\t\tm \u003d 0;\n\t\t\t\tlwsl_notice(\u0022doing lws_callback_on_writable_all_protocol\u005cn\u0022);\n\t\t\t\tlws_callback_on_writable_all_protocol(context,\n\t\t\t\t\t \u0026protocols[PROTOCOL_DUMB_INCREMENT]);\n\t\t\t}\n\t\t}\n\n\t\tif (flag_echo \u0026\u0026 lws_now_secs() !\u003d last) {\n\t\t\tlwsl_notice(\u0022rxb %d, rx_count %d\u005cn\u0022, rxb, rx_count);\n\t\t\tlast \u003d lws_now_secs();\n\t\t}\n\t}\n\n\tlwsl_err(\u0022Exiting\u005cn\u0022);\n\tlws_context_destroy(context);\n\n\treturn ret;\n\nusage:\n\tfprintf(stderr, \u0022Usage: libwebsockets-test-client \u0022\n\t\t\t\t\u0022\u003cserver address\u003e [--port\u003d\u003cp\u003e] \u0022\n\t\t\t\t\u0022[--ssl] [-k] [-v \u003cver\u003e] \u0022\n\t\t\t\t\u0022[-d \u003clog bitfield\u003e] [-l]\u005cn\u0022);\n\treturn 1;\n}\n","s":{"c":1713533101,"u": 1240}} ],"g": 10632,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}