Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1575707424, "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":"091d3ad98d256ae38e7796e990fa026e", "oid":{ "oid": "efbab4c602269dbb2a0015db9a00b9feae33ae44", "alias": [ "refs/heads/master"]},"blobname": "minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c", "blob": "/*\n * lws-minimal-http-client-multi\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 * This demonstrates the a minimal http client using lws, which makes\n * 8 downloads simultaneously from warmcat.com.\n *\n * Currently that takes the form of 8 individual simultaneous tcp and\n * tls connections, which happen concurrently. Notice that the ordering\n * of the returned payload may be intermingled for the various connections.\n *\n * By default the connections happen all together at the beginning and operate\n * concurrently, which is fast. However this is resource-intenstive, there are\n * 8 tcp connections, 8 tls tunnels on both the client and server. You can\n * instead opt to have the connections happen one after the other inside a\n * single tcp connection and tls tunnel, using HTTP/1.1 pipelining. To be\n * eligible to be pipelined on another existing connection to the same server,\n * the client connection must have the LCCSCF_PIPELINE flag on its\n * info.ssl_connection member (this is independent of whether the connection\n * is in ssl mode or not).\n *\n * HTTP/1.0: Pipelining only possible if Keep-Alive: yes sent by server\n * HTTP/1.1: always possible... serializes requests\n * HTTP/2: always possible... all requests sent as individual streams in parallel\n */\n\n#include \u003clibwebsockets.h\u003e\n#include \u003cstring.h\u003e\n#include \u003csignal.h\u003e\n#include \u003cassert.h\u003e\n#include \u003ctime.h\u003e\n\n#define COUNT 8\n\nstruct user {\n\tint index;\n};\n\nstatic int interrupted, completed, failed, numbered, stagger_idx;\nstatic struct lws *client_wsi[COUNT];\nstatic struct user user[COUNT];\nstatic lws_sorted_usec_list_t sul_stagger;\nstatic struct lws_client_connect_info i;\nstruct lws_context *context;\n\nstatic int\ncallback_http(struct lws *wsi, enum lws_callback_reasons reason,\n\t void *user, void *in, size_t len)\n{\n\tstruct user *u \u003d (struct user *)user;\n\n\tswitch (reason) {\n\n\tcase LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:\n\t\tlwsl_user(\u0022LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: resp %u\u005cn\u0022,\n\t\t\t\tlws_http_client_http_response(wsi));\n\t\tbreak;\n\n\t/* because we are protocols[0] ... */\n\tcase LWS_CALLBACK_CLIENT_CONNECTION_ERROR:\n\t\tlwsl_err(\u0022CLIENT_CONNECTION_ERROR: %s\u005cn\u0022,\n\t\t\t in ? (char *)in : \u0022(null)\u0022);\n\t\tclient_wsi[u-\u003eindex] \u003d NULL;\n\t\tfailed++;\n\t\tif (++completed \u003d\u003d COUNT) {\n\t\t\tlwsl_err(\u0022Done: failed: %d\u005cn\u0022, failed);\n\t\t\tinterrupted \u003d 1;\n\t\t}\n\t\tbreak;\n\n\t/* chunks of chunked content, with header removed */\n\tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:\n\t\tlwsl_user(\u0022RECEIVE_CLIENT_HTTP_READ: conn %d: read %d\u005cn\u0022,\n\t\t\tu-\u003eindex, (int)len);\n#if 0 /* enable to dump the html */\n\t\t{\n\t\t\tconst char *p \u003d in;\n\n\t\t\twhile (len--)\n\t\t\t\tif (*p \u003c 0x7f)\n\t\t\t\t\tputchar(*p++);\n\t\t\t\telse\n\t\t\t\t\tputchar('.');\n\t\t}\n#endif\n\t\treturn 0; /* don't passthru */\n\n\t/* uninterpreted http 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\tif (lws_http_client_read(wsi, \u0026px, \u0026lenx) \u003c 0)\n\t\t\t\treturn -1;\n\t\t}\n\t\treturn 0; /* don't passthru */\n\n\tcase LWS_CALLBACK_COMPLETED_CLIENT_HTTP:\n\t\tlwsl_user(\u0022LWS_CALLBACK_COMPLETED_CLIENT_HTTP %p: idx %d\u005cn\u0022,\n\t\t\t wsi, u-\u003eindex);\n\t\tclient_wsi[u-\u003eindex] \u003d NULL;\n\t\tif (++completed \u003d\u003d COUNT) {\n\t\t\tif (!failed)\n\t\t\t\tlwsl_user(\u0022Done: all OK\u005cn\u0022);\n\t\t\telse\n\t\t\t\tlwsl_err(\u0022Done: failed: %d\u005cn\u0022, failed);\n\t\t\tinterrupted \u003d 1;\n\t\t\t/* so we exit immediately */\n\t\t\tlws_cancel_service(lws_get_context(wsi));\n\t\t}\n\t\tbreak;\n\n\tcase LWS_CALLBACK_CLOSED_CLIENT_HTTP:\n\t\tif (u \u0026\u0026 client_wsi[u-\u003eindex]) {\n\t\t\t/*\n\t\t\t * If it completed normally, it will have been set to\n\t\t\t * NULL then already. So we are dealing with an\n\t\t\t * abnormal, failing, close\n\t\t\t */\n\t\t\tclient_wsi[u-\u003eindex] \u003d NULL;\n\t\t\tfailed++;\n\t\t\tif (++completed \u003d\u003d COUNT) {\n\t\t\t\tlwsl_err(\u0022Done: failed: %d\u005cn\u0022, failed);\n\t\t\t\tinterrupted \u003d 1;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn lws_callback_http_dummy(wsi, reason, user, in, len);\n}\n\nstatic const struct lws_protocols protocols[] \u003d {\n\t{ \u0022http\u0022, callback_http, 0, 0, },\n\t{ NULL, NULL, 0, 0 }\n};\n\nstatic void\nsigint_handler(int sig)\n{\n\tinterrupted \u003d 1;\n}\n\n#if defined(WIN32)\nint gettimeofday(struct timeval * tp, struct timezone * tzp)\n{\n // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's\n // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)\n // until 00:00:00 January 1, 1970 \n static const uint64_t EPOCH \u003d ((uint64_t) 116444736000000000ULL);\n\n SYSTEMTIME system_time;\n FILETIME file_time;\n uint64_t time;\n\n GetSystemTime( \u0026system_time );\n SystemTimeToFileTime( \u0026system_time, \u0026file_time );\n time \u003d ((uint64_t)file_time.dwLowDateTime ) ;\n time +\u003d ((uint64_t)file_time.dwHighDateTime) \u003c\u003c 32;\n\n tp-\u003etv_sec \u003d (long) ((time - EPOCH) / 10000000L);\n tp-\u003etv_usec \u003d (long) (system_time.wMilliseconds * 1000);\n return 0;\n}\n#endif\n\nunsigned long long us(void)\n{\n\tstruct timeval t;\n\n\tgettimeofday(\u0026t, NULL);\n\n\treturn (t.tv_sec * 1000000ull) + t.tv_usec;\n}\n\nstatic void\nlws_try_client_connection(struct lws_client_connect_info *i, int m)\n{\n\tchar path[128];\n\n\tif (numbered) {\n\t\tlws_snprintf(path, sizeof(path), \u0022/%d.png\u0022, m + 1);\n\t\ti-\u003epath \u003d path;\n\t} else\n\t\ti-\u003epath \u003d \u0022/\u0022;\n\n\ti-\u003epwsi \u003d \u0026client_wsi[m];\n\tuser[m].index \u003d m;\n\ti-\u003euserdata \u003d \u0026user[m];\n\n\tif (!lws_client_connect_via_info(i)) {\n\t\tfailed++;\n\t\tif (++completed \u003d\u003d COUNT) {\n\t\t\tlwsl_user(\u0022Done: failed: %d\u005cn\u0022, failed);\n\t\t\tinterrupted \u003d 1;\n\t\t}\n\t} else\n\t\tlwsl_user(\u0022started connection %p: idx %d (%s)\u005cn\u0022,\n\t\t\t client_wsi[m], m, i-\u003epath);\n}\n\nstatic void\nstagger_cb(lws_sorted_usec_list_t *sul)\n{\n\tlws_usec_t next;\n\n\t/*\n\t * open the connections at 100ms intervals, with the\n\t * last one being after 1s, testing both queuing, and\n\t * direct H2 stream addition stability\n\t */\n\tlws_try_client_connection(\u0026i, stagger_idx++);\n\n\tif (stagger_idx \u003d\u003d (int)LWS_ARRAY_SIZE(client_wsi))\n\t\treturn;\n\n\tnext \u003d 300 * LWS_US_PER_MS;\n\tif (stagger_idx \u003d\u003d (int)LWS_ARRAY_SIZE(client_wsi) - 1)\n\t\tnext +\u003d 700 * LWS_US_PER_MS;\n\n\tlws_sul_schedule(context, 0, \u0026sul_stagger, stagger_cb, next);\n}\n\nint main(int argc, const char **argv)\n{\n\tstruct lws_context_creation_info info;\n\tunsigned long long start;\n\tconst char *p;\n\tint n \u003d 0, m, staggered \u003d 0, logs \u003d\n\t\tLLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE\n\t\t/* for LLL_ verbosity above NOTICE to be built into lws,\n\t\t * lws must have been configured and built with\n\t\t * -DCMAKE_BUILD_TYPE\u003dDEBUG instead of \u003dRELEASE */\n\t\t/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */\n\t\t/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */\n\t\t/* | LLL_DEBUG */;\n\n\tsignal(SIGINT, sigint_handler);\n\n\tmemset(\u0026i, 0, sizeof i); /* otherwise uninitialized garbage */\n\n\tstaggered \u003d !!lws_cmdline_option(argc, argv, \u0022-s\u0022);\n\tif ((p \u003d lws_cmdline_option(argc, argv, \u0022-d\u0022)))\n\t\tlogs \u003d atoi(p);\n\n\tlws_set_log_level(logs, NULL);\n\tlwsl_user(\u0022LWS minimal http client [-s (staggered)] [-p (pipeline)]\u005cn\u0022);\n\tlwsl_user(\u0022 [--h1 (http/1 only)] [-l (localhost)] [-d \u003clogs\u003e]\u005cn\u0022);\n\tlwsl_user(\u0022 [-n (numbered)]\u005cn\u0022);\n\n\tmemset(\u0026info, 0, sizeof info); /* otherwise uninitialized garbage */\n\tinfo.options \u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;\n\tinfo.port \u003d CONTEXT_PORT_NO_LISTEN; /* we do not run any server */\n\tinfo.protocols \u003d protocols;\n\t/*\n\t * since we know this lws context is only ever going to be used with\n\t * COUNT 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 1 internal and COUNT + 1 (allowing for h2\n\t * network wsi) that we will use.\n\t */\n\tinfo.fd_limit_per_thread \u003d 1 + COUNT + 1;\n\n#if defined(LWS_WITH_MBEDTLS)\n\t/*\n\t * OpenSSL uses the system trust store. mbedTLS has to be told which\n\t * CA to trust explicitly.\n\t */\n\tinfo.client_ssl_ca_filepath \u003d \u0022./warmcat.com.cer\u0022;\n#endif\n\n#if defined(LWS_WITH_DETAILED_LATENCY)\n\tinfo.detailed_latency_cb \u003d lws_det_lat_plot_cb;\n\tinfo.detailed_latency_filepath \u003d \u0022/tmp/lws-latency-results\u0022;\n#endif\n\n\tcontext \u003d lws_create_context(\u0026info);\n\tif (!context) {\n\t\tlwsl_err(\u0022lws init failed\u005cn\u0022);\n\t\treturn 1;\n\t}\n\n\ti.context \u003d context;\n\ti.ssl_connection \u003d LCCSCF_USE_SSL;\n\n\t/* enables h1 or h2 connection sharing */\n\tif (lws_cmdline_option(argc, argv, \u0022-p\u0022))\n\t\ti.ssl_connection |\u003d LCCSCF_PIPELINE;\n\n\t/* force h1 even if h2 available */\n\tif (lws_cmdline_option(argc, argv, \u0022--h1\u0022))\n\t\ti.alpn \u003d \u0022http/1.1\u0022;\n\n\tif (lws_cmdline_option(argc, argv, \u0022-l\u0022)) {\n\t\ti.port \u003d 7681;\n\t\ti.address \u003d \u0022localhost\u0022;\n\t\ti.ssl_connection |\u003d LCCSCF_ALLOW_SELFSIGNED;\n\t} else {\n\t\ti.port \u003d 443;\n\t\ti.address \u003d \u0022warmcat.com\u0022;\n\t}\n\n\tif (lws_cmdline_option(argc, argv, \u0022-n\u0022))\n\t\tnumbered \u003d 1;\n\n\tif ((p \u003d lws_cmdline_option(argc, argv, \u0022--server\u0022)))\n\t\ti.address \u003d p;\n\n\tif ((p \u003d lws_cmdline_option(argc, argv, \u0022--port\u0022)))\n\t\ti.port \u003d atoi(p);\n\n\tif ((p \u003d lws_cmdline_option(argc, argv, \u0022--server\u0022)))\n\t\ti.address \u003d p;\n\n\ti.host \u003d i.address;\n\ti.origin \u003d i.address;\n\ti.method \u003d \u0022GET\u0022;\n\ti.protocol \u003d protocols[0].name;\n\n\tif (!staggered)\n\t\t/*\n\t\t * just pile on all the connections at once, testing the\n\t\t * pipeline queuing before the first is connected\n\t\t */\n\t\tfor (m \u003d 0; m \u003c (int)LWS_ARRAY_SIZE(client_wsi); m++)\n\t\t\tlws_try_client_connection(\u0026i, m);\n\telse\n\t\t/*\n\t\t * delay the connections slightly\n\t\t */\n\t\tlws_sul_schedule(context, 0, \u0026sul_stagger, stagger_cb,\n\t\t\t\t 100 * LWS_US_PER_MS);\n\n\tstart \u003d us();\n\tm \u003d 0;\n\twhile (n \u003e\u003d 0 \u0026\u0026 !interrupted)\n\t\tn \u003d lws_service(context, 0);\n\n\tlwsl_user(\u0022Duration: %lldms\u005cn\u0022, (us() - start) / 1000);\n\tlws_context_destroy(context);\n\n\tlwsl_user(\u0022Exiting with %d\u005cn\u0022, failed || completed !\u003d COUNT);\n\n\treturn failed || completed !\u003d COUNT;\n}\n","s":{"c":1575450399,"u": 356}} ],"g": 759,"chitpc": 0,"ehitpc": 0, "indexed":0 }