1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws-minimal-ws-raw-proxy
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  * This demonstrates a ws (server) -> raw (client) proxy,  it's a ws server
10*1c60b9acSAndroid Build Coastguard Worker  * that accepts connections, creates an onward client connection to some other
11*1c60b9acSAndroid Build Coastguard Worker  * no-protocol server, eg, nc -l 127.0.0.1 1234
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The idea is to show the general approach for making async proxies using lws
14*1c60b9acSAndroid Build Coastguard Worker  * that are robust and valgrind-clean.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * There's no vhd or pss on either side.  Instead when the ws server gets an
17*1c60b9acSAndroid Build Coastguard Worker  * incoming connection and negotiates the ws link, he creates an object
18*1c60b9acSAndroid Build Coastguard Worker  * representing the proxied connection, it is not destroyed automatically when
19*1c60b9acSAndroid Build Coastguard Worker  * any particular wsi is closed, instead the last wsi that is part of the
20*1c60b9acSAndroid Build Coastguard Worker  * proxied connection destroys it when he is closed.
21*1c60b9acSAndroid Build Coastguard Worker  */
22*1c60b9acSAndroid Build Coastguard Worker 
23*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
24*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
25*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
26*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
27*1c60b9acSAndroid Build Coastguard Worker 
28*1c60b9acSAndroid Build Coastguard Worker /* one of these created for each pending message that is to be forwarded */
29*1c60b9acSAndroid Build Coastguard Worker 
30*1c60b9acSAndroid Build Coastguard Worker typedef struct proxy_msg {
31*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_t		list;
32*1c60b9acSAndroid Build Coastguard Worker 	size_t			len;
33*1c60b9acSAndroid Build Coastguard Worker 	/*
34*1c60b9acSAndroid Build Coastguard Worker 	 * the packet content is overallocated here, if p is a pointer to
35*1c60b9acSAndroid Build Coastguard Worker 	 * this struct, you can get a pointer to the message contents by
36*1c60b9acSAndroid Build Coastguard Worker 	 * ((uint8_t)&p[1]) + LWS_PRE.
37*1c60b9acSAndroid Build Coastguard Worker 	 *
38*1c60b9acSAndroid Build Coastguard Worker 	 * Notice we additionally take care to overallocate LWS_PRE before the
39*1c60b9acSAndroid Build Coastguard Worker 	 * actual message data, so we can simplify sending it.
40*1c60b9acSAndroid Build Coastguard Worker 	 */
41*1c60b9acSAndroid Build Coastguard Worker } proxy_msg_t;
42*1c60b9acSAndroid Build Coastguard Worker 
43*1c60b9acSAndroid Build Coastguard Worker /*
44*1c60b9acSAndroid Build Coastguard Worker  * One of these is created when a inbound ws connection joins, it represents
45*1c60b9acSAndroid Build Coastguard Worker  * the proxy action provoked by that.
46*1c60b9acSAndroid Build Coastguard Worker  */
47*1c60b9acSAndroid Build Coastguard Worker 
48*1c60b9acSAndroid Build Coastguard Worker typedef struct proxy_conn {
49*1c60b9acSAndroid Build Coastguard Worker 	struct lws		*wsi_ws; /* wsi for the inbound ws conn */
50*1c60b9acSAndroid Build Coastguard Worker 	struct lws		*wsi_raw; /* wsi for the outbound raw conn */
51*1c60b9acSAndroid Build Coastguard Worker 
52*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_owner_t	pending_msg_to_ws;
53*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_owner_t	pending_msg_to_raw;
54*1c60b9acSAndroid Build Coastguard Worker } proxy_conn_t;
55*1c60b9acSAndroid Build Coastguard Worker 
56*1c60b9acSAndroid Build Coastguard Worker 
57*1c60b9acSAndroid Build Coastguard Worker static int
proxy_ws_raw_msg_destroy(struct lws_dll2 * d,void * user)58*1c60b9acSAndroid Build Coastguard Worker proxy_ws_raw_msg_destroy(struct lws_dll2 *d, void *user)
59*1c60b9acSAndroid Build Coastguard Worker {
60*1c60b9acSAndroid Build Coastguard Worker 	proxy_msg_t *msg = lws_container_of(d, proxy_msg_t, list);
61*1c60b9acSAndroid Build Coastguard Worker 
62*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(d);
63*1c60b9acSAndroid Build Coastguard Worker 	free(msg);
64*1c60b9acSAndroid Build Coastguard Worker 
65*1c60b9acSAndroid Build Coastguard Worker 	return 0;
66*1c60b9acSAndroid Build Coastguard Worker }
67*1c60b9acSAndroid Build Coastguard Worker 
68*1c60b9acSAndroid Build Coastguard Worker /*
69*1c60b9acSAndroid Build Coastguard Worker  * First the ws server side
70*1c60b9acSAndroid Build Coastguard Worker  */
71*1c60b9acSAndroid Build Coastguard Worker 
72*1c60b9acSAndroid Build Coastguard Worker static int
callback_proxy_ws_server(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)73*1c60b9acSAndroid Build Coastguard Worker callback_proxy_ws_server(struct lws *wsi, enum lws_callback_reasons reason,
74*1c60b9acSAndroid Build Coastguard Worker 			 void *user, void *in, size_t len)
75*1c60b9acSAndroid Build Coastguard Worker {
76*1c60b9acSAndroid Build Coastguard Worker 	proxy_conn_t *pc = (proxy_conn_t *)lws_get_opaque_user_data(wsi);
77*1c60b9acSAndroid Build Coastguard Worker 	struct lws_client_connect_info i;
78*1c60b9acSAndroid Build Coastguard Worker 	proxy_msg_t *msg;
79*1c60b9acSAndroid Build Coastguard Worker 	uint8_t *data;
80*1c60b9acSAndroid Build Coastguard Worker 	int m, a;
81*1c60b9acSAndroid Build Coastguard Worker 
82*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
83*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_ESTABLISHED:
84*1c60b9acSAndroid Build Coastguard Worker 		/* so let's create the proxy connection object */
85*1c60b9acSAndroid Build Coastguard Worker 		pc = malloc(sizeof(*pc));
86*1c60b9acSAndroid Build Coastguard Worker 		memset(pc, 0, sizeof(*pc));
87*1c60b9acSAndroid Build Coastguard Worker 
88*1c60b9acSAndroid Build Coastguard Worker 		/* mark this accepted ws connection with the proxy conn obj */
89*1c60b9acSAndroid Build Coastguard Worker 		lws_set_opaque_user_data(wsi, pc);
90*1c60b9acSAndroid Build Coastguard Worker 		/* tell the proxy conn object that we are the ws side of it */
91*1c60b9acSAndroid Build Coastguard Worker 		pc->wsi_ws = wsi;
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 		/*
94*1c60b9acSAndroid Build Coastguard Worker 		 * For this example proxy, our job is to create a new, onward,
95*1c60b9acSAndroid Build Coastguard Worker 		 * raw client connection to proxy stuff on to
96*1c60b9acSAndroid Build Coastguard Worker 		 */
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 		memset(&i, 0, sizeof(i));
99*1c60b9acSAndroid Build Coastguard Worker 
100*1c60b9acSAndroid Build Coastguard Worker 		i.method = "RAW";
101*1c60b9acSAndroid Build Coastguard Worker 		i.context = lws_get_context(wsi);
102*1c60b9acSAndroid Build Coastguard Worker 		i.port = 1234;
103*1c60b9acSAndroid Build Coastguard Worker 		i.address = "127.0.0.1";
104*1c60b9acSAndroid Build Coastguard Worker 		i.ssl_connection = 0;
105*1c60b9acSAndroid Build Coastguard Worker 		i.local_protocol_name = "lws-ws-raw-raw";
106*1c60b9acSAndroid Build Coastguard Worker 
107*1c60b9acSAndroid Build Coastguard Worker 		/* also mark the onward, raw client conn with the proxy_conn */
108*1c60b9acSAndroid Build Coastguard Worker 		i.opaque_user_data = pc;
109*1c60b9acSAndroid Build Coastguard Worker 		/* if it succeeds, set the wsi into the proxy_conn */
110*1c60b9acSAndroid Build Coastguard Worker 		i.pwsi = &pc->wsi_raw;
111*1c60b9acSAndroid Build Coastguard Worker 
112*1c60b9acSAndroid Build Coastguard Worker 		if (!lws_client_connect_via_info(&i)) {
113*1c60b9acSAndroid Build Coastguard Worker 			lwsl_warn("%s: onward connection failed\n", __func__);
114*1c60b9acSAndroid Build Coastguard Worker 			return -1; /* hang up on the ws client, triggering
115*1c60b9acSAndroid Build Coastguard Worker 				    * _CLOSE flow */
116*1c60b9acSAndroid Build Coastguard Worker 		}
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker 		break;
119*1c60b9acSAndroid Build Coastguard Worker 
120*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLOSED:
121*1c60b9acSAndroid Build Coastguard Worker 		/*
122*1c60b9acSAndroid Build Coastguard Worker 		 * Clean up any pending messages to us that are never going
123*1c60b9acSAndroid Build Coastguard Worker 		 * to get delivered now, we are in the middle of closing
124*1c60b9acSAndroid Build Coastguard Worker 		 */
125*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_foreach_safe(&pc->pending_msg_to_ws, NULL,
126*1c60b9acSAndroid Build Coastguard Worker 				      proxy_ws_raw_msg_destroy);
127*1c60b9acSAndroid Build Coastguard Worker 
128*1c60b9acSAndroid Build Coastguard Worker 		/*
129*1c60b9acSAndroid Build Coastguard Worker 		 * Remove our pointer from the proxy_conn... we are about to
130*1c60b9acSAndroid Build Coastguard Worker 		 * be destroyed.
131*1c60b9acSAndroid Build Coastguard Worker 		 */
132*1c60b9acSAndroid Build Coastguard Worker 		pc->wsi_ws = NULL;
133*1c60b9acSAndroid Build Coastguard Worker 		lws_set_opaque_user_data(wsi, NULL);
134*1c60b9acSAndroid Build Coastguard Worker 
135*1c60b9acSAndroid Build Coastguard Worker 		if (!pc->wsi_raw) {
136*1c60b9acSAndroid Build Coastguard Worker 			/*
137*1c60b9acSAndroid Build Coastguard Worker 			 * The onward raw conn either never got started or is
138*1c60b9acSAndroid Build Coastguard Worker 			 * already closed... then we are the last guy still
139*1c60b9acSAndroid Build Coastguard Worker 			 * holding on to the proxy_conn... and we're going away
140*1c60b9acSAndroid Build Coastguard Worker 			 * so let's destroy it
141*1c60b9acSAndroid Build Coastguard Worker 			 */
142*1c60b9acSAndroid Build Coastguard Worker 
143*1c60b9acSAndroid Build Coastguard Worker 			free(pc);
144*1c60b9acSAndroid Build Coastguard Worker 			break;
145*1c60b9acSAndroid Build Coastguard Worker 		}
146*1c60b9acSAndroid Build Coastguard Worker 
147*1c60b9acSAndroid Build Coastguard Worker 		/*
148*1c60b9acSAndroid Build Coastguard Worker 		 * Onward conn still alive...
149*1c60b9acSAndroid Build Coastguard Worker 		 * does he have stuff left to deliver?
150*1c60b9acSAndroid Build Coastguard Worker 		 */
151*1c60b9acSAndroid Build Coastguard Worker 		if (pc->pending_msg_to_raw.count) {
152*1c60b9acSAndroid Build Coastguard Worker 			/*
153*1c60b9acSAndroid Build Coastguard Worker 			 * Yes, let him get on with trying to send
154*1c60b9acSAndroid Build Coastguard Worker 			 * the remaining pieces... but put a time limit
155*1c60b9acSAndroid Build Coastguard Worker 			 * on how hard he will try now the ws part is
156*1c60b9acSAndroid Build Coastguard Worker 			 * disappearing... give him 3s
157*1c60b9acSAndroid Build Coastguard Worker 			 */
158*1c60b9acSAndroid Build Coastguard Worker 			lws_set_timeout(pc->wsi_raw,
159*1c60b9acSAndroid Build Coastguard Worker 				PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE, 3);
160*1c60b9acSAndroid Build Coastguard Worker 			break;
161*1c60b9acSAndroid Build Coastguard Worker 		}
162*1c60b9acSAndroid Build Coastguard Worker 		/*
163*1c60b9acSAndroid Build Coastguard Worker 		 * Onward raw client conn doesn't have anything left
164*1c60b9acSAndroid Build Coastguard Worker 		 * to do, let's close him right after this, he will take care to
165*1c60b9acSAndroid Build Coastguard Worker 		 * destroy the proxy_conn when he goes down after he sees we
166*1c60b9acSAndroid Build Coastguard Worker 		 * have already been closed
167*1c60b9acSAndroid Build Coastguard Worker 		 */
168*1c60b9acSAndroid Build Coastguard Worker 
169*1c60b9acSAndroid Build Coastguard Worker 		lws_wsi_close(pc->wsi_raw, LWS_TO_KILL_ASYNC);
170*1c60b9acSAndroid Build Coastguard Worker 		break;
171*1c60b9acSAndroid Build Coastguard Worker 
172*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_SERVER_WRITEABLE:
173*1c60b9acSAndroid Build Coastguard Worker 		if (!pc || !pc->pending_msg_to_ws.count)
174*1c60b9acSAndroid Build Coastguard Worker 			break;
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 		msg = lws_container_of(pc->pending_msg_to_ws.head,
177*1c60b9acSAndroid Build Coastguard Worker 				       proxy_msg_t, list);
178*1c60b9acSAndroid Build Coastguard Worker 		data = (uint8_t *)&msg[1] + LWS_PRE;
179*1c60b9acSAndroid Build Coastguard Worker 
180*1c60b9acSAndroid Build Coastguard Worker 		/* notice we allowed for LWS_PRE in the payload already */
181*1c60b9acSAndroid Build Coastguard Worker 		m = lws_write(wsi, data, msg->len, LWS_WRITE_TEXT);
182*1c60b9acSAndroid Build Coastguard Worker 		a = (int)msg->len;
183*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&msg->list);
184*1c60b9acSAndroid Build Coastguard Worker 		free(msg);
185*1c60b9acSAndroid Build Coastguard Worker 
186*1c60b9acSAndroid Build Coastguard Worker 		if (m < a) {
187*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("ERROR %d writing to ws\n", m);
188*1c60b9acSAndroid Build Coastguard Worker 			return -1;
189*1c60b9acSAndroid Build Coastguard Worker 		}
190*1c60b9acSAndroid Build Coastguard Worker 
191*1c60b9acSAndroid Build Coastguard Worker 		/*
192*1c60b9acSAndroid Build Coastguard Worker 		 * If more to do...
193*1c60b9acSAndroid Build Coastguard Worker 		 */
194*1c60b9acSAndroid Build Coastguard Worker 		if (pc->pending_msg_to_ws.count)
195*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
196*1c60b9acSAndroid Build Coastguard Worker 		break;
197*1c60b9acSAndroid Build Coastguard Worker 
198*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RECEIVE:
199*1c60b9acSAndroid Build Coastguard Worker 		if (!pc || !pc->wsi_raw)
200*1c60b9acSAndroid Build Coastguard Worker 			break;
201*1c60b9acSAndroid Build Coastguard Worker 
202*1c60b9acSAndroid Build Coastguard Worker 		/* notice we over-allocate by LWS_PRE + rx len */
203*1c60b9acSAndroid Build Coastguard Worker 		msg = (proxy_msg_t *)malloc(sizeof(*msg) + LWS_PRE + len);
204*1c60b9acSAndroid Build Coastguard Worker 		data = (uint8_t *)&msg[1] + LWS_PRE;
205*1c60b9acSAndroid Build Coastguard Worker 
206*1c60b9acSAndroid Build Coastguard Worker 		if (!msg) {
207*1c60b9acSAndroid Build Coastguard Worker 			lwsl_user("OOM: dropping\n");
208*1c60b9acSAndroid Build Coastguard Worker 			break;
209*1c60b9acSAndroid Build Coastguard Worker 		}
210*1c60b9acSAndroid Build Coastguard Worker 
211*1c60b9acSAndroid Build Coastguard Worker 		memset(msg, 0, sizeof(*msg));
212*1c60b9acSAndroid Build Coastguard Worker 		msg->len = len;
213*1c60b9acSAndroid Build Coastguard Worker 		memcpy(data, in, len);
214*1c60b9acSAndroid Build Coastguard Worker 
215*1c60b9acSAndroid Build Coastguard Worker 		/* add us on to the list of packets to send to the onward conn */
216*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_add_tail(&msg->list, &pc->pending_msg_to_raw);
217*1c60b9acSAndroid Build Coastguard Worker 
218*1c60b9acSAndroid Build Coastguard Worker 		/* ask to send on the onward proxy client conn */
219*1c60b9acSAndroid Build Coastguard Worker 		lws_callback_on_writable(pc->wsi_raw);
220*1c60b9acSAndroid Build Coastguard Worker 		break;
221*1c60b9acSAndroid Build Coastguard Worker 
222*1c60b9acSAndroid Build Coastguard Worker 	default:
223*1c60b9acSAndroid Build Coastguard Worker 		break;
224*1c60b9acSAndroid Build Coastguard Worker 	}
225*1c60b9acSAndroid Build Coastguard Worker 
226*1c60b9acSAndroid Build Coastguard Worker 	return 0;
227*1c60b9acSAndroid Build Coastguard Worker }
228*1c60b9acSAndroid Build Coastguard Worker 
229*1c60b9acSAndroid Build Coastguard Worker /*
230*1c60b9acSAndroid Build Coastguard Worker  * Then the onward, raw client side
231*1c60b9acSAndroid Build Coastguard Worker  */
232*1c60b9acSAndroid Build Coastguard Worker 
233*1c60b9acSAndroid Build Coastguard Worker static int
callback_proxy_raw_client(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)234*1c60b9acSAndroid Build Coastguard Worker callback_proxy_raw_client(struct lws *wsi, enum lws_callback_reasons reason,
235*1c60b9acSAndroid Build Coastguard Worker 			  void *user, void *in, size_t len)
236*1c60b9acSAndroid Build Coastguard Worker {
237*1c60b9acSAndroid Build Coastguard Worker 	proxy_conn_t *pc = (proxy_conn_t *)lws_get_opaque_user_data(wsi);
238*1c60b9acSAndroid Build Coastguard Worker 	proxy_msg_t *msg;
239*1c60b9acSAndroid Build Coastguard Worker 	uint8_t *data;
240*1c60b9acSAndroid Build Coastguard Worker 	int m, a;
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
243*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
244*1c60b9acSAndroid Build Coastguard Worker 		lwsl_warn("%s: onward raw connection failed\n", __func__);
245*1c60b9acSAndroid Build Coastguard Worker 		pc->wsi_raw = NULL;
246*1c60b9acSAndroid Build Coastguard Worker 		break;
247*1c60b9acSAndroid Build Coastguard Worker 
248*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RAW_ADOPT:
249*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
250*1c60b9acSAndroid Build Coastguard Worker 		pc->wsi_raw = wsi;
251*1c60b9acSAndroid Build Coastguard Worker 		lws_callback_on_writable(wsi);
252*1c60b9acSAndroid Build Coastguard Worker 		break;
253*1c60b9acSAndroid Build Coastguard Worker 
254*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RAW_CLOSE:
255*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
256*1c60b9acSAndroid Build Coastguard Worker 		/*
257*1c60b9acSAndroid Build Coastguard Worker 		 * Clean up any pending messages to us that are never going
258*1c60b9acSAndroid Build Coastguard Worker 		 * to get delivered now, we are in the middle of closing
259*1c60b9acSAndroid Build Coastguard Worker 		 */
260*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_foreach_safe(&pc->pending_msg_to_raw, NULL,
261*1c60b9acSAndroid Build Coastguard Worker 				      proxy_ws_raw_msg_destroy);
262*1c60b9acSAndroid Build Coastguard Worker 
263*1c60b9acSAndroid Build Coastguard Worker 		/*
264*1c60b9acSAndroid Build Coastguard Worker 		 * Remove our pointer from the proxy_conn... we are about to
265*1c60b9acSAndroid Build Coastguard Worker 		 * be destroyed.
266*1c60b9acSAndroid Build Coastguard Worker 		 */
267*1c60b9acSAndroid Build Coastguard Worker 		pc->wsi_raw = NULL;
268*1c60b9acSAndroid Build Coastguard Worker 		lws_set_opaque_user_data(wsi, NULL);
269*1c60b9acSAndroid Build Coastguard Worker 
270*1c60b9acSAndroid Build Coastguard Worker 		if (!pc->wsi_ws) {
271*1c60b9acSAndroid Build Coastguard Worker 			/*
272*1c60b9acSAndroid Build Coastguard Worker 			 * The original ws conn is already closed... then we are
273*1c60b9acSAndroid Build Coastguard Worker 			 * the last guy still holding on to the proxy_conn...
274*1c60b9acSAndroid Build Coastguard Worker 			 * and we're going away, so let's destroy it
275*1c60b9acSAndroid Build Coastguard Worker 			 */
276*1c60b9acSAndroid Build Coastguard Worker 
277*1c60b9acSAndroid Build Coastguard Worker 			free(pc);
278*1c60b9acSAndroid Build Coastguard Worker 			break;
279*1c60b9acSAndroid Build Coastguard Worker 		}
280*1c60b9acSAndroid Build Coastguard Worker 
281*1c60b9acSAndroid Build Coastguard Worker 		/*
282*1c60b9acSAndroid Build Coastguard Worker 		 * Original ws conn still alive...
283*1c60b9acSAndroid Build Coastguard Worker 		 * does he have stuff left to deliver?
284*1c60b9acSAndroid Build Coastguard Worker 		 */
285*1c60b9acSAndroid Build Coastguard Worker 		if (pc->pending_msg_to_ws.count) {
286*1c60b9acSAndroid Build Coastguard Worker 			/*
287*1c60b9acSAndroid Build Coastguard Worker 			 * Yes, let him get on with trying to send
288*1c60b9acSAndroid Build Coastguard Worker 			 * the remaining pieces... but put a time limit
289*1c60b9acSAndroid Build Coastguard Worker 			 * on how hard he will try now the raw part is
290*1c60b9acSAndroid Build Coastguard Worker 			 * disappearing... give him 3s
291*1c60b9acSAndroid Build Coastguard Worker 			 */
292*1c60b9acSAndroid Build Coastguard Worker 			lws_set_timeout(pc->wsi_ws,
293*1c60b9acSAndroid Build Coastguard Worker 				PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE, 3);
294*1c60b9acSAndroid Build Coastguard Worker 			break;
295*1c60b9acSAndroid Build Coastguard Worker 		}
296*1c60b9acSAndroid Build Coastguard Worker 		/*
297*1c60b9acSAndroid Build Coastguard Worker 		 * Original ws client conn doesn't have anything left
298*1c60b9acSAndroid Build Coastguard Worker 		 * to do, let's close him right after this, he will take care to
299*1c60b9acSAndroid Build Coastguard Worker 		 * destroy the proxy_conn when he goes down after he sees we
300*1c60b9acSAndroid Build Coastguard Worker 		 * have already been closed
301*1c60b9acSAndroid Build Coastguard Worker 		 */
302*1c60b9acSAndroid Build Coastguard Worker 
303*1c60b9acSAndroid Build Coastguard Worker 		lws_wsi_close(pc->wsi_ws, LWS_TO_KILL_ASYNC);
304*1c60b9acSAndroid Build Coastguard Worker 		break;
305*1c60b9acSAndroid Build Coastguard Worker 
306*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RAW_RX:
307*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
308*1c60b9acSAndroid Build Coastguard Worker 		if (!pc || !pc->wsi_ws)
309*1c60b9acSAndroid Build Coastguard Worker 			break;
310*1c60b9acSAndroid Build Coastguard Worker 
311*1c60b9acSAndroid Build Coastguard Worker 		/* notice we over-allocate by LWS_PRE + rx len */
312*1c60b9acSAndroid Build Coastguard Worker 		msg = (proxy_msg_t *)malloc(sizeof(*msg) + LWS_PRE + len);
313*1c60b9acSAndroid Build Coastguard Worker 		data = (uint8_t *)&msg[1] + LWS_PRE;
314*1c60b9acSAndroid Build Coastguard Worker 
315*1c60b9acSAndroid Build Coastguard Worker 		if (!msg) {
316*1c60b9acSAndroid Build Coastguard Worker 			lwsl_user("OOM: dropping\n");
317*1c60b9acSAndroid Build Coastguard Worker 			break;
318*1c60b9acSAndroid Build Coastguard Worker 		}
319*1c60b9acSAndroid Build Coastguard Worker 
320*1c60b9acSAndroid Build Coastguard Worker 		memset(msg, 0, sizeof(*msg));
321*1c60b9acSAndroid Build Coastguard Worker 		msg->len = len;
322*1c60b9acSAndroid Build Coastguard Worker 		memcpy(data, in, len);
323*1c60b9acSAndroid Build Coastguard Worker 
324*1c60b9acSAndroid Build Coastguard Worker 		/* add us on to the list of packets to send to the onward conn */
325*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_add_tail(&msg->list, &pc->pending_msg_to_ws);
326*1c60b9acSAndroid Build Coastguard Worker 
327*1c60b9acSAndroid Build Coastguard Worker 		/* ask to send on the onward proxy client conn */
328*1c60b9acSAndroid Build Coastguard Worker 		lws_callback_on_writable(pc->wsi_ws);
329*1c60b9acSAndroid Build Coastguard Worker 		break;
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_RAW_WRITEABLE:
332*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n");
333*1c60b9acSAndroid Build Coastguard Worker 		if (!pc || !pc->pending_msg_to_raw.count)
334*1c60b9acSAndroid Build Coastguard Worker 			break;
335*1c60b9acSAndroid Build Coastguard Worker 
336*1c60b9acSAndroid Build Coastguard Worker 		msg = lws_container_of(pc->pending_msg_to_raw.head,
337*1c60b9acSAndroid Build Coastguard Worker 				       proxy_msg_t, list);
338*1c60b9acSAndroid Build Coastguard Worker 		data = (uint8_t *)&msg[1] + LWS_PRE;
339*1c60b9acSAndroid Build Coastguard Worker 
340*1c60b9acSAndroid Build Coastguard Worker 		/* notice we allowed for LWS_PRE in the payload already */
341*1c60b9acSAndroid Build Coastguard Worker 		m = lws_write(wsi, data, msg->len, LWS_WRITE_TEXT);
342*1c60b9acSAndroid Build Coastguard Worker 		a = (int)msg->len;
343*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&msg->list);
344*1c60b9acSAndroid Build Coastguard Worker 		free(msg);
345*1c60b9acSAndroid Build Coastguard Worker 
346*1c60b9acSAndroid Build Coastguard Worker 		if (m < a) {
347*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("ERROR %d writing to raw\n", m);
348*1c60b9acSAndroid Build Coastguard Worker 			return -1;
349*1c60b9acSAndroid Build Coastguard Worker 		}
350*1c60b9acSAndroid Build Coastguard Worker 
351*1c60b9acSAndroid Build Coastguard Worker 		/*
352*1c60b9acSAndroid Build Coastguard Worker 		 * If more to do...
353*1c60b9acSAndroid Build Coastguard Worker 		 */
354*1c60b9acSAndroid Build Coastguard Worker 		if (pc->pending_msg_to_raw.count)
355*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
356*1c60b9acSAndroid Build Coastguard Worker 		break;
357*1c60b9acSAndroid Build Coastguard Worker 	default:
358*1c60b9acSAndroid Build Coastguard Worker 		break;
359*1c60b9acSAndroid Build Coastguard Worker 	}
360*1c60b9acSAndroid Build Coastguard Worker 
361*1c60b9acSAndroid Build Coastguard Worker 	return 0;
362*1c60b9acSAndroid Build Coastguard Worker }
363*1c60b9acSAndroid Build Coastguard Worker 
364*1c60b9acSAndroid Build Coastguard Worker static struct lws_protocols protocols[] = {
365*1c60b9acSAndroid Build Coastguard Worker 	{ "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
366*1c60b9acSAndroid Build Coastguard Worker 	{ "lws-ws-raw-ws", callback_proxy_ws_server, 0, 1024, 0, NULL, 0 },
367*1c60b9acSAndroid Build Coastguard Worker 	{ "lws-ws-raw-raw", callback_proxy_raw_client, 0, 1024, 0, NULL, 0 },
368*1c60b9acSAndroid Build Coastguard Worker 	LWS_PROTOCOL_LIST_TERM
369*1c60b9acSAndroid Build Coastguard Worker };
370*1c60b9acSAndroid Build Coastguard Worker 
371*1c60b9acSAndroid Build Coastguard Worker static const lws_retry_bo_t retry = {
372*1c60b9acSAndroid Build Coastguard Worker 	.secs_since_valid_ping = 3,
373*1c60b9acSAndroid Build Coastguard Worker 	.secs_since_valid_hangup = 10,
374*1c60b9acSAndroid Build Coastguard Worker };
375*1c60b9acSAndroid Build Coastguard Worker 
376*1c60b9acSAndroid Build Coastguard Worker static int interrupted;
377*1c60b9acSAndroid Build Coastguard Worker 
378*1c60b9acSAndroid Build Coastguard Worker static const struct lws_http_mount mount = {
379*1c60b9acSAndroid Build Coastguard Worker 	/* .mount_next */		NULL,		/* linked-list "next" */
380*1c60b9acSAndroid Build Coastguard Worker 	/* .mountpoint */		"/",		/* mountpoint URL */
381*1c60b9acSAndroid Build Coastguard Worker 	/* .origin */			"./mount-origin",  /* serve from dir */
382*1c60b9acSAndroid Build Coastguard Worker 	/* .def */			"index.html",	/* default filename */
383*1c60b9acSAndroid Build Coastguard Worker 	/* .protocol */			NULL,
384*1c60b9acSAndroid Build Coastguard Worker 	/* .cgienv */			NULL,
385*1c60b9acSAndroid Build Coastguard Worker 	/* .extra_mimetypes */		NULL,
386*1c60b9acSAndroid Build Coastguard Worker 	/* .interpret */		NULL,
387*1c60b9acSAndroid Build Coastguard Worker 	/* .cgi_timeout */		0,
388*1c60b9acSAndroid Build Coastguard Worker 	/* .cache_max_age */		0,
389*1c60b9acSAndroid Build Coastguard Worker 	/* .auth_mask */		0,
390*1c60b9acSAndroid Build Coastguard Worker 	/* .cache_reusable */		0,
391*1c60b9acSAndroid Build Coastguard Worker 	/* .cache_revalidate */		0,
392*1c60b9acSAndroid Build Coastguard Worker 	/* .cache_intermediaries */	0,
393*1c60b9acSAndroid Build Coastguard Worker 	/* .origin_protocol */		LWSMPRO_FILE,	/* files in a dir */
394*1c60b9acSAndroid Build Coastguard Worker 	/* .mountpoint_len */		1,		/* char count */
395*1c60b9acSAndroid Build Coastguard Worker 	/* .basic_auth_login_file */	NULL,
396*1c60b9acSAndroid Build Coastguard Worker };
397*1c60b9acSAndroid Build Coastguard Worker 
sigint_handler(int sig)398*1c60b9acSAndroid Build Coastguard Worker void sigint_handler(int sig)
399*1c60b9acSAndroid Build Coastguard Worker {
400*1c60b9acSAndroid Build Coastguard Worker 	interrupted = 1;
401*1c60b9acSAndroid Build Coastguard Worker }
402*1c60b9acSAndroid Build Coastguard Worker 
main(int argc,const char ** argv)403*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
404*1c60b9acSAndroid Build Coastguard Worker {
405*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context_creation_info info;
406*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *context;
407*1c60b9acSAndroid Build Coastguard Worker 	const char *p;
408*1c60b9acSAndroid Build Coastguard Worker 	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
409*1c60b9acSAndroid Build Coastguard Worker 			/* for LLL_ verbosity above NOTICE to be built into lws,
410*1c60b9acSAndroid Build Coastguard Worker 			 * lws must have been configured and built with
411*1c60b9acSAndroid Build Coastguard Worker 			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
412*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
413*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
414*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_DEBUG */;
415*1c60b9acSAndroid Build Coastguard Worker 
416*1c60b9acSAndroid Build Coastguard Worker 	signal(SIGINT, sigint_handler);
417*1c60b9acSAndroid Build Coastguard Worker 
418*1c60b9acSAndroid Build Coastguard Worker 	if ((p = lws_cmdline_option(argc, argv, "-d")))
419*1c60b9acSAndroid Build Coastguard Worker 		logs = atoi(p);
420*1c60b9acSAndroid Build Coastguard Worker 
421*1c60b9acSAndroid Build Coastguard Worker 	lws_set_log_level(logs, NULL);
422*1c60b9acSAndroid Build Coastguard Worker 	lwsl_user("LWS minimal ws-raw proxy | visit http://localhost:7681 (-s = use TLS / https)\n");
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
425*1c60b9acSAndroid Build Coastguard Worker 	info.port = 7681;
426*1c60b9acSAndroid Build Coastguard Worker 	info.mounts = &mount;
427*1c60b9acSAndroid Build Coastguard Worker 	info.protocols = protocols;
428*1c60b9acSAndroid Build Coastguard Worker 	info.vhost_name = "localhost";
429*1c60b9acSAndroid Build Coastguard Worker 	info.options =
430*1c60b9acSAndroid Build Coastguard Worker 		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
431*1c60b9acSAndroid Build Coastguard Worker 
432*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS)
433*1c60b9acSAndroid Build Coastguard Worker 	if (lws_cmdline_option(argc, argv, "-s")) {
434*1c60b9acSAndroid Build Coastguard Worker 		lwsl_user("Server using TLS\n");
435*1c60b9acSAndroid Build Coastguard Worker 		info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
436*1c60b9acSAndroid Build Coastguard Worker 		info.ssl_cert_filepath = "localhost-100y.cert";
437*1c60b9acSAndroid Build Coastguard Worker 		info.ssl_private_key_filepath = "localhost-100y.key";
438*1c60b9acSAndroid Build Coastguard Worker 	}
439*1c60b9acSAndroid Build Coastguard Worker #endif
440*1c60b9acSAndroid Build Coastguard Worker 
441*1c60b9acSAndroid Build Coastguard Worker 	if (lws_cmdline_option(argc, argv, "-h"))
442*1c60b9acSAndroid Build Coastguard Worker 		info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
443*1c60b9acSAndroid Build Coastguard Worker 
444*1c60b9acSAndroid Build Coastguard Worker 	if (lws_cmdline_option(argc, argv, "-v"))
445*1c60b9acSAndroid Build Coastguard Worker 		info.retry_and_idle_policy = &retry;
446*1c60b9acSAndroid Build Coastguard Worker 
447*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
448*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
449*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("lws init failed\n");
450*1c60b9acSAndroid Build Coastguard Worker 		return 1;
451*1c60b9acSAndroid Build Coastguard Worker 	}
452*1c60b9acSAndroid Build Coastguard Worker 
453*1c60b9acSAndroid Build Coastguard Worker 	while (n >= 0 && !interrupted)
454*1c60b9acSAndroid Build Coastguard Worker 		n = lws_service(context, 0);
455*1c60b9acSAndroid Build Coastguard Worker 
456*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
457*1c60b9acSAndroid Build Coastguard Worker 
458*1c60b9acSAndroid Build Coastguard Worker 	return 0;
459*1c60b9acSAndroid Build Coastguard Worker }
460