1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-secure-streams-threads
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2021 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker  *
9*1c60b9acSAndroid Build Coastguard Worker  *
10*1c60b9acSAndroid Build Coastguard Worker  * This demonstrates how other threads can wake the lws event loop and ask it
11*1c60b9acSAndroid Build Coastguard Worker  * to do things via lws_cancel_service(), notifying Secure Streams using the
12*1c60b9acSAndroid Build Coastguard Worker  * LWSSSCS_EVENT_WAIT_CANCELLED state callback.
13*1c60b9acSAndroid Build Coastguard Worker  *
14*1c60b9acSAndroid Build Coastguard Worker  * Because of what we're testing, we don't actually connect the SS just create
15*1c60b9acSAndroid Build Coastguard Worker  * it and wait for the states we are testing for to come at 10Hz.
16*1c60b9acSAndroid Build Coastguard Worker  *
17*1c60b9acSAndroid Build Coastguard Worker  * We run the test for 3s and check we got an appropriate amount of wakes
18*1c60b9acSAndroid Build Coastguard Worker  * to call it a success.
19*1c60b9acSAndroid Build Coastguard Worker  *
20*1c60b9acSAndroid Build Coastguard Worker  * You can use the same pattern to have any amount of shared data protected by
21*1c60b9acSAndroid Build Coastguard Worker  * the mutex, containing whatever the other threads want the lws event loop
22*1c60b9acSAndroid Build Coastguard Worker  * thread to do for them.
23*1c60b9acSAndroid Build Coastguard Worker  */
24*1c60b9acSAndroid Build Coastguard Worker 
25*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
26*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
27*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
28*1c60b9acSAndroid Build Coastguard Worker 
29*1c60b9acSAndroid Build Coastguard Worker #include <pthread.h>
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker /*
32*1c60b9acSAndroid Build Coastguard Worker  * Define this to cause an ss api access from a foreign thread, it will
33*1c60b9acSAndroid Build Coastguard Worker  * assert.  This is for testing lws, don't do this in your code.
34*1c60b9acSAndroid Build Coastguard Worker  */
35*1c60b9acSAndroid Build Coastguard Worker // #define DO_ILLEGAL_API_THREAD
36*1c60b9acSAndroid Build Coastguard Worker 
37*1c60b9acSAndroid Build Coastguard Worker static int interrupted, bad = 1, finished;
38*1c60b9acSAndroid Build Coastguard Worker static lws_sorted_usec_list_t sul_timeout;
39*1c60b9acSAndroid Build Coastguard Worker static struct lws_context *context;
40*1c60b9acSAndroid Build Coastguard Worker static pthread_t pthread_spam;
41*1c60b9acSAndroid Build Coastguard Worker static int wakes, started_thread;
42*1c60b9acSAndroid Build Coastguard Worker 
43*1c60b9acSAndroid Build Coastguard Worker #if defined(DO_ILLEGAL_API_THREAD)
44*1c60b9acSAndroid Build Coastguard Worker static struct lws_ss_handle *ss; /* only needed for DO_ILLEGAL_API_THREAD */
45*1c60b9acSAndroid Build Coastguard Worker #endif
46*1c60b9acSAndroid Build Coastguard Worker 
47*1c60b9acSAndroid Build Coastguard Worker /* the data shared between the spam thread and the lws event loop */
48*1c60b9acSAndroid Build Coastguard Worker 
49*1c60b9acSAndroid Build Coastguard Worker static pthread_mutex_t lock_shared;
50*1c60b9acSAndroid Build Coastguard Worker static int shared_counter;
51*1c60b9acSAndroid Build Coastguard Worker 
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_SS_USE_SSPC)
54*1c60b9acSAndroid Build Coastguard Worker static const char * const default_ss_policy =
55*1c60b9acSAndroid Build Coastguard Worker 	"{"
56*1c60b9acSAndroid Build Coastguard Worker 		"\"schema-version\":1,"
57*1c60b9acSAndroid Build Coastguard Worker 		"\"s\": ["
58*1c60b9acSAndroid Build Coastguard Worker 			"{"
59*1c60b9acSAndroid Build Coastguard Worker 				"\"mintest\": {"
60*1c60b9acSAndroid Build Coastguard Worker 					"\"endpoint\": \"connectivitycheck.android.com\","
61*1c60b9acSAndroid Build Coastguard Worker 					"\"http_url\": \"generate_204\","
62*1c60b9acSAndroid Build Coastguard Worker 					"\"port\": 80,"
63*1c60b9acSAndroid Build Coastguard Worker 					"\"protocol\": \"h1\","
64*1c60b9acSAndroid Build Coastguard Worker 					"\"http_method\": \"GET\","
65*1c60b9acSAndroid Build Coastguard Worker 					"\"opportunistic\": true,"
66*1c60b9acSAndroid Build Coastguard Worker 					"\"http_expect\": 204,"
67*1c60b9acSAndroid Build Coastguard Worker 					"\"http_fail_redirect\": true"
68*1c60b9acSAndroid Build Coastguard Worker 				"}"
69*1c60b9acSAndroid Build Coastguard Worker 			"}"
70*1c60b9acSAndroid Build Coastguard Worker 		"]"
71*1c60b9acSAndroid Build Coastguard Worker 	"}"
72*1c60b9acSAndroid Build Coastguard Worker ;
73*1c60b9acSAndroid Build Coastguard Worker 
74*1c60b9acSAndroid Build Coastguard Worker #endif
75*1c60b9acSAndroid Build Coastguard Worker 
76*1c60b9acSAndroid Build Coastguard Worker typedef struct myss {
77*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ss_handle 		*ss;
78*1c60b9acSAndroid Build Coastguard Worker 	void				*opaque_data;
79*1c60b9acSAndroid Build Coastguard Worker 	/* ... application specific state ... */
80*1c60b9acSAndroid Build Coastguard Worker } myss_t;
81*1c60b9acSAndroid Build Coastguard Worker 
82*1c60b9acSAndroid Build Coastguard Worker static void *
thread_spam(void * d)83*1c60b9acSAndroid Build Coastguard Worker thread_spam(void *d)
84*1c60b9acSAndroid Build Coastguard Worker {
85*1c60b9acSAndroid Build Coastguard Worker 
86*1c60b9acSAndroid Build Coastguard Worker 	do {
87*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&lock_shared); /* --------- shared lock { */
88*1c60b9acSAndroid Build Coastguard Worker 
89*1c60b9acSAndroid Build Coastguard Worker 		/*
90*1c60b9acSAndroid Build Coastguard Worker 		 * prepare the shared data area to indicate whatever it is that
91*1c60b9acSAndroid Build Coastguard Worker 		 * we want doing on the main event loop.  In this case, we just
92*1c60b9acSAndroid Build Coastguard Worker 		 * bump a counter, but it can be any amount of data prepared,
93*1c60b9acSAndroid Build Coastguard Worker 		 * eg, whole info struct for a connection we want.
94*1c60b9acSAndroid Build Coastguard Worker 		 */
95*1c60b9acSAndroid Build Coastguard Worker 
96*1c60b9acSAndroid Build Coastguard Worker 		shared_counter++;
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: cancelling wait from spam thread: %d\n",
99*1c60b9acSAndroid Build Coastguard Worker 				__func__, shared_counter);
100*1c60b9acSAndroid Build Coastguard Worker 		lws_cancel_service(context);
101*1c60b9acSAndroid Build Coastguard Worker 
102*1c60b9acSAndroid Build Coastguard Worker #if defined(DO_ILLEGAL_API_THREAD)
103*1c60b9acSAndroid Build Coastguard Worker 		/*
104*1c60b9acSAndroid Build Coastguard Worker 		 * ILLEGAL...
105*1c60b9acSAndroid Build Coastguard Worker 		 * We cannot call any other lws api from a foreign thread
106*1c60b9acSAndroid Build Coastguard Worker 		 */
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker 		if (ss)
109*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_request_tx(ss);
110*1c60b9acSAndroid Build Coastguard Worker #endif
111*1c60b9acSAndroid Build Coastguard Worker 
112*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&lock_shared); /* } shared lock ------- */
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 		usleep(100000); /* wait 100ms and signal main thread again */
115*1c60b9acSAndroid Build Coastguard Worker 
116*1c60b9acSAndroid Build Coastguard Worker 	} while (!finished);
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker 	pthread_exit(NULL);
119*1c60b9acSAndroid Build Coastguard Worker 
120*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
121*1c60b9acSAndroid Build Coastguard Worker }
122*1c60b9acSAndroid Build Coastguard Worker 
123*1c60b9acSAndroid Build Coastguard Worker 
124*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
myss_state(void * userobj,void * h_src,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)125*1c60b9acSAndroid Build Coastguard Worker myss_state(void *userobj, void *h_src, lws_ss_constate_t state,
126*1c60b9acSAndroid Build Coastguard Worker 	   lws_ss_tx_ordinal_t ack)
127*1c60b9acSAndroid Build Coastguard Worker {
128*1c60b9acSAndroid Build Coastguard Worker 	// myss_t *m = (myss_t *)userobj;
129*1c60b9acSAndroid Build Coastguard Worker 	void *retval;
130*1c60b9acSAndroid Build Coastguard Worker 
131*1c60b9acSAndroid Build Coastguard Worker 	switch (state) {
132*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CREATING:
133*1c60b9acSAndroid Build Coastguard Worker 		if (pthread_create(&pthread_spam, NULL, thread_spam, NULL)) {
134*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("thread creation failed\n");
135*1c60b9acSAndroid Build Coastguard Worker 			return LWSSSSRET_DESTROY_ME;
136*1c60b9acSAndroid Build Coastguard Worker 		}
137*1c60b9acSAndroid Build Coastguard Worker 		started_thread = 1;
138*1c60b9acSAndroid Build Coastguard Worker 		break;
139*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DESTROYING:
140*1c60b9acSAndroid Build Coastguard Worker 		finished = 1;
141*1c60b9acSAndroid Build Coastguard Worker 		if (started_thread)
142*1c60b9acSAndroid Build Coastguard Worker 			pthread_join(pthread_spam, &retval);
143*1c60b9acSAndroid Build Coastguard Worker 		break;
144*1c60b9acSAndroid Build Coastguard Worker 
145*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_EVENT_WAIT_CANCELLED:
146*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_lock(&lock_shared); /* --------- shared lock { */
147*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: LWSSSCS_EVENT_WAIT_CANCELLED: %d, shared: %d\n",
148*1c60b9acSAndroid Build Coastguard Worker 			    __func__, ++wakes, shared_counter);
149*1c60b9acSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&lock_shared); /* } shared lock ------- */
150*1c60b9acSAndroid Build Coastguard Worker 		break;
151*1c60b9acSAndroid Build Coastguard Worker 
152*1c60b9acSAndroid Build Coastguard Worker 	default:
153*1c60b9acSAndroid Build Coastguard Worker 		break;
154*1c60b9acSAndroid Build Coastguard Worker 	}
155*1c60b9acSAndroid Build Coastguard Worker 
156*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
157*1c60b9acSAndroid Build Coastguard Worker }
158*1c60b9acSAndroid Build Coastguard Worker 
159*1c60b9acSAndroid Build Coastguard Worker static const lws_ss_info_t ssi_lws_threads = {
160*1c60b9acSAndroid Build Coastguard Worker 	.handle_offset		  = offsetof(myss_t, ss),
161*1c60b9acSAndroid Build Coastguard Worker 	.opaque_user_data_offset  = offsetof(myss_t, opaque_data),
162*1c60b9acSAndroid Build Coastguard Worker 	/* we don't actually do any rx or tx in this test */
163*1c60b9acSAndroid Build Coastguard Worker 	.state			  = myss_state,
164*1c60b9acSAndroid Build Coastguard Worker 	.user_alloc		  = sizeof(myss_t),
165*1c60b9acSAndroid Build Coastguard Worker 	.streamtype		  = "mintest",
166*1c60b9acSAndroid Build Coastguard Worker 	.manual_initial_tx_credit = 0,
167*1c60b9acSAndroid Build Coastguard Worker };
168*1c60b9acSAndroid Build Coastguard Worker 
169*1c60b9acSAndroid Build Coastguard Worker static void
sul_timeout_cb(lws_sorted_usec_list_t * sul)170*1c60b9acSAndroid Build Coastguard Worker sul_timeout_cb(lws_sorted_usec_list_t *sul)
171*1c60b9acSAndroid Build Coastguard Worker {
172*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: test finishing\n", __func__);
173*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
174*1c60b9acSAndroid Build Coastguard Worker }
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker static void
sigint_handler(int sig)178*1c60b9acSAndroid Build Coastguard Worker sigint_handler(int sig)
179*1c60b9acSAndroid Build Coastguard Worker {
180*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
181*1c60b9acSAndroid Build Coastguard Worker }
182*1c60b9acSAndroid Build Coastguard Worker 
183*1c60b9acSAndroid Build Coastguard Worker static int
system_notify_cb(lws_state_manager_t * mgr,lws_state_notify_link_t * link,int current,int target)184*1c60b9acSAndroid Build Coastguard Worker system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
185*1c60b9acSAndroid Build Coastguard Worker 		   int current, int target)
186*1c60b9acSAndroid Build Coastguard Worker {
187*1c60b9acSAndroid Build Coastguard Worker 	if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
188*1c60b9acSAndroid Build Coastguard Worker 		return 0;
189*1c60b9acSAndroid Build Coastguard Worker 
190*1c60b9acSAndroid Build Coastguard Worker 	/* the test SS.. not going to connect it, just see if the cancel_service
191*1c60b9acSAndroid Build Coastguard Worker 	 * messages are coming
192*1c60b9acSAndroid Build Coastguard Worker 	 */
193*1c60b9acSAndroid Build Coastguard Worker 
194*1c60b9acSAndroid Build Coastguard Worker 	if (lws_ss_create(context, 0, &ssi_lws_threads, NULL,
195*1c60b9acSAndroid Build Coastguard Worker #if defined(DO_ILLEGAL_API_THREAD)
196*1c60b9acSAndroid Build Coastguard Worker 			&ss,
197*1c60b9acSAndroid Build Coastguard Worker #else
198*1c60b9acSAndroid Build Coastguard Worker 			NULL,
199*1c60b9acSAndroid Build Coastguard Worker #endif
200*1c60b9acSAndroid Build Coastguard Worker 			NULL, NULL)) {
201*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to create secure stream\n",
202*1c60b9acSAndroid Build Coastguard Worker 			 __func__);
203*1c60b9acSAndroid Build Coastguard Worker 
204*1c60b9acSAndroid Build Coastguard Worker 		return -1;
205*1c60b9acSAndroid Build Coastguard Worker 	}
206*1c60b9acSAndroid Build Coastguard Worker 
207*1c60b9acSAndroid Build Coastguard Worker 	/* set up the test timeout */
208*1c60b9acSAndroid Build Coastguard Worker 
209*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_schedule(context, 0, &sul_timeout, sul_timeout_cb,
210*1c60b9acSAndroid Build Coastguard Worker 			 3 * LWS_US_PER_SEC);
211*1c60b9acSAndroid Build Coastguard Worker 
212*1c60b9acSAndroid Build Coastguard Worker 	return 0;
213*1c60b9acSAndroid Build Coastguard Worker }
214*1c60b9acSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)215*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
216*1c60b9acSAndroid Build Coastguard Worker {
217*1c60b9acSAndroid Build Coastguard Worker 	lws_state_notify_link_t notifier = { { NULL, NULL, NULL},
218*1c60b9acSAndroid Build Coastguard Worker 					     system_notify_cb, "app" };
219*1c60b9acSAndroid Build Coastguard Worker 	lws_state_notify_link_t *na[] = { &notifier, NULL };
220*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context_creation_info info;
221*1c60b9acSAndroid Build Coastguard Worker 
222*1c60b9acSAndroid Build Coastguard Worker 	signal(SIGINT, sigint_handler);
223*1c60b9acSAndroid Build Coastguard Worker 
224*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof info);
225*1c60b9acSAndroid Build Coastguard Worker 
226*1c60b9acSAndroid Build Coastguard Worker 	lws_cmdline_option_handle_builtin(argc, argv, &info);
227*1c60b9acSAndroid Build Coastguard Worker 
228*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("LWS Secure Streams threads test client [-d<verb>]\n");
229*1c60b9acSAndroid Build Coastguard Worker 
230*1c60b9acSAndroid Build Coastguard Worker 	info.fd_limit_per_thread	= 1 + 6 + 1;
231*1c60b9acSAndroid Build Coastguard Worker 	info.port			= CONTEXT_PORT_NO_LISTEN;
232*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_SS_USE_SSPC)
233*1c60b9acSAndroid Build Coastguard Worker 	info.pss_policies_json		= default_ss_policy;
234*1c60b9acSAndroid Build Coastguard Worker #else
235*1c60b9acSAndroid Build Coastguard Worker 	info.protocols			= lws_sspc_protocols;
236*1c60b9acSAndroid Build Coastguard Worker 	{
237*1c60b9acSAndroid Build Coastguard Worker 		const char *p;
238*1c60b9acSAndroid Build Coastguard Worker 
239*1c60b9acSAndroid Build Coastguard Worker 		/* connect to ssproxy via UDS by default, else via
240*1c60b9acSAndroid Build Coastguard Worker 		 * tcp connection to this port */
241*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-p")))
242*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_port = (uint16_t)atoi(p);
243*1c60b9acSAndroid Build Coastguard Worker 
244*1c60b9acSAndroid Build Coastguard Worker 		/* UDS "proxy.ss.lws" in abstract namespace, else this socket
245*1c60b9acSAndroid Build Coastguard Worker 		 * path; when -p given this can specify the network interface
246*1c60b9acSAndroid Build Coastguard Worker 		 * to bind to */
247*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-i")))
248*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_bind = p;
249*1c60b9acSAndroid Build Coastguard Worker 
250*1c60b9acSAndroid Build Coastguard Worker 		/* if -p given, -a specifies the proxy address to connect to */
251*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-a")))
252*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_address = p;
253*1c60b9acSAndroid Build Coastguard Worker 	}
254*1c60b9acSAndroid Build Coastguard Worker #endif
255*1c60b9acSAndroid Build Coastguard Worker 	info.options			= LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
256*1c60b9acSAndroid Build Coastguard Worker 					  LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
257*1c60b9acSAndroid Build Coastguard Worker 	info.register_notifier_list = na;
258*1c60b9acSAndroid Build Coastguard Worker 
259*1c60b9acSAndroid Build Coastguard Worker 	/* create the context */
260*1c60b9acSAndroid Build Coastguard Worker 
261*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
262*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
263*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("lws init failed\n");
264*1c60b9acSAndroid Build Coastguard Worker 		return 1;
265*1c60b9acSAndroid Build Coastguard Worker 	}
266*1c60b9acSAndroid Build Coastguard Worker 
267*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_SS_USE_SSPC)
268*1c60b9acSAndroid Build Coastguard Worker 	if (!lws_create_vhost(context, &info)) {
269*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to create default vhost\n", __func__);
270*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
271*1c60b9acSAndroid Build Coastguard Worker 	}
272*1c60b9acSAndroid Build Coastguard Worker #endif
273*1c60b9acSAndroid Build Coastguard Worker 
274*1c60b9acSAndroid Build Coastguard Worker 	/* the event loop */
275*1c60b9acSAndroid Build Coastguard Worker 
276*1c60b9acSAndroid Build Coastguard Worker 	while (lws_service(context, 0) >= 0 && !interrupted)
277*1c60b9acSAndroid Build Coastguard Worker 		;
278*1c60b9acSAndroid Build Coastguard Worker 
279*1c60b9acSAndroid Build Coastguard Worker 	/* compare what happened with what we expect */
280*1c60b9acSAndroid Build Coastguard Worker 
281*1c60b9acSAndroid Build Coastguard Worker 	if (wakes > 10)
282*1c60b9acSAndroid Build Coastguard Worker 		/* OSX can do the usleep thread slower than 100ms */
283*1c60b9acSAndroid Build Coastguard Worker 		bad = 0;
284*1c60b9acSAndroid Build Coastguard Worker 
285*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("wakes %d\n", wakes);
286*1c60b9acSAndroid Build Coastguard Worker 
287*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_SS_USE_SSPC)
288*1c60b9acSAndroid Build Coastguard Worker bail:
289*1c60b9acSAndroid Build Coastguard Worker #endif
290*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_cancel(&sul_timeout);
291*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
292*1c60b9acSAndroid Build Coastguard Worker 
293*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
294*1c60b9acSAndroid Build Coastguard Worker 
295*1c60b9acSAndroid Build Coastguard Worker 	return bad;
296*1c60b9acSAndroid Build Coastguard Worker }
297