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