• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 #include "private-lib-abstract.h"
27 
28 typedef struct lws_abstxp_raw_skt_priv {
29 	struct lws_abs *abs;
30 	struct lws *wsi;
31 
32 	lws_dll2_t same_abs_transport_list;
33 
34 	uint8_t established:1;
35 	uint8_t connecting:1;
36 } abs_raw_skt_priv_t;
37 
38 struct vhd {
39 	lws_dll2_owner_t owner;
40 };
41 
42 static int
heartbeat_cb(struct lws_dll2 * d,void * user)43 heartbeat_cb(struct lws_dll2 *d, void *user)
44 {
45 	abs_raw_skt_priv_t *priv = lws_container_of(d, abs_raw_skt_priv_t,
46 						    same_abs_transport_list);
47 
48 	if (priv->abs->ap->heartbeat)
49 		priv->abs->ap->heartbeat(priv->abs->api);
50 
51 	return 0;
52 }
53 
54 static int
callback_abs_client_raw_skt(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)55 callback_abs_client_raw_skt(struct lws *wsi, enum lws_callback_reasons reason,
56 			    void *user, void *in, size_t len)
57 {
58 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)user;
59 	struct vhd *vhd = (struct vhd *)
60 		lws_protocol_vh_priv_get(lws_get_vhost(wsi),
61 					 lws_get_protocol(wsi));
62 
63 	switch (reason) {
64 	case LWS_CALLBACK_PROTOCOL_INIT:
65 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
66 				lws_get_protocol(wsi), sizeof(struct vhd));
67 		if (!vhd)
68 			return 1;
69 		lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
70 					       lws_get_protocol(wsi),
71 					       LWS_CALLBACK_USER, 1);
72 		break;
73 
74 	case LWS_CALLBACK_USER:
75 		/*
76 		 * This comes at 1Hz without a wsi context, so there is no
77 		 * valid priv.  We need to track the live abstract objects that
78 		 * are using our abstract protocol, and pass the heartbeat
79 		 * through to the ones that care.
80 		 */
81 		if (!vhd)
82 			break;
83 
84 		lws_dll2_foreach_safe(&vhd->owner, NULL, heartbeat_cb);
85 
86 		lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
87 					       lws_get_protocol(wsi),
88 					       LWS_CALLBACK_USER, 1);
89 		break;
90 
91         case LWS_CALLBACK_RAW_CONNECTED:
92 		lwsl_debug("LWS_CALLBACK_RAW_CONNECTED\n");
93 		priv->connecting = 0;
94 		priv->established = 1;
95 		if (priv->abs->ap->accept)
96 			priv->abs->ap->accept(priv->abs->api);
97 		if (wsi->seq)
98 			/*
99 			 * we are bound to a sequencer who wants to know about
100 			 * our lifecycle events
101 			 */
102 
103 			lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONNECTED,
104 						  wsi, NULL);
105                 break;
106 
107 	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
108 		lwsl_user("CONNECTION_ERROR\n");
109 		if (in)
110 			lwsl_user("   %s\n", (const char *)in);
111 
112 		if (wsi->seq)
113 			/*
114 			 * we are bound to a sequencer who wants to know about
115 			 * our lifecycle events
116 			 */
117 
118 			lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_FAIL,
119 					    wsi, NULL);
120 
121 		goto close_path;
122 
123 		/* fallthru */
124 	case LWS_CALLBACK_RAW_CLOSE:
125 		if (!user)
126 			break;
127 
128 		if (wsi->seq)
129 			/*
130 			 * we are bound to a sequencer who wants to know about
131 			 * our lifecycle events
132 			 */
133 
134 			lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_CLOSE,
135 					    wsi, NULL);
136 
137 close_path:
138 		lwsl_debug("LWS_CALLBACK_RAW_CLOSE\n");
139 		priv->established = 0;
140 		priv->connecting = 0;
141 		if (priv->abs && priv->abs->ap->closed)
142 			priv->abs->ap->closed(priv->abs->api);
143 		lws_set_wsi_user(wsi, NULL);
144 		break;
145 
146 	case LWS_CALLBACK_RAW_RX:
147 		lwsl_debug("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
148 		return !!priv->abs->ap->rx(priv->abs->api, in, len);
149 
150 	case LWS_CALLBACK_RAW_WRITEABLE:
151 		lwsl_debug("LWS_CALLBACK_RAW_WRITEABLE\n");
152 		priv->abs->ap->writeable(priv->abs->api,
153 				lws_get_peer_write_allowance(priv->wsi));
154 		break;
155 
156 	case LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL:
157 		lws_dll2_add_tail(&priv->same_abs_transport_list, &vhd->owner);
158 		break;
159 
160 	case LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL:
161 		lws_dll2_remove(&priv->same_abs_transport_list);
162 		break;
163 
164 	default:
165 		break;
166 	}
167 
168 	return 0;
169 }
170 
171 static int
lws_atcrs_close(lws_abs_transport_inst_t * ati)172 lws_atcrs_close(lws_abs_transport_inst_t *ati)
173 {
174 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
175 	struct lws *wsi = priv->wsi;
176 
177 	if (!priv->wsi)
178 		return 0;
179 
180 	if (!lws_raw_transaction_completed(priv->wsi))
181 		return 0;
182 
183 	priv->wsi = NULL;
184 	lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
185 
186 	/* priv is destroyed in the CLOSE callback */
187 
188 	return 0;
189 }
190 
191 
192 const struct lws_protocols protocol_abs_client_raw_skt = {
193 	"lws-abs-cli-raw-skt", callback_abs_client_raw_skt,
194 	0, 1024, 1024, NULL, 0
195 };
196 
197 static int
lws_atcrs_tx(lws_abs_transport_inst_t * ati,uint8_t * buf,size_t len)198 lws_atcrs_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
199 {
200 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
201 
202 	if (!priv->wsi) {
203 		lwsl_err("%s: NULL priv->wsi\n", __func__);
204 		return 1;
205 	}
206 
207 	lwsl_debug("%s: priv %p, wsi %p, ro %p\n", __func__,
208 			priv, priv->wsi, priv->wsi->role_ops);
209 
210 	if (lws_write(priv->wsi, buf, len, LWS_WRITE_RAW) < 0)
211 		lws_atcrs_close(ati);
212 
213 	return 0;
214 }
215 
216 #if defined(LWS_WITH_CLIENT)
217 static int
lws_atcrs_client_conn(const lws_abs_t * abs)218 lws_atcrs_client_conn(const lws_abs_t *abs)
219 {
220 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)abs->ati;
221 	struct lws_client_connect_info i;
222 	const lws_token_map_t *tm;
223 
224 	if (priv->connecting)
225 		return 0;
226 
227 	if (priv->established) {
228 		lws_set_timeout(priv->wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
229 
230 		return 0;
231 	}
232 
233 	memset(&i, 0, sizeof(i));
234 
235 	/* address and port are passed-in using the abstract transport tokens */
236 
237 	tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
238 	if (!tm) {
239 		lwsl_notice("%s: raw_skt needs LTMI_PEER_V_DNS_ADDRESS\n",
240 			    __func__);
241 
242 		return 1;
243 	}
244 	i.address = tm->u.value;
245 
246 	tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_PORT);
247 	if (!tm) {
248 		lwsl_notice("%s: raw_skt needs LTMI_PEER_LV_PORT\n", __func__);
249 
250 		return 1;
251 	}
252 	i.port = tm->u.lvalue;
253 
254 	/* optional */
255 	i.ssl_connection = 0;
256 	tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
257 	if (tm)
258 		i.ssl_connection = tm->u.lvalue;
259 
260 
261 	lwsl_debug("%s: raw_skt priv %p connecting to %s:%u %p\n",
262 		   __func__, priv, i.address, i.port, abs->vh->context);
263 
264 	i.path = "";
265 	i.method = "RAW";
266 	i.vhost = abs->vh;
267 	i.userdata = priv;
268 	i.host = i.address;
269 	i.pwsi = &priv->wsi;
270 	i.origin = i.address;
271 	i.context = abs->vh->context;
272 	i.local_protocol_name = "lws-abs-cli-raw-skt";
273 	i.seq = abs->seq;
274 	i.opaque_user_data = abs->opaque_user_data;
275 
276 	/*
277 	 * the protocol itself has some natural attributes we should pass on
278 	 */
279 
280 	if (abs->ap->flags & LWS_AP_FLAG_PIPELINE_TRANSACTIONS)
281 		i.ssl_connection |= LCCSCF_PIPELINE;
282 
283 	if (abs->ap->flags & LWS_AP_FLAG_MUXABLE_STREAM)
284 		i.ssl_connection |= LCCSCF_MUXABLE_STREAM;
285 
286 	priv->wsi = lws_client_connect_via_info(&i);
287 	if (!priv->wsi)
288 		return 1;
289 
290 	priv->connecting = 1;
291 
292 	return 0;
293 }
294 #endif
295 
296 static int
lws_atcrs_ask_for_writeable(lws_abs_transport_inst_t * ati)297 lws_atcrs_ask_for_writeable(lws_abs_transport_inst_t *ati)
298 {
299 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
300 
301 	if (!priv->wsi || !priv->established)
302 		return 1;
303 
304 	lws_callback_on_writable(priv->wsi);
305 
306 	return 0;
307 }
308 
309 static int
lws_atcrs_create(struct lws_abs * ai)310 lws_atcrs_create(struct lws_abs *ai)
311 {
312 	abs_raw_skt_priv_t *at = (abs_raw_skt_priv_t *)ai->ati;
313 
314 	memset(at, 0, sizeof(*at));
315 	at->abs = ai;
316 
317 	return 0;
318 }
319 
320 static void
lws_atcrs_destroy(lws_abs_transport_inst_t ** pati)321 lws_atcrs_destroy(lws_abs_transport_inst_t **pati)
322 {
323 	/*
324 	 * For ourselves, we don't free anything because the abstract layer
325 	 * combined our allocation with that of the abs instance, and it will
326 	 * free the whole thing after this.
327 	 */
328 	*pati = NULL;
329 }
330 
331 static int
lws_atcrs_set_timeout(lws_abs_transport_inst_t * ati,int reason,int secs)332 lws_atcrs_set_timeout(lws_abs_transport_inst_t *ati, int reason, int secs)
333 {
334 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
335 
336 	lws_set_timeout(priv->wsi, reason, secs);
337 
338 	return 0;
339 }
340 
341 static int
lws_atcrs_state(lws_abs_transport_inst_t * ati)342 lws_atcrs_state(lws_abs_transport_inst_t *ati)
343 {
344 	abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
345 
346 	if (!priv || !priv->wsi || (!priv->established && !priv->connecting))
347 		return 0;
348 
349 	return 1;
350 }
351 
352 static int
lws_atcrs_compare(lws_abs_t * abs1,lws_abs_t * abs2)353 lws_atcrs_compare(lws_abs_t *abs1, lws_abs_t *abs2)
354 {
355 	const lws_token_map_t *tm1, *tm2;
356 
357 	tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
358 	tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
359 
360 	/* Address token is mandatory and must match */
361 	if (!tm1 || !tm2 || strcmp(tm1->u.value, tm2->u.value))
362 		return 1;
363 
364 	/* Port token is mandatory and must match */
365 	tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_PORT);
366 	tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_PORT);
367 	if (!tm1 || !tm2 || tm1->u.lvalue != tm2->u.lvalue)
368 		return 1;
369 
370 	/* TLS is optional... */
371 	tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
372 	tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
373 
374 	/* ... but both must have the same situation with it given or not... */
375 	if (!!tm1 != !!tm2)
376 		return 1;
377 
378 	/* if not using TLS, then that's enough to call it */
379 	if (!tm1)
380 		return 0;
381 
382 	/* ...and if there are tls flags, both must have the same tls flags */
383 	if (tm1->u.lvalue != tm2->u.lvalue)
384 		return 1;
385 
386 	/* ... and both must use the same client tls ctx / vhost */
387 	return abs1->vh != abs2->vh;
388 }
389 
390 const lws_abs_transport_t lws_abs_transport_cli_raw_skt = {
391 	.name			= "raw_skt",
392 	.alloc			= sizeof(abs_raw_skt_priv_t),
393 
394 	.create			= lws_atcrs_create,
395 	.destroy		= lws_atcrs_destroy,
396 	.compare		= lws_atcrs_compare,
397 
398 	.tx			= lws_atcrs_tx,
399 #if !defined(LWS_WITH_CLIENT)
400 	.client_conn		= NULL,
401 #else
402 	.client_conn		= lws_atcrs_client_conn,
403 #endif
404 	.close			= lws_atcrs_close,
405 	.ask_for_writeable	= lws_atcrs_ask_for_writeable,
406 	.set_timeout		= lws_atcrs_set_timeout,
407 	.state			= lws_atcrs_state,
408 };
409