1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-api-test-lws_sequencer 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * This api test uses the lws_sequencer api to make five http client requests 10d4afb5ceSopenharmony_ci * to libwebsockets.org in sequence, from inside the event loop. The fourth 11d4afb5ceSopenharmony_ci * fourth http client request is directed to port 22 where it stalls 12d4afb5ceSopenharmony_ci * triggering the lws_sequencer timeout flow. The fifth is given a nonexistant 13d4afb5ceSopenharmony_ci * dns name and is expected to fail. 14d4afb5ceSopenharmony_ci */ 15d4afb5ceSopenharmony_ci 16d4afb5ceSopenharmony_ci#include <libwebsockets.h> 17d4afb5ceSopenharmony_ci 18d4afb5ceSopenharmony_ci#include <signal.h> 19d4afb5ceSopenharmony_ci 20d4afb5ceSopenharmony_cistatic int interrupted, test_good = 0; 21d4afb5ceSopenharmony_ci 22d4afb5ceSopenharmony_cienum { 23d4afb5ceSopenharmony_ci SEQ1, 24d4afb5ceSopenharmony_ci SEQ2, 25d4afb5ceSopenharmony_ci SEQ3_404, 26d4afb5ceSopenharmony_ci SEQ4_TIMEOUT, /* we expect to timeout */ 27d4afb5ceSopenharmony_ci SEQ5_BAD_ADDRESS /* we expect the connection to fail */ 28d4afb5ceSopenharmony_ci}; 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_ci/* 31d4afb5ceSopenharmony_ci * This is the user defined struct whose space is allocated along with the 32d4afb5ceSopenharmony_ci * sequencer when that is created. 33d4afb5ceSopenharmony_ci * 34d4afb5ceSopenharmony_ci * You'd put everything your sequencer needs to do its job in here. 35d4afb5ceSopenharmony_ci */ 36d4afb5ceSopenharmony_ci 37d4afb5ceSopenharmony_cistruct myseq { 38d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 39d4afb5ceSopenharmony_ci struct lws *cwsi; /* client wsi for current step if any */ 40d4afb5ceSopenharmony_ci 41d4afb5ceSopenharmony_ci int state; /* which test we're on */ 42d4afb5ceSopenharmony_ci int http_resp; 43d4afb5ceSopenharmony_ci}; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci/* sequencer messages specific to this sequencer */ 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_cienum { 48d4afb5ceSopenharmony_ci SEQ_MSG_CLIENT_FAILED = LWSSEQ_USER_BASE, 49d4afb5ceSopenharmony_ci SEQ_MSG_CLIENT_DONE, 50d4afb5ceSopenharmony_ci}; 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci/* this is the sequence of GETs we will do */ 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_cistatic const char *url_paths[] = { 55d4afb5ceSopenharmony_ci "https://libwebsockets.org/index.html", 56d4afb5ceSopenharmony_ci "https://libwebsockets.org/lws.css", 57d4afb5ceSopenharmony_ci "https://libwebsockets.org/404.html", 58d4afb5ceSopenharmony_ci "https://libwebsockets.org:22", /* this causes us to time out */ 59d4afb5ceSopenharmony_ci "https://doesntexist.invalid/" /* fail early in connect */ 60d4afb5ceSopenharmony_ci}; 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_cistatic void 64d4afb5ceSopenharmony_cisigint_handler(int sig) 65d4afb5ceSopenharmony_ci{ 66d4afb5ceSopenharmony_ci interrupted = 1; 67d4afb5ceSopenharmony_ci} 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci/* 70d4afb5ceSopenharmony_ci * This is the sequencer-aware http protocol handler. It monitors the client 71d4afb5ceSopenharmony_ci * http action and queues messages for the sequencer when something definitive 72d4afb5ceSopenharmony_ci * happens. 73d4afb5ceSopenharmony_ci */ 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_cistatic int 76d4afb5ceSopenharmony_cicallback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, 77d4afb5ceSopenharmony_ci void *in, size_t len) 78d4afb5ceSopenharmony_ci{ 79d4afb5ceSopenharmony_ci struct myseq *s = (struct myseq *)user; 80d4afb5ceSopenharmony_ci int seq_msg = SEQ_MSG_CLIENT_FAILED; 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ci switch (reason) { 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci /* because we are protocols[0] ... */ 85d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 86d4afb5ceSopenharmony_ci lwsl_notice("CLIENT_CONNECTION_ERROR: %s\n", 87d4afb5ceSopenharmony_ci in ? (char *)in : "(null)"); 88d4afb5ceSopenharmony_ci goto notify; 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: 91d4afb5ceSopenharmony_ci if (!s) 92d4afb5ceSopenharmony_ci return 1; 93d4afb5ceSopenharmony_ci s->http_resp = (int)lws_http_client_http_response(wsi); 94d4afb5ceSopenharmony_ci lwsl_info("Connected with server response: %d\n", s->http_resp); 95d4afb5ceSopenharmony_ci break; 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci /* chunks of chunked content, with header removed */ 98d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: 99d4afb5ceSopenharmony_ci lwsl_info("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len); 100d4afb5ceSopenharmony_ci#if 0 /* enable to dump the html */ 101d4afb5ceSopenharmony_ci { 102d4afb5ceSopenharmony_ci const char *p = in; 103d4afb5ceSopenharmony_ci 104d4afb5ceSopenharmony_ci while (len--) 105d4afb5ceSopenharmony_ci if (*p < 0x7f) 106d4afb5ceSopenharmony_ci putchar(*p++); 107d4afb5ceSopenharmony_ci else 108d4afb5ceSopenharmony_ci putchar('.'); 109d4afb5ceSopenharmony_ci } 110d4afb5ceSopenharmony_ci#endif 111d4afb5ceSopenharmony_ci return 0; /* don't passthru */ 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci /* uninterpreted http content */ 114d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: 115d4afb5ceSopenharmony_ci { 116d4afb5ceSopenharmony_ci char buffer[1024 + LWS_PRE]; 117d4afb5ceSopenharmony_ci char *px = buffer + LWS_PRE; 118d4afb5ceSopenharmony_ci int lenx = sizeof(buffer) - LWS_PRE; 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci if (lws_http_client_read(wsi, &px, &lenx) < 0) 121d4afb5ceSopenharmony_ci return -1; 122d4afb5ceSopenharmony_ci } 123d4afb5ceSopenharmony_ci return 0; /* don't passthru */ 124d4afb5ceSopenharmony_ci 125d4afb5ceSopenharmony_ci case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: 126d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_COMPLETED_CLIENT_HTTP: wsi %p\n", 127d4afb5ceSopenharmony_ci wsi); 128d4afb5ceSopenharmony_ci if (!s) 129d4afb5ceSopenharmony_ci return 1; 130d4afb5ceSopenharmony_ci /* 131d4afb5ceSopenharmony_ci * We got a definitive transaction completion 132d4afb5ceSopenharmony_ci */ 133d4afb5ceSopenharmony_ci seq_msg = SEQ_MSG_CLIENT_DONE; 134d4afb5ceSopenharmony_ci goto notify; 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_CLIENT_HTTP: 137d4afb5ceSopenharmony_ci lwsl_info("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); 138d4afb5ceSopenharmony_ci if (!s) 139d4afb5ceSopenharmony_ci return 1; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci lwsl_user("%s: wsi %p: seq failed at CLOSED_CLIENT_HTTP\n", 142d4afb5ceSopenharmony_ci __func__, wsi); 143d4afb5ceSopenharmony_ci goto notify; 144d4afb5ceSopenharmony_ci 145d4afb5ceSopenharmony_ci default: 146d4afb5ceSopenharmony_ci break; 147d4afb5ceSopenharmony_ci } 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_cinotify: 152d4afb5ceSopenharmony_ci /* 153d4afb5ceSopenharmony_ci * We only inform the sequencer of a definitive outcome for our step. 154d4afb5ceSopenharmony_ci * 155d4afb5ceSopenharmony_ci * So once we have informed it, we detach ourselves from the sequencer 156d4afb5ceSopenharmony_ci * and the sequencer from ourselves. Wsi may want to live on but after 157d4afb5ceSopenharmony_ci * we got our result and moved on to the next test or completed, the 158d4afb5ceSopenharmony_ci * sequencer doesn't want to hear from it again. 159d4afb5ceSopenharmony_ci */ 160d4afb5ceSopenharmony_ci if (!s) 161d4afb5ceSopenharmony_ci return 1; 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci lws_set_wsi_user(wsi, NULL); 164d4afb5ceSopenharmony_ci s->cwsi = NULL; 165d4afb5ceSopenharmony_ci lws_seq_queue_event(lws_seq_from_user(s), seq_msg, 166d4afb5ceSopenharmony_ci NULL, NULL); 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci return 0; 169d4afb5ceSopenharmony_ci} 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_cistatic const struct lws_protocols protocols[] = { 172d4afb5ceSopenharmony_ci { "seq-test-http", callback_http, 0, 0, 0, NULL, 0 }, 173d4afb5ceSopenharmony_ci LWS_PROTOCOL_LIST_TERM 174d4afb5ceSopenharmony_ci}; 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_cistatic int 178d4afb5ceSopenharmony_cisequencer_start_client(struct myseq *s) 179d4afb5ceSopenharmony_ci{ 180d4afb5ceSopenharmony_ci struct lws_client_connect_info i; 181d4afb5ceSopenharmony_ci const char *prot, *path1; 182d4afb5ceSopenharmony_ci char uri[128], path[128]; 183d4afb5ceSopenharmony_ci int n; 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci lws_strncpy(uri, url_paths[s->state], sizeof(uri)); 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci memset(&i, 0, sizeof i); 188d4afb5ceSopenharmony_ci i.context = lws_seq_get_context(lws_seq_from_user(s)); 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (lws_parse_uri(uri, &prot, &i.address, &i.port, &path1)) { 191d4afb5ceSopenharmony_ci lwsl_err("%s: uri error %s\n", __func__, uri); 192d4afb5ceSopenharmony_ci } 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci if (!strcmp(prot, "https")) 195d4afb5ceSopenharmony_ci i.ssl_connection = LCCSCF_USE_SSL; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci path[0] = '/'; 198d4afb5ceSopenharmony_ci n = 1; 199d4afb5ceSopenharmony_ci if (path1[0] == '/') 200d4afb5ceSopenharmony_ci n = 0; 201d4afb5ceSopenharmony_ci lws_strncpy(&path[n], path1, sizeof(path) - 1); 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci i.path = path; 204d4afb5ceSopenharmony_ci i.host = i.address; 205d4afb5ceSopenharmony_ci i.origin = i.address; 206d4afb5ceSopenharmony_ci i.method = "GET"; 207d4afb5ceSopenharmony_ci i.vhost = s->vhost; 208d4afb5ceSopenharmony_ci i.userdata = s; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci i.protocol = protocols[0].name; 211d4afb5ceSopenharmony_ci i.local_protocol_name = protocols[0].name; 212d4afb5ceSopenharmony_ci i.pwsi = &s->cwsi; 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci if (!lws_client_connect_via_info(&i)) { 215d4afb5ceSopenharmony_ci lwsl_notice("%s: connecting to %s://%s:%d%s failed\n", 216d4afb5ceSopenharmony_ci __func__, prot, i.address, i.port, path); 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci /* we couldn't even get started with the client connection */ 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci lws_seq_queue_event(lws_seq_from_user(s), 221d4afb5ceSopenharmony_ci (lws_seq_events_t)SEQ_MSG_CLIENT_FAILED, NULL, NULL); 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci return 1; 224d4afb5ceSopenharmony_ci } 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci lws_seq_timeout_us(lws_seq_from_user(s), 3 * LWS_US_PER_SEC); 227d4afb5ceSopenharmony_ci 228d4afb5ceSopenharmony_ci lwsl_notice("%s: wsi %p: connecting to %s://%s:%d%s\n", __func__, 229d4afb5ceSopenharmony_ci s->cwsi, prot, i.address, i.port, path); 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci return 0; 232d4afb5ceSopenharmony_ci} 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci/* 235d4afb5ceSopenharmony_ci * The sequencer callback handles queued sequencer messages in the order they 236d4afb5ceSopenharmony_ci * were queued. The messages are presented from the event loop thread context 237d4afb5ceSopenharmony_ci * even if they were queued from a different thread. 238d4afb5ceSopenharmony_ci */ 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_cistatic lws_seq_cb_return_t 241d4afb5ceSopenharmony_cisequencer_cb(struct lws_sequencer *seq, void *user, int event, 242d4afb5ceSopenharmony_ci void *data, void *aux) 243d4afb5ceSopenharmony_ci{ 244d4afb5ceSopenharmony_ci struct myseq *s = (struct myseq *)user; 245d4afb5ceSopenharmony_ci 246d4afb5ceSopenharmony_ci switch ((int)event) { 247d4afb5ceSopenharmony_ci case LWSSEQ_CREATED: /* our sequencer just got started */ 248d4afb5ceSopenharmony_ci s->state = SEQ1; /* first thing we'll do is the first url */ 249d4afb5ceSopenharmony_ci goto step; 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci case LWSSEQ_DESTROYED: 252d4afb5ceSopenharmony_ci /* 253d4afb5ceSopenharmony_ci * This sequencer is about to be destroyed. If we have any 254d4afb5ceSopenharmony_ci * other assets in play, detach them from us. 255d4afb5ceSopenharmony_ci */ 256d4afb5ceSopenharmony_ci if (s->cwsi) 257d4afb5ceSopenharmony_ci lws_set_wsi_user(s->cwsi, NULL); 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci interrupted = 1; 260d4afb5ceSopenharmony_ci break; 261d4afb5ceSopenharmony_ci 262d4afb5ceSopenharmony_ci case LWSSEQ_TIMED_OUT: /* current step timed out */ 263d4afb5ceSopenharmony_ci if (s->state == SEQ4_TIMEOUT) { 264d4afb5ceSopenharmony_ci lwsl_user("%s: test %d got expected timeout\n", 265d4afb5ceSopenharmony_ci __func__, s->state); 266d4afb5ceSopenharmony_ci goto done; 267d4afb5ceSopenharmony_ci } 268d4afb5ceSopenharmony_ci lwsl_user("%s: seq timed out at step %d\n", __func__, s->state); 269d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci case SEQ_MSG_CLIENT_FAILED: 272d4afb5ceSopenharmony_ci if (s->state == SEQ5_BAD_ADDRESS) { 273d4afb5ceSopenharmony_ci /* 274d4afb5ceSopenharmony_ci * in this specific case, we expect to fail 275d4afb5ceSopenharmony_ci */ 276d4afb5ceSopenharmony_ci lwsl_user("%s: test %d failed as expected\n", 277d4afb5ceSopenharmony_ci __func__, s->state); 278d4afb5ceSopenharmony_ci goto done; 279d4afb5ceSopenharmony_ci } 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci lwsl_user("%s: seq failed at step %d\n", __func__, s->state); 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci case SEQ_MSG_CLIENT_DONE: 286d4afb5ceSopenharmony_ci if (s->state >= SEQ4_TIMEOUT) { 287d4afb5ceSopenharmony_ci /* 288d4afb5ceSopenharmony_ci * In these specific cases, done would be a failure, 289d4afb5ceSopenharmony_ci * we expected to timeout or fail 290d4afb5ceSopenharmony_ci */ 291d4afb5ceSopenharmony_ci lwsl_user("%s: seq failed at step %d\n", __func__, 292d4afb5ceSopenharmony_ci s->state); 293d4afb5ceSopenharmony_ci 294d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 295d4afb5ceSopenharmony_ci } 296d4afb5ceSopenharmony_ci lwsl_user("%s: seq done step %d (resp %d)\n", __func__, 297d4afb5ceSopenharmony_ci s->state, s->http_resp); 298d4afb5ceSopenharmony_ci 299d4afb5ceSopenharmony_cidone: 300d4afb5ceSopenharmony_ci lws_seq_timeout_us(lws_seq_from_user(s), LWSSEQTO_NONE); 301d4afb5ceSopenharmony_ci s->state++; 302d4afb5ceSopenharmony_ci if (s->state == LWS_ARRAY_SIZE(url_paths)) { 303d4afb5ceSopenharmony_ci /* the sequence has completed */ 304d4afb5ceSopenharmony_ci lwsl_user("%s: sequence completed OK\n", __func__); 305d4afb5ceSopenharmony_ci 306d4afb5ceSopenharmony_ci test_good = 1; 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_ci return LWSSEQ_RET_DESTROY; 309d4afb5ceSopenharmony_ci } 310d4afb5ceSopenharmony_ci 311d4afb5ceSopenharmony_cistep: 312d4afb5ceSopenharmony_ci sequencer_start_client(s); 313d4afb5ceSopenharmony_ci break; 314d4afb5ceSopenharmony_ci default: 315d4afb5ceSopenharmony_ci break; 316d4afb5ceSopenharmony_ci } 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci return LWSSEQ_RET_CONTINUE; 319d4afb5ceSopenharmony_ci} 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_ciint 322d4afb5ceSopenharmony_cimain(int argc, const char **argv) 323d4afb5ceSopenharmony_ci{ 324d4afb5ceSopenharmony_ci int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 325d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 326d4afb5ceSopenharmony_ci struct lws_context *context; 327d4afb5ceSopenharmony_ci struct lws_sequencer *seq; 328d4afb5ceSopenharmony_ci struct lws_vhost *vh; 329d4afb5ceSopenharmony_ci lws_seq_info_t i; 330d4afb5ceSopenharmony_ci struct myseq *s; 331d4afb5ceSopenharmony_ci const char *p; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci /* the normal lws init */ 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 336d4afb5ceSopenharmony_ci 337d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 338d4afb5ceSopenharmony_ci logs = atoi(p); 339d4afb5ceSopenharmony_ci 340d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 341d4afb5ceSopenharmony_ci lwsl_user("LWS API selftest: lws_sequencer\n"); 342d4afb5ceSopenharmony_ci 343d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 344d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; 345d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | 346d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_EXPLICIT_VHOSTS; 347d4afb5ceSopenharmony_ci info.protocols = protocols; 348d4afb5ceSopenharmony_ci 349d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 350d4afb5ceSopenharmony_ci /* 351d4afb5ceSopenharmony_ci * OpenSSL uses the system trust store. mbedTLS has to be told which 352d4afb5ceSopenharmony_ci * CA to trust explicitly. 353d4afb5ceSopenharmony_ci */ 354d4afb5ceSopenharmony_ci info.client_ssl_ca_filepath = "./libwebsockets.org.cer"; 355d4afb5ceSopenharmony_ci#endif 356d4afb5ceSopenharmony_ci 357d4afb5ceSopenharmony_ci context = lws_create_context(&info); 358d4afb5ceSopenharmony_ci if (!context) { 359d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 360d4afb5ceSopenharmony_ci return 1; 361d4afb5ceSopenharmony_ci } 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci vh = lws_create_vhost(context, &info); 364d4afb5ceSopenharmony_ci if (!vh) { 365d4afb5ceSopenharmony_ci lwsl_err("Failed to create first vhost\n"); 366d4afb5ceSopenharmony_ci goto bail1; 367d4afb5ceSopenharmony_ci } 368d4afb5ceSopenharmony_ci 369d4afb5ceSopenharmony_ci /* 370d4afb5ceSopenharmony_ci * Create the sequencer... when the event loop starts, it will 371d4afb5ceSopenharmony_ci * receive the LWSSEQ_CREATED callback 372d4afb5ceSopenharmony_ci */ 373d4afb5ceSopenharmony_ci 374d4afb5ceSopenharmony_ci memset(&i, 0, sizeof(i)); 375d4afb5ceSopenharmony_ci i.context = context; 376d4afb5ceSopenharmony_ci i.user_size = sizeof(struct myseq); 377d4afb5ceSopenharmony_ci i.puser = (void **)&s; 378d4afb5ceSopenharmony_ci i.cb = sequencer_cb; 379d4afb5ceSopenharmony_ci i.name = "seq"; 380d4afb5ceSopenharmony_ci 381d4afb5ceSopenharmony_ci seq = lws_seq_create(&i); 382d4afb5ceSopenharmony_ci if (!seq) { 383d4afb5ceSopenharmony_ci lwsl_err("%s: unable to create sequencer\n", __func__); 384d4afb5ceSopenharmony_ci goto bail1; 385d4afb5ceSopenharmony_ci } 386d4afb5ceSopenharmony_ci s->vhost = vh; 387d4afb5ceSopenharmony_ci 388d4afb5ceSopenharmony_ci /* the usual lws event loop */ 389d4afb5ceSopenharmony_ci 390d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 391d4afb5ceSopenharmony_ci n = lws_service(context, 0); 392d4afb5ceSopenharmony_ci 393d4afb5ceSopenharmony_cibail1: 394d4afb5ceSopenharmony_ci lwsl_user("Completed: %s\n", !test_good ? "FAIL" : "PASS"); 395d4afb5ceSopenharmony_ci 396d4afb5ceSopenharmony_ci lws_context_destroy(context); 397d4afb5ceSopenharmony_ci 398d4afb5ceSopenharmony_ci return !test_good; 399d4afb5ceSopenharmony_ci} 400