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":1571531769, "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":"9a144106db711f41cffeb9d6d349d75d", "oid":{ "oid": "b7a04a67d15efd0f17bf795b8d3648425b604581", "alias": [ "refs/heads/master"]},"blobname": "minimal-examples/api-tests/api-test-lws_sequencer/main.c", "blob": "/*\n * lws-api-test-lws_sequencer\n *\n * Written in 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 api test uses the lws_sequencer api to make five http client requests\n * to libwebsockets.org in sequence, from inside the event loop. The fourth\n * fourth http client request is directed to port 22 where it stalls\n * triggering the lws_sequencer timeout flow. The fifth is given a nonexistant\n * dns name and is expected to fail.\n */\n\n#include \u003clibwebsockets.h\u003e\n\n#include \u003csignal.h\u003e\n\nstatic int interrupted, test_good \u003d 0;\n\nenum {\n\tSEQ1,\n\tSEQ2,\n\tSEQ3_404,\n\tSEQ4_TIMEOUT,\t\t/* we expect to timeout */\n\tSEQ5_BAD_ADDRESS\t/* we expect the connection to fail */\n};\n\n/*\n * This is the user defined struct whose space is allocated along with the\n * sequencer when that is created.\n *\n * You'd put everything your sequencer needs to do its job in here.\n */\n\nstruct myseq {\n\tstruct lws_vhost\t*vhost;\n\tstruct lws\t\t*cwsi;\t/* client wsi for current step if any */\n\n\tint\t\t\tstate;\t/* which test we're on */\n\tint\t\t\thttp_resp;\n};\n\n/* sequencer messages specific to this sequencer */\n\nenum {\n\tSEQ_MSG_CLIENT_FAILED \u003d LWSSEQ_USER_BASE,\n\tSEQ_MSG_CLIENT_DONE,\n};\n\n/* this is the sequence of GETs we will do */\n\nstatic const char *url_paths[] \u003d {\n\t\u0022https://libwebsockets.org/index.html\u0022,\n\t\u0022https://libwebsockets.org/lws.css\u0022,\n\t\u0022https://libwebsockets.org/404.html\u0022,\n\t\u0022https://libwebsockets.org:22\u0022,\t\t/* this causes us to time out */\n\t\u0022https://doesntexist.invalid/\u0022\t\t/* fail early in connect */\n};\n\n\nstatic void\nsigint_handler(int sig)\n{\n\tinterrupted \u003d 1;\n}\n\n/*\n * This is the sequencer-aware http protocol handler. It monitors the client\n * http action and queues messages for the sequencer when something definitive\n * happens.\n */\n\nstatic int\ncallback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,\n\t void *in, size_t len)\n{\n\tstruct myseq *s \u003d (struct myseq *)user;\n\tint seq_msg \u003d SEQ_MSG_CLIENT_FAILED;\n\n\tswitch (reason) {\n\n\t/* because we are protocols[0] ... */\n\tcase LWS_CALLBACK_CLIENT_CONNECTION_ERROR:\n\t\tlwsl_notice(\u0022CLIENT_CONNECTION_ERROR: %s\u005cn\u0022,\n\t\t\t in ? (char *)in : \u0022(null)\u0022);\n\t\tgoto notify;\n\n\tcase LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:\n\t\tif (!s)\n\t\t\treturn 1;\n\t\ts-\u003ehttp_resp \u003d lws_http_client_http_response(wsi);\n\t\tlwsl_info(\u0022Connected with server response: %d\u005cn\u0022, s-\u003ehttp_resp);\n\t\tbreak;\n\n\t/* chunks of chunked content, with header removed */\n\tcase LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:\n\t\tlwsl_info(\u0022RECEIVE_CLIENT_HTTP_READ: read %d\u005cn\u0022, (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_notice(\u0022LWS_CALLBACK_COMPLETED_CLIENT_HTTP: wsi %p\u005cn\u0022,\n\t\t\t wsi);\n\t\tif (!s)\n\t\t\treturn 1;\n\t\t/*\n\t\t * We got a definitive transaction completion\n\t\t */\n\t\tseq_msg \u003d SEQ_MSG_CLIENT_DONE;\n\t\tgoto notify;\n\n\tcase LWS_CALLBACK_CLOSED_CLIENT_HTTP:\n\t\tlwsl_info(\u0022LWS_CALLBACK_CLOSED_CLIENT_HTTP\u005cn\u0022);\n\t\tif (!s)\n\t\t\treturn 1;\n\n\t\tlwsl_user(\u0022%s: wsi %p: seq failed at CLOSED_CLIENT_HTTP\u005cn\u0022,\n\t\t\t __func__, wsi);\n\t\tgoto notify;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn lws_callback_http_dummy(wsi, reason, user, in, len);\n\nnotify:\n\t/*\n\t * We only inform the sequencer of a definitive outcome for our step.\n\t *\n\t * So once we have informed it, we detach ourselves from the sequencer\n\t * and the sequencer from ourselves. Wsi may want to live on but after\n\t * we got our result and moved on to the next test or completed, the\n\t * sequencer doesn't want to hear from it again.\n\t */\n\tif (!s)\n\t\treturn 1;\n\n\tlws_set_wsi_user(wsi, NULL);\n\ts-\u003ecwsi \u003d NULL;\n\tlws_seq_queue_event(lws_seq_from_user(s), seq_msg,\n\t\t\t\t NULL, NULL);\n\n\treturn 0;\n}\n\nstatic const struct lws_protocols protocols[] \u003d {\n\t{ \u0022seq-test-http\u0022, callback_http, 0, 0, },\n\t{ NULL, NULL, 0, 0 }\n};\n\n\nstatic int\nsequencer_start_client(struct myseq *s)\n{\n\tstruct lws_client_connect_info i;\n\tconst char *prot, *path1;\n\tchar uri[128], path[128];\n\tint n;\n\n\tlws_strncpy(uri, url_paths[s-\u003estate], sizeof(uri));\n\n\tmemset(\u0026i, 0, sizeof i);\n\ti.context \u003d lws_seq_get_context(lws_seq_from_user(s));\n\n\tif (lws_parse_uri(uri, \u0026prot, \u0026i.address, \u0026i.port, \u0026path1)) {\n\t\tlwsl_err(\u0022%s: uri error %s\u005cn\u0022, __func__, uri);\n\t}\n\n\tif (!strcmp(prot, \u0022https\u0022))\n\t\ti.ssl_connection \u003d LCCSCF_USE_SSL;\n\n\tpath[0] \u003d '/';\n\tn \u003d 1;\n\tif (path1[0] \u003d\u003d '/')\n\t\tn \u003d 0;\n\tlws_strncpy(\u0026path[n], path1, sizeof(path) - 1);\n\n\ti.path \u003d path;\n\ti.host \u003d i.address;\n\ti.origin \u003d i.address;\n\ti.method \u003d \u0022GET\u0022;\n\ti.vhost \u003d s-\u003evhost;\n\ti.userdata \u003d s;\n\n\ti.protocol \u003d protocols[0].name;\n\ti.local_protocol_name \u003d protocols[0].name;\n\ti.pwsi \u003d \u0026s-\u003ecwsi;\n\n\tif (!lws_client_connect_via_info(\u0026i)) {\n\t\tlwsl_notice(\u0022%s: connecting to %s://%s:%d%s failed\u005cn\u0022,\n\t\t\t __func__, prot, i.address, i.port, path);\n\n\t\t/* we couldn't even get started with the client connection */\n\n\t\tlws_seq_queue_event(lws_seq_from_user(s),\n\t\t\t\t SEQ_MSG_CLIENT_FAILED, NULL, NULL);\n\n\t\treturn 1;\n\t}\n\n\tlws_seq_timeout_us(lws_seq_from_user(s), 3 * LWS_US_PER_SEC);\n\n\tlwsl_notice(\u0022%s: wsi %p: connecting to %s://%s:%d%s\u005cn\u0022, __func__,\n\t\t s-\u003ecwsi, prot, i.address, i.port, path);\n\n\treturn 0;\n}\n\n/*\n * The sequencer callback handles queued sequencer messages in the order they\n * were queued. The messages are presented from the event loop thread context\n * even if they were queued from a different thread.\n */\n\nstatic lws_seq_cb_return_t\nsequencer_cb(struct lws_sequencer *seq, void *user, int event,\n\t void *data, void *aux)\n{\n\tstruct myseq *s \u003d (struct myseq *)user;\n\n\tswitch ((int)event) {\n\tcase LWSSEQ_CREATED: /* our sequencer just got started */\n\t\ts-\u003estate \u003d SEQ1; /* first thing we'll do is the first url */\n\t\tgoto step;\n\n\tcase LWSSEQ_DESTROYED:\n\t\t/*\n\t\t * This sequencer is about to be destroyed. If we have any\n\t\t * other assets in play, detach them from us.\n\t\t */\n\t\tif (s-\u003ecwsi)\n\t\t\tlws_set_wsi_user(s-\u003ecwsi, NULL);\n\n\t\tinterrupted \u003d 1;\n\t\tbreak;\n\n\tcase LWSSEQ_TIMED_OUT: /* current step timed out */\n\t\tif (s-\u003estate \u003d\u003d SEQ4_TIMEOUT) {\n\t\t\tlwsl_user(\u0022%s: test %d got expected timeout\u005cn\u0022,\n\t\t\t\t __func__, s-\u003estate);\n\t\t\tgoto done;\n\t\t}\n\t\tlwsl_user(\u0022%s: seq timed out at step %d\u005cn\u0022, __func__, s-\u003estate);\n\t\treturn LWSSEQ_RET_DESTROY;\n\n\tcase SEQ_MSG_CLIENT_FAILED:\n\t\tif (s-\u003estate \u003d\u003d SEQ5_BAD_ADDRESS) {\n\t\t\t/*\n\t\t\t * in this specific case, we expect to fail\n\t\t\t */\n\t\t\tlwsl_user(\u0022%s: test %d failed as expected\u005cn\u0022,\n\t\t\t\t __func__, s-\u003estate);\n\t\t\tgoto done;\n\t\t}\n\n\t\tlwsl_user(\u0022%s: seq failed at step %d\u005cn\u0022, __func__, s-\u003estate);\n\n\t\treturn LWSSEQ_RET_DESTROY;\n\n\tcase SEQ_MSG_CLIENT_DONE:\n\t\tif (s-\u003estate \u003e\u003d SEQ4_TIMEOUT) {\n\t\t\t/*\n\t\t\t * In these specific cases, done would be a failure,\n\t\t\t * we expected to timeout or fail\n\t\t\t */\n\t\t\tlwsl_user(\u0022%s: seq failed at step %d\u005cn\u0022, __func__,\n\t\t\t\t s-\u003estate);\n\n\t\t\treturn LWSSEQ_RET_DESTROY;\n\t\t}\n\t\tlwsl_user(\u0022%s: seq done step %d (resp %d)\u005cn\u0022, __func__,\n\t\t\t s-\u003estate, s-\u003ehttp_resp);\n\ndone:\n\t\tlws_seq_timeout_us(lws_seq_from_user(s), LWSSEQTO_NONE);\n\t\ts-\u003estate++;\n\t\tif (s-\u003estate \u003d\u003d LWS_ARRAY_SIZE(url_paths)) {\n\t\t\t/* the sequence has completed */\n\t\t\tlwsl_user(\u0022%s: sequence completed OK\u005cn\u0022, __func__);\n\n\t\t\ttest_good \u003d 1;\n\n\t\t\treturn LWSSEQ_RET_DESTROY;\n\t\t}\n\nstep:\n\t\tsequencer_start_client(s);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn LWSSEQ_RET_CONTINUE;\n}\n\nint\nmain(int argc, const char **argv)\n{\n\tint n \u003d 1, logs \u003d LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;\n\tstruct lws_context_creation_info info;\n\tstruct lws_context *context;\n\tstruct lws_sequencer *seq;\n\tstruct lws_vhost *vh;\n\tlws_seq_info_t i;\n\tstruct myseq *s;\n\tconst char *p;\n\n\t/* the normal lws init */\n\n\tsignal(SIGINT, sigint_handler);\n\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 API selftest: lws_sequencer\u005cn\u0022);\n\n\tmemset(\u0026info, 0, sizeof info); /* otherwise uninitialized garbage */\n\tinfo.port \u003d CONTEXT_PORT_NO_LISTEN;\n\tinfo.options \u003d LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |\n\t\t LWS_SERVER_OPTION_EXPLICIT_VHOSTS;\n\tinfo.protocols \u003d protocols;\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./libwebsockets.org.cer\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\tvh \u003d lws_create_vhost(context, \u0026info);\n\tif (!vh) {\n\t\tlwsl_err(\u0022Failed to create first vhost\u005cn\u0022);\n\t\tgoto bail1;\n\t}\n\n\t/*\n\t * Create the sequencer... when the event loop starts, it will\n\t * receive the LWSSEQ_CREATED callback\n\t */\n\n\tmemset(\u0026i, 0, sizeof(i));\n\ti.context \u003d context;\n\ti.user_size \u003d sizeof(struct myseq);\n\ti.puser \u003d (void **)\u0026s;\n\ti.cb \u003d sequencer_cb;\n\ti.name \u003d \u0022seq\u0022;\n\n\tseq \u003d lws_seq_create(\u0026i);\n\tif (!seq) {\n\t\tlwsl_err(\u0022%s: unable to create sequencer\u005cn\u0022, __func__);\n\t\tgoto bail1;\n\t}\n\ts-\u003evhost \u003d vh;\n\n\t/* the usual lws event loop */\n\n\twhile (n \u003e\u003d 0 \u0026\u0026 !interrupted)\n\t\tn \u003d lws_service(context, 0);\n\nbail1:\n\tlwsl_user(\u0022Completed: %s\u005cn\u0022, !test_good ? \u0022FAIL\u0022 : \u0022PASS\u0022);\n\n\tlws_context_destroy(context);\n\n\treturn !test_good;\n}\n","s":{"c":1571531769,"u": 412}} ],"g": 1789,"chitpc": 0,"ehitpc": 0, "indexed":0 }