1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-secure-streams-smd
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 a minimal http client using secure streams to access the
11*1c60b9acSAndroid Build Coastguard Worker  * SMD api.  This file is only built when LWS_SS_USE_SSPC defined.
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * This is an alternative test implementation selected by --multi at runtime,
14*1c60b9acSAndroid Build Coastguard Worker  * it's in its own file to stop muddying up the main test sources.  It's only
15*1c60b9acSAndroid Build Coastguard Worker  * available when built with SSPC / produces -client executable.
16*1c60b9acSAndroid Build Coastguard Worker  *
17*1c60b9acSAndroid Build Coastguard Worker  * We will fork several times, the original thread and the forks hook up to
18*1c60b9acSAndroid Build Coastguard Worker  * the proxy with smd SS, each fork waits a second for everyone to have joined,
19*1c60b9acSAndroid Build Coastguard Worker  * and then each fork (NOT the original process) sends a bunch of user messages
20*1c60b9acSAndroid Build Coastguard Worker  * that all the forks should receive, having been distributed by SMD and the
21*1c60b9acSAndroid Build Coastguard Worker  * ss proxy.
22*1c60b9acSAndroid Build Coastguard Worker  *
23*1c60b9acSAndroid Build Coastguard Worker  * The participants check they received all the messages expected from everyone
24*1c60b9acSAndroid Build Coastguard Worker  * and then send a final message indicating success and exits.  The original
25*1c60b9acSAndroid Build Coastguard Worker  * fork is watching for these to arrive before the timeout, if so it's a PASS.
26*1c60b9acSAndroid Build Coastguard Worker  */
27*1c60b9acSAndroid Build Coastguard Worker 
28*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
29*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
30*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
31*1c60b9acSAndroid Build Coastguard Worker 
32*1c60b9acSAndroid Build Coastguard Worker static int bad = 1, interrupted;
33*1c60b9acSAndroid Build Coastguard Worker 
34*1c60b9acSAndroid Build Coastguard Worker /* number of forks */
35*1c60b9acSAndroid Build Coastguard Worker #define FORKS 4
36*1c60b9acSAndroid Build Coastguard Worker /* number of messages each will send, eg, 4 forks 64 message == 256 messages */
37*1c60b9acSAndroid Build Coastguard Worker #define MSGCOUNT 64
38*1c60b9acSAndroid Build Coastguard Worker 
39*1c60b9acSAndroid Build Coastguard Worker typedef struct myss {
40*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ss_handle 		*ss;
41*1c60b9acSAndroid Build Coastguard Worker 	void				*opaque_data;
42*1c60b9acSAndroid Build Coastguard Worker 	/* ... application specific state ... */
43*1c60b9acSAndroid Build Coastguard Worker 	uint64_t			seen_mask[FORKS];
44*1c60b9acSAndroid Build Coastguard Worker 	int				seen_msgs[FORKS];
45*1c60b9acSAndroid Build Coastguard Worker 	lws_sorted_usec_list_t		sul;
46*1c60b9acSAndroid Build Coastguard Worker 	int				count;
47*1c60b9acSAndroid Build Coastguard Worker 	char				seen_all;
48*1c60b9acSAndroid Build Coastguard Worker 	char				send_seen_all;
49*1c60b9acSAndroid Build Coastguard Worker 	char				starting;
50*1c60b9acSAndroid Build Coastguard Worker } myss_t;
51*1c60b9acSAndroid Build Coastguard Worker 
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker /* secure streams payload interface */
54*1c60b9acSAndroid Build Coastguard Worker 
55*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
multi_myss_rx(void * userobj,const uint8_t * buf,size_t len,int flags)56*1c60b9acSAndroid Build Coastguard Worker multi_myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
57*1c60b9acSAndroid Build Coastguard Worker {
58*1c60b9acSAndroid Build Coastguard Worker 	myss_t *m = (myss_t *)userobj;
59*1c60b9acSAndroid Build Coastguard Worker 	const char *p;
60*1c60b9acSAndroid Build Coastguard Worker 	int fk, t, n;
61*1c60b9acSAndroid Build Coastguard Worker 	size_t al;
62*1c60b9acSAndroid Build Coastguard Worker 
63*1c60b9acSAndroid Build Coastguard Worker 	/* ignore our and other forks announcing their result */
64*1c60b9acSAndroid Build Coastguard Worker 
65*1c60b9acSAndroid Build Coastguard Worker 	if (lws_json_simple_find((const char *)buf, len, "\"seen_all\":", &al))
66*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_OK;
67*1c60b9acSAndroid Build Coastguard Worker 
68*1c60b9acSAndroid Build Coastguard Worker 	/*
69*1c60b9acSAndroid Build Coastguard Worker 	 * otherwise once we saw the expected messages, any other messages
70*1c60b9acSAndroid Build Coastguard Worker 	 * coming in this class are wrong
71*1c60b9acSAndroid Build Coastguard Worker 	 */
72*1c60b9acSAndroid Build Coastguard Worker 
73*1c60b9acSAndroid Build Coastguard Worker 	if (m->seen_all) {
74*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: unexpected extra messages\n", __func__);
75*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
76*1c60b9acSAndroid Build Coastguard Worker 	}
77*1c60b9acSAndroid Build Coastguard Worker 
78*1c60b9acSAndroid Build Coastguard Worker 	p = lws_json_simple_find((const char *)buf, len, "\"fork\":", &al);
79*1c60b9acSAndroid Build Coastguard Worker 	if (!p)
80*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
81*1c60b9acSAndroid Build Coastguard Worker 	fk = atoi(p);
82*1c60b9acSAndroid Build Coastguard Worker 	if (fk < 1 || fk > FORKS)
83*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker 	p = lws_json_simple_find((const char *)buf, len, "\"test\":", &al);
86*1c60b9acSAndroid Build Coastguard Worker 	if (!p)
87*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
88*1c60b9acSAndroid Build Coastguard Worker 	t = atoi(p);
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker 	if (t < 0 || t >= MSGCOUNT)
91*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 	m->seen_mask[fk - 1] |= 1ull << t;
94*1c60b9acSAndroid Build Coastguard Worker 	m->seen_msgs[fk - 1]++; /* keep an eye on dupes */
95*1c60b9acSAndroid Build Coastguard Worker 
96*1c60b9acSAndroid Build Coastguard Worker 	/* Have we seen a full set of messages from everyone? */
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < FORKS; n++) {
99*1c60b9acSAndroid Build Coastguard Worker 		if (m->seen_msgs[n] != (int)MSGCOUNT)
100*1c60b9acSAndroid Build Coastguard Worker 			return LWSSSSRET_OK;
101*1c60b9acSAndroid Build Coastguard Worker 		if (m->seen_mask[n] != 0xffffffffffffffffull)
102*1c60b9acSAndroid Build Coastguard Worker 			return LWSSSSRET_OK;
103*1c60b9acSAndroid Build Coastguard Worker 	}
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker 	/*
106*1c60b9acSAndroid Build Coastguard Worker 	 * Oh... so we have finished collecting messages
107*1c60b9acSAndroid Build Coastguard Worker 	 */
108*1c60b9acSAndroid Build Coastguard Worker 
109*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("%s: test thread %d: %s received all messages\n", __func__,
110*1c60b9acSAndroid Build Coastguard Worker 			(int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
111*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_tag(m->ss));
112*1c60b9acSAndroid Build Coastguard Worker 	m->seen_all = m->send_seen_all = 1;
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 	/*
115*1c60b9acSAndroid Build Coastguard Worker 	 * Prepare to inform the original process we saw everything
116*1c60b9acSAndroid Build Coastguard Worker 	 * from everyone OK
117*1c60b9acSAndroid Build Coastguard Worker 	 */
118*1c60b9acSAndroid Build Coastguard Worker 
119*1c60b9acSAndroid Build Coastguard Worker 	lws_ss_request_tx(m->ss);
120*1c60b9acSAndroid Build Coastguard Worker 
121*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
122*1c60b9acSAndroid Build Coastguard Worker }
123*1c60b9acSAndroid Build Coastguard Worker 
124*1c60b9acSAndroid Build Coastguard Worker static void
sul_multi_tx_periodic_cb(lws_sorted_usec_list_t * sul)125*1c60b9acSAndroid Build Coastguard Worker sul_multi_tx_periodic_cb(lws_sorted_usec_list_t *sul)
126*1c60b9acSAndroid Build Coastguard Worker {
127*1c60b9acSAndroid Build Coastguard Worker 	myss_t *m = lws_container_of(sul, myss_t, sul);
128*1c60b9acSAndroid Build Coastguard Worker 
129*1c60b9acSAndroid Build Coastguard Worker 	if (!m->send_seen_all && m->seen_all) {
130*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_destroy(&m->ss);
131*1c60b9acSAndroid Build Coastguard Worker 		return;
132*1c60b9acSAndroid Build Coastguard Worker 	}
133*1c60b9acSAndroid Build Coastguard Worker 
134*1c60b9acSAndroid Build Coastguard Worker 	m->starting = 1;
135*1c60b9acSAndroid Build Coastguard Worker 	if (m->count < MSGCOUNT ||  m->send_seen_all)
136*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_request_tx(m->ss);
137*1c60b9acSAndroid Build Coastguard Worker }
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
multi_myss_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)140*1c60b9acSAndroid Build Coastguard Worker multi_myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
141*1c60b9acSAndroid Build Coastguard Worker 	int *flags)
142*1c60b9acSAndroid Build Coastguard Worker {
143*1c60b9acSAndroid Build Coastguard Worker 	myss_t *m = (myss_t *)userobj;
144*1c60b9acSAndroid Build Coastguard Worker 
145*1c60b9acSAndroid Build Coastguard Worker 	/*
146*1c60b9acSAndroid Build Coastguard Worker 	 * We want to send exactly MSGCOUNT user class smd messages
147*1c60b9acSAndroid Build Coastguard Worker 	 */
148*1c60b9acSAndroid Build Coastguard Worker 
149*1c60b9acSAndroid Build Coastguard Worker 	if (!m->starting || (m->count == MSGCOUNT && !m->send_seen_all))
150*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_TX_DONT_SEND;
151*1c60b9acSAndroid Build Coastguard Worker 
152*1c60b9acSAndroid Build Coastguard Worker //	lwsl_notice("%s: sending SS smd\n", __func__);
153*1c60b9acSAndroid Build Coastguard Worker 
154*1c60b9acSAndroid Build Coastguard Worker 	lws_ser_wu64be(buf, 1 << LWSSMDCL_USER_BASE_BITNUM);
155*1c60b9acSAndroid Build Coastguard Worker 	lws_ser_wu64be(buf + 8, 0); /* valgrind notices uninitialized if left */
156*1c60b9acSAndroid Build Coastguard Worker 
157*1c60b9acSAndroid Build Coastguard Worker 	if (m->send_seen_all) {
158*1c60b9acSAndroid Build Coastguard Worker 		*len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)
159*1c60b9acSAndroid Build Coastguard Worker 			lws_snprintf((char *)buf + LWS_SMD_SS_RX_HEADER_LEN, *len,
160*1c60b9acSAndroid Build Coastguard Worker 			     "{\"class\":\"user\",\"fork\": %d,\"seen_all\":true}",
161*1c60b9acSAndroid Build Coastguard Worker 			     (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 		m->send_seen_all = 0;
164*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: test thread %d: sent summary message\n", __func__,
165*1c60b9acSAndroid Build Coastguard Worker 				(int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
166*1c60b9acSAndroid Build Coastguard Worker 	} else
167*1c60b9acSAndroid Build Coastguard Worker 		*len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)
168*1c60b9acSAndroid Build Coastguard Worker 			lws_snprintf((char *)buf + LWS_SMD_SS_RX_HEADER_LEN, *len,
169*1c60b9acSAndroid Build Coastguard Worker 			     "{\"class\":\"user\",\"fork\": %d,\"test\":%u}",
170*1c60b9acSAndroid Build Coastguard Worker 			     (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
171*1c60b9acSAndroid Build Coastguard Worker 			     m->count++);
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker 	*flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
174*1c60b9acSAndroid Build Coastguard Worker 
175*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
176*1c60b9acSAndroid Build Coastguard Worker 			sul_multi_tx_periodic_cb, 25 * LWS_US_PER_MS);
177*1c60b9acSAndroid Build Coastguard Worker 
178*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
179*1c60b9acSAndroid Build Coastguard Worker }
180*1c60b9acSAndroid Build Coastguard Worker 
181*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
multi_myss_state(void * userobj,void * h_src,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)182*1c60b9acSAndroid Build Coastguard Worker multi_myss_state(void *userobj, void *h_src, lws_ss_constate_t state,
183*1c60b9acSAndroid Build Coastguard Worker 	   lws_ss_tx_ordinal_t ack)
184*1c60b9acSAndroid Build Coastguard Worker {
185*1c60b9acSAndroid Build Coastguard Worker 	myss_t *m = (myss_t *)userobj;
186*1c60b9acSAndroid Build Coastguard Worker 	int n;
187*1c60b9acSAndroid Build Coastguard Worker 
188*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: %s: %s (%d), ord 0x%x\n", __func__, lws_ss_tag(m->ss),
189*1c60b9acSAndroid Build Coastguard Worker 		    lws_ss_state_name((int)state), state, (unsigned int)ack);
190*1c60b9acSAndroid Build Coastguard Worker 
191*1c60b9acSAndroid Build Coastguard Worker 	switch (state) {
192*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DESTROYING:
193*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_cancel(&m->sul);
194*1c60b9acSAndroid Build Coastguard Worker 		interrupted = 1;
195*1c60b9acSAndroid Build Coastguard Worker 		return 0;
196*1c60b9acSAndroid Build Coastguard Worker 
197*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_CONNECTED:
198*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: CONNECTED: test fork %d\n", __func__,
199*1c60b9acSAndroid Build Coastguard Worker 				(int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
200*1c60b9acSAndroid Build Coastguard Worker 		/*
201*1c60b9acSAndroid Build Coastguard Worker 		 * Because in this test everybody is watching and counting
202*1c60b9acSAndroid Build Coastguard Worker 		 * everybody else's messages from different forks, we have to
203*1c60b9acSAndroid Build Coastguard Worker 		 * hold off starting sending for 2s so all forks can join the
204*1c60b9acSAndroid Build Coastguard Worker 		 * proxy first and not miss anything
205*1c60b9acSAndroid Build Coastguard Worker 		 */
206*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
207*1c60b9acSAndroid Build Coastguard Worker 				sul_multi_tx_periodic_cb, 2 * LWS_US_PER_SEC);
208*1c60b9acSAndroid Build Coastguard Worker 		m->starting = 0;
209*1c60b9acSAndroid Build Coastguard Worker 		return 0;
210*1c60b9acSAndroid Build Coastguard Worker 	case LWSSSCS_DISCONNECTED:
211*1c60b9acSAndroid Build Coastguard Worker 		for (n = 0; n < FORKS; n++)
212*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: testfork %d: peer %d: seen_msg = %d, "
213*1c60b9acSAndroid Build Coastguard Worker 				    "seen make = 0x%llx\n", __func__,
214*1c60b9acSAndroid Build Coastguard Worker 				    (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
215*1c60b9acSAndroid Build Coastguard Worker 				    n, m->seen_msgs[n],
216*1c60b9acSAndroid Build Coastguard Worker 				    (unsigned long long)m->seen_mask[n]);
217*1c60b9acSAndroid Build Coastguard Worker 		break;
218*1c60b9acSAndroid Build Coastguard Worker 	default:
219*1c60b9acSAndroid Build Coastguard Worker 		break;
220*1c60b9acSAndroid Build Coastguard Worker 	}
221*1c60b9acSAndroid Build Coastguard Worker 
222*1c60b9acSAndroid Build Coastguard Worker 	return 0;
223*1c60b9acSAndroid Build Coastguard Worker }
224*1c60b9acSAndroid Build Coastguard Worker 
225*1c60b9acSAndroid Build Coastguard Worker static const lws_ss_info_t ssi_multi_lws_smd = {
226*1c60b9acSAndroid Build Coastguard Worker 	.handle_offset		  = offsetof(myss_t, ss),
227*1c60b9acSAndroid Build Coastguard Worker 	.opaque_user_data_offset  = offsetof(myss_t, opaque_data),
228*1c60b9acSAndroid Build Coastguard Worker 	.rx			  = multi_myss_rx,
229*1c60b9acSAndroid Build Coastguard Worker 	.tx			  = multi_myss_tx,
230*1c60b9acSAndroid Build Coastguard Worker 	.state			  = multi_myss_state,
231*1c60b9acSAndroid Build Coastguard Worker 	.user_alloc		  = sizeof(myss_t),
232*1c60b9acSAndroid Build Coastguard Worker 	.streamtype		  = LWS_SMD_STREAMTYPENAME,
233*1c60b9acSAndroid Build Coastguard Worker 	.manual_initial_tx_credit = 1 << LWSSMDCL_USER_BASE_BITNUM,
234*1c60b9acSAndroid Build Coastguard Worker };
235*1c60b9acSAndroid Build Coastguard Worker 
236*1c60b9acSAndroid Build Coastguard Worker static lws_ss_state_return_t
multi_myss_rx_monitor(void * userobj,const uint8_t * buf,size_t len,int flags)237*1c60b9acSAndroid Build Coastguard Worker multi_myss_rx_monitor(void *userobj, const uint8_t *buf, size_t len, int flags)
238*1c60b9acSAndroid Build Coastguard Worker {
239*1c60b9acSAndroid Build Coastguard Worker 	myss_t *m = (myss_t *)userobj;
240*1c60b9acSAndroid Build Coastguard Worker 	const char *p;
241*1c60b9acSAndroid Build Coastguard Worker 	size_t al;
242*1c60b9acSAndroid Build Coastguard Worker 	int fk, n;
243*1c60b9acSAndroid Build Coastguard Worker 
244*1c60b9acSAndroid Build Coastguard Worker 	/* ignore our and other forks announcing their result */
245*1c60b9acSAndroid Build Coastguard Worker 
246*1c60b9acSAndroid Build Coastguard Worker 	if (!lws_json_simple_find((const char *)buf, len, "\"seen_all\":", &al))
247*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_OK;
248*1c60b9acSAndroid Build Coastguard Worker 
249*1c60b9acSAndroid Build Coastguard Worker 	p = lws_json_simple_find((const char *)buf, len, "\"fork\":", &al);
250*1c60b9acSAndroid Build Coastguard Worker 	if (!p)
251*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
252*1c60b9acSAndroid Build Coastguard Worker 	fk = atoi(p);
253*1c60b9acSAndroid Build Coastguard Worker 	if (fk < 1 || fk > FORKS)
254*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
255*1c60b9acSAndroid Build Coastguard Worker 
256*1c60b9acSAndroid Build Coastguard Worker 	if (m->seen_msgs[fk - 1])
257*1c60b9acSAndroid Build Coastguard Worker 		/* expected only once ... dupe */
258*1c60b9acSAndroid Build Coastguard Worker 		return LWSSSSRET_DESTROY_ME;
259*1c60b9acSAndroid Build Coastguard Worker 
260*1c60b9acSAndroid Build Coastguard Worker 	m->seen_msgs[fk - 1] = 1;
261*1c60b9acSAndroid Build Coastguard Worker 
262*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < FORKS; n++)
263*1c60b9acSAndroid Build Coastguard Worker 		if (!m->seen_msgs[n])
264*1c60b9acSAndroid Build Coastguard Worker 			return LWSSSSRET_OK;
265*1c60b9acSAndroid Build Coastguard Worker 
266*1c60b9acSAndroid Build Coastguard Worker 	/* the test has succeeded */
267*1c60b9acSAndroid Build Coastguard Worker 
268*1c60b9acSAndroid Build Coastguard Worker 	bad = 0;
269*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
270*1c60b9acSAndroid Build Coastguard Worker 
271*1c60b9acSAndroid Build Coastguard Worker 	return LWSSSSRET_OK;
272*1c60b9acSAndroid Build Coastguard Worker }
273*1c60b9acSAndroid Build Coastguard Worker 
274*1c60b9acSAndroid Build Coastguard Worker static const lws_ss_info_t ssi_multi_lws_smd_monitor = {
275*1c60b9acSAndroid Build Coastguard Worker 	.handle_offset		  = offsetof(myss_t, ss),
276*1c60b9acSAndroid Build Coastguard Worker 	.opaque_user_data_offset  = offsetof(myss_t, opaque_data),
277*1c60b9acSAndroid Build Coastguard Worker 	.rx			  = multi_myss_rx_monitor,
278*1c60b9acSAndroid Build Coastguard Worker //	.state			  = multi_myss_state_monitor,
279*1c60b9acSAndroid Build Coastguard Worker 	.user_alloc		  = sizeof(myss_t),
280*1c60b9acSAndroid Build Coastguard Worker 	.streamtype		  = LWS_SMD_STREAMTYPENAME,
281*1c60b9acSAndroid Build Coastguard Worker 	.manual_initial_tx_credit = 1 << LWSSMDCL_USER_BASE_BITNUM,
282*1c60b9acSAndroid Build Coastguard Worker };
283*1c60b9acSAndroid Build Coastguard Worker 
284*1c60b9acSAndroid Build Coastguard Worker /* for comparison, this is a non-SS lws_smd participant */
285*1c60b9acSAndroid Build Coastguard Worker 
286*1c60b9acSAndroid Build Coastguard Worker static int
direct_smd_cb(void * opaque,lws_smd_class_t _class,lws_usec_t timestamp,void * buf,size_t len)287*1c60b9acSAndroid Build Coastguard Worker direct_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
288*1c60b9acSAndroid Build Coastguard Worker 	      void *buf, size_t len)
289*1c60b9acSAndroid Build Coastguard Worker {
290*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context **pctx = (struct lws_context **)opaque;
291*1c60b9acSAndroid Build Coastguard Worker 
292*1c60b9acSAndroid Build Coastguard Worker 	if (_class != LWSSMDCL_SYSTEM_STATE)
293*1c60b9acSAndroid Build Coastguard Worker 		return 0;
294*1c60b9acSAndroid Build Coastguard Worker 
295*1c60b9acSAndroid Build Coastguard Worker 	if (!lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
296*1c60b9acSAndroid Build Coastguard Worker 
297*1c60b9acSAndroid Build Coastguard Worker 		/*
298*1c60b9acSAndroid Build Coastguard Worker 		 * Create the SSPC link to lws_smd... notice in ssi_lws_smd
299*1c60b9acSAndroid Build Coastguard Worker 		 * above, we tell this link to use the user class filter.
300*1c60b9acSAndroid Build Coastguard Worker 		 *
301*1c60b9acSAndroid Build Coastguard Worker 		 * If context->user is zero, we are the original process
302*1c60b9acSAndroid Build Coastguard Worker 		 * monitoring the progress of the others, otherwise we are
303*1c60b9acSAndroid Build Coastguard Worker 		 * 1 .. FORKS and producing / checking the smd messages
304*1c60b9acSAndroid Build Coastguard Worker 		 */
305*1c60b9acSAndroid Build Coastguard Worker 
306*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: starting ss for test fork %d\n", __func__,
307*1c60b9acSAndroid Build Coastguard Worker 				(int)(intptr_t)lws_context_user(*pctx));
308*1c60b9acSAndroid Build Coastguard Worker 
309*1c60b9acSAndroid Build Coastguard Worker 		if (lws_ss_create(*pctx, 0, lws_context_user(*pctx) ?
310*1c60b9acSAndroid Build Coastguard Worker 				&ssi_multi_lws_smd /* forked process send / check */:
311*1c60b9acSAndroid Build Coastguard Worker 				&ssi_multi_lws_smd_monitor /* original monitors */,
312*1c60b9acSAndroid Build Coastguard Worker 				NULL, NULL, NULL, NULL)) {
313*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("%s: failed to create secure stream\n",
314*1c60b9acSAndroid Build Coastguard Worker 				 __func__);
315*1c60b9acSAndroid Build Coastguard Worker 
316*1c60b9acSAndroid Build Coastguard Worker 			return -1;
317*1c60b9acSAndroid Build Coastguard Worker 		}
318*1c60b9acSAndroid Build Coastguard Worker 	}
319*1c60b9acSAndroid Build Coastguard Worker 
320*1c60b9acSAndroid Build Coastguard Worker 	return 0;
321*1c60b9acSAndroid Build Coastguard Worker }
322*1c60b9acSAndroid Build Coastguard Worker 
323*1c60b9acSAndroid Build Coastguard Worker 
324*1c60b9acSAndroid Build Coastguard Worker static void
sul_timeout_cb(lws_sorted_usec_list_t * sul)325*1c60b9acSAndroid Build Coastguard Worker sul_timeout_cb(lws_sorted_usec_list_t *sul)
326*1c60b9acSAndroid Build Coastguard Worker {
327*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
328*1c60b9acSAndroid Build Coastguard Worker }
329*1c60b9acSAndroid Build Coastguard Worker 
330*1c60b9acSAndroid Build Coastguard Worker int
smd_ss_multi_test(int argc,const char ** argv)331*1c60b9acSAndroid Build Coastguard Worker smd_ss_multi_test(int argc, const char **argv)
332*1c60b9acSAndroid Build Coastguard Worker {
333*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context_creation_info info;
334*1c60b9acSAndroid Build Coastguard Worker 	lws_sorted_usec_list_t sul_timeout;
335*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context;
336*1c60b9acSAndroid Build Coastguard Worker 	pid_t pid;
337*1c60b9acSAndroid Build Coastguard Worker 	int n;
338*1c60b9acSAndroid Build Coastguard Worker 
339*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("LWS Secure Streams SMD MULTI test client [-d<verb>]\n");
340*1c60b9acSAndroid Build Coastguard Worker 
341*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < FORKS; n++) {
342*1c60b9acSAndroid Build Coastguard Worker 		pid = fork();
343*1c60b9acSAndroid Build Coastguard Worker 		if (!pid) /* forked child */ {
344*1c60b9acSAndroid Build Coastguard Worker 			break;
345*1c60b9acSAndroid Build Coastguard Worker 		}
346*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("%s: forked test process %u\n", __func__, pid);
347*1c60b9acSAndroid Build Coastguard Worker 	}
348*1c60b9acSAndroid Build Coastguard Worker 
349*1c60b9acSAndroid Build Coastguard Worker 	if (n == FORKS)
350*1c60b9acSAndroid Build Coastguard Worker 		/* the original process */
351*1c60b9acSAndroid Build Coastguard Worker 		n = -1; /* so original ends up with context.user as 0 below */
352*1c60b9acSAndroid Build Coastguard Worker 
353*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof info);
354*1c60b9acSAndroid Build Coastguard Worker 	memset(&sul_timeout, 0, sizeof sul_timeout);
355*1c60b9acSAndroid Build Coastguard Worker 
356*1c60b9acSAndroid Build Coastguard Worker 	lws_cmdline_option_handle_builtin(argc, argv, &info);
357*1c60b9acSAndroid Build Coastguard Worker 
358*1c60b9acSAndroid Build Coastguard Worker 	{
359*1c60b9acSAndroid Build Coastguard Worker 		const char *p;
360*1c60b9acSAndroid Build Coastguard Worker 
361*1c60b9acSAndroid Build Coastguard Worker 		/* connect to ssproxy via UDS by default, else via
362*1c60b9acSAndroid Build Coastguard Worker 		 * tcp connection to this port */
363*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-p")))
364*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_port = (uint16_t)atoi(p);
365*1c60b9acSAndroid Build Coastguard Worker 
366*1c60b9acSAndroid Build Coastguard Worker 		/* UDS "proxy.ss.lws" in abstract namespace, else this socket
367*1c60b9acSAndroid Build Coastguard Worker 		 * path; when -p given this can specify the network interface
368*1c60b9acSAndroid Build Coastguard Worker 		 * to bind to */
369*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-i")))
370*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_bind = p;
371*1c60b9acSAndroid Build Coastguard Worker 
372*1c60b9acSAndroid Build Coastguard Worker 		/* if -p given, -a specifies the proxy address to connect to */
373*1c60b9acSAndroid Build Coastguard Worker 		if ((p = lws_cmdline_option(argc, argv, "-a")))
374*1c60b9acSAndroid Build Coastguard Worker 			info.ss_proxy_address = p;
375*1c60b9acSAndroid Build Coastguard Worker 	}
376*1c60b9acSAndroid Build Coastguard Worker 
377*1c60b9acSAndroid Build Coastguard Worker 	info.fd_limit_per_thread	= 1 + 6 + 1;
378*1c60b9acSAndroid Build Coastguard Worker 	info.port			= CONTEXT_PORT_NO_LISTEN;
379*1c60b9acSAndroid Build Coastguard Worker 	info.protocols			= lws_sspc_protocols;
380*1c60b9acSAndroid Build Coastguard Worker 	info.options			= LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
381*1c60b9acSAndroid Build Coastguard Worker 					  LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
382*1c60b9acSAndroid Build Coastguard Worker 
383*1c60b9acSAndroid Build Coastguard Worker 	info.early_smd_cb		= direct_smd_cb;
384*1c60b9acSAndroid Build Coastguard Worker 	info.early_smd_class_filter	= 0xffffffff;
385*1c60b9acSAndroid Build Coastguard Worker 	info.early_smd_opaque		= &context;
386*1c60b9acSAndroid Build Coastguard Worker 
387*1c60b9acSAndroid Build Coastguard Worker 	info.user			= (void *)(intptr_t)(n + 1);
388*1c60b9acSAndroid Build Coastguard Worker 
389*1c60b9acSAndroid Build Coastguard Worker 	/* create the context */
390*1c60b9acSAndroid Build Coastguard Worker 
391*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
392*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
393*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("lws init failed\n");
394*1c60b9acSAndroid Build Coastguard Worker 		return 1;
395*1c60b9acSAndroid Build Coastguard Worker 	}
396*1c60b9acSAndroid Build Coastguard Worker 
397*1c60b9acSAndroid Build Coastguard Worker 	if (!lws_create_vhost(context, &info)) {
398*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: failed to create default vhost\n", __func__);
399*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
400*1c60b9acSAndroid Build Coastguard Worker 	}
401*1c60b9acSAndroid Build Coastguard Worker 
402*1c60b9acSAndroid Build Coastguard Worker 	/* set up the test timeout */
403*1c60b9acSAndroid Build Coastguard Worker 
404*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_schedule(context, 0, &sul_timeout, sul_timeout_cb,
405*1c60b9acSAndroid Build Coastguard Worker 			 10 * LWS_US_PER_SEC);
406*1c60b9acSAndroid Build Coastguard Worker 
407*1c60b9acSAndroid Build Coastguard Worker 	/* the event loop */
408*1c60b9acSAndroid Build Coastguard Worker 
409*1c60b9acSAndroid Build Coastguard Worker 	while (lws_service(context, 0) >= 0 && !interrupted)
410*1c60b9acSAndroid Build Coastguard Worker 		;
411*1c60b9acSAndroid Build Coastguard Worker 
412*1c60b9acSAndroid Build Coastguard Worker bail:
413*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
414*1c60b9acSAndroid Build Coastguard Worker 
415*1c60b9acSAndroid Build Coastguard Worker 	if (n == -1)
416*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("%s: finished %s\n", __func__, bad ? "FAIL" : "PASS");
417*1c60b9acSAndroid Build Coastguard Worker 
418*1c60b9acSAndroid Build Coastguard Worker 	return bad;
419*1c60b9acSAndroid Build Coastguard Worker }
420