• 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 
27 #if defined (_DEBUG)
lwsi_set_role(struct lws * wsi,lws_wsi_state_t role)28 void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
29 {
30 	wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role;
31 
32 	lwsl_debug("lwsi_set_role(%p, 0x%lx)\n", wsi,
33 					(unsigned long)wsi->wsistate);
34 }
35 
lwsi_set_state(struct lws * wsi,lws_wsi_state_t lrs)36 void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
37 {
38 	wsi->wsistate = (wsi->wsistate & (~LRS_MASK)) | lrs;
39 
40 	lwsl_debug("lwsi_set_state(%p, 0x%lx)\n", wsi,
41 					(unsigned long)wsi->wsistate);
42 }
43 #endif
44 
45 
46 void
lws_vhost_bind_wsi(struct lws_vhost * vh,struct lws * wsi)47 lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
48 {
49 	if (wsi->vhost == vh)
50 		return;
51 	lws_context_lock(vh->context, __func__); /* ---------- context { */
52 	wsi->vhost = vh;
53 	vh->count_bound_wsi++;
54 	lws_context_unlock(vh->context); /* } context ---------- */
55 	lwsl_debug("%s: vh %s: wsi %s/%s, count_bound_wsi %d\n", __func__,
56 		   vh->name, wsi->role_ops ? wsi->role_ops->name : "none",
57 		   wsi->protocol ? wsi->protocol->name : "none",
58 		   vh->count_bound_wsi);
59 	assert(wsi->vhost->count_bound_wsi > 0);
60 }
61 
62 void
lws_vhost_unbind_wsi(struct lws * wsi)63 lws_vhost_unbind_wsi(struct lws *wsi)
64 {
65 	if (!wsi->vhost)
66 		return;
67 
68 	lws_context_lock(wsi->context, __func__); /* ---------- context { */
69 
70 	assert(wsi->vhost->count_bound_wsi > 0);
71 	wsi->vhost->count_bound_wsi--;
72 	lwsl_debug("%s: vh %s: count_bound_wsi %d\n", __func__,
73 		   wsi->vhost->name, wsi->vhost->count_bound_wsi);
74 
75 	if (!wsi->vhost->count_bound_wsi &&
76 	    wsi->vhost->being_destroyed) {
77 		/*
78 		 * We have closed all wsi that were bound to this vhost
79 		 * by any pt: nothing can be servicing any wsi belonging
80 		 * to it any more.
81 		 *
82 		 * Finalize the vh destruction
83 		 */
84 		__lws_vhost_destroy2(wsi->vhost);
85 	}
86 	wsi->vhost = NULL;
87 
88 	lws_context_unlock(wsi->context); /* } context ---------- */
89 }
90 
91 struct lws *
lws_get_network_wsi(struct lws * wsi)92 lws_get_network_wsi(struct lws *wsi)
93 {
94 	if (!wsi)
95 		return NULL;
96 
97 #if defined(LWS_WITH_HTTP2) || defined(LWS_ROLE_MQTT)
98 	if (!wsi->mux_substream
99 #if defined(LWS_WITH_CLIENT)
100 			&& !wsi->client_mux_substream
101 #endif
102 	)
103 		return wsi;
104 
105 	while (wsi->mux.parent_wsi)
106 		wsi = wsi->mux.parent_wsi;
107 #endif
108 
109 	return wsi;
110 }
111 
112 
113 const struct lws_protocols *
lws_vhost_name_to_protocol(struct lws_vhost * vh,const char * name)114 lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
115 {
116 	int n;
117 
118 	for (n = 0; n < vh->count_protocols; n++)
119 		if (vh->protocols[n].name && !strcmp(name, vh->protocols[n].name))
120 			return &vh->protocols[n];
121 
122 	return NULL;
123 }
124 
125 int
lws_callback_all_protocol(struct lws_context * context,const struct lws_protocols * protocol,int reason)126 lws_callback_all_protocol(struct lws_context *context,
127 			  const struct lws_protocols *protocol, int reason)
128 {
129 	struct lws_context_per_thread *pt = &context->pt[0];
130 	unsigned int n, m = context->count_threads;
131 	struct lws *wsi;
132 
133 	while (m--) {
134 		for (n = 0; n < pt->fds_count; n++) {
135 			wsi = wsi_from_fd(context, pt->fds[n].fd);
136 			if (!wsi)
137 				continue;
138 			if (wsi->protocol == protocol)
139 				protocol->callback(wsi, reason, wsi->user_space,
140 						   NULL, 0);
141 		}
142 		pt++;
143 	}
144 
145 	return 0;
146 }
147 
148 int
lws_callback_all_protocol_vhost_args(struct lws_vhost * vh,const struct lws_protocols * protocol,int reason,void * argp,size_t len)149 lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
150 			  const struct lws_protocols *protocol, int reason,
151 			  void *argp, size_t len)
152 {
153 	struct lws_context *context = vh->context;
154 	struct lws_context_per_thread *pt = &context->pt[0];
155 	unsigned int n, m = context->count_threads;
156 	struct lws *wsi;
157 
158 	while (m--) {
159 		for (n = 0; n < pt->fds_count; n++) {
160 			wsi = wsi_from_fd(context, pt->fds[n].fd);
161 			if (!wsi)
162 				continue;
163 			if (wsi->vhost == vh && (wsi->protocol == protocol ||
164 						 !protocol))
165 				wsi->protocol->callback(wsi, reason,
166 						wsi->user_space, argp, len);
167 		}
168 		pt++;
169 	}
170 
171 	return 0;
172 }
173 
174 int
lws_callback_all_protocol_vhost(struct lws_vhost * vh,const struct lws_protocols * protocol,int reason)175 lws_callback_all_protocol_vhost(struct lws_vhost *vh,
176 			  const struct lws_protocols *protocol, int reason)
177 {
178 	return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
179 }
180 
181 int
lws_callback_vhost_protocols(struct lws * wsi,int reason,void * in,int len)182 lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
183 {
184 	int n;
185 
186 	for (n = 0; n < wsi->vhost->count_protocols; n++)
187 		if (wsi->vhost->protocols[n].callback(wsi, reason, NULL, in, len))
188 			return 1;
189 
190 	return 0;
191 }
192 
193 int
lws_callback_vhost_protocols_vhost(struct lws_vhost * vh,int reason,void * in,size_t len)194 lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
195 				   size_t len)
196 {
197 	int n;
198 	struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi");
199 
200 	if (!wsi)
201 		return 1;
202 
203 	wsi->context = vh->context;
204 	lws_vhost_bind_wsi(vh, wsi);
205 
206 	for (n = 0; n < wsi->vhost->count_protocols; n++) {
207 		wsi->protocol = &vh->protocols[n];
208 		if (wsi->protocol->callback(wsi, reason, NULL, in, len)) {
209 			lws_free(wsi);
210 			return 1;
211 		}
212 	}
213 
214 	lws_free(wsi);
215 
216 	return 0;
217 }
218 
219 
220 int
lws_rx_flow_control(struct lws * wsi,int _enable)221 lws_rx_flow_control(struct lws *wsi, int _enable)
222 {
223 	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
224 	int en = _enable;
225 
226 	// h2 ignores rx flow control atm
227 	if (lwsi_role_h2(wsi) || wsi->mux_substream ||
228 	    lwsi_role_h2_ENCAPSULATION(wsi))
229 		return 0; // !!!
230 
231 	lwsl_info("%s: %p 0x%x\n", __func__, wsi, _enable);
232 
233 	if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) {
234 		/*
235 		 * convert user bool style to bitmap style... in user simple
236 		 * bool style _enable = 0 = flow control it, = 1 = allow rx
237 		 */
238 		en = LWS_RXFLOW_REASON_APPLIES | LWS_RXFLOW_REASON_USER_BOOL;
239 		if (_enable & 1)
240 			en |= LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT;
241 	}
242 
243 	lws_pt_lock(pt, __func__);
244 
245 	/* any bit set in rxflow_bitmap DISABLEs rxflow control */
246 	if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT)
247 		wsi->rxflow_bitmap &= ~(en & 0xff);
248 	else
249 		wsi->rxflow_bitmap |= en & 0xff;
250 
251 	if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) ==
252 	    wsi->rxflow_change_to)
253 		goto skip;
254 
255 	wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE |
256 				(!wsi->rxflow_bitmap);
257 
258 	lwsl_info("%s: %p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi,
259 		  wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
260 
261 	if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW ||
262 	    !wsi->rxflow_will_be_applied) {
263 		en = __lws_rx_flow_control(wsi);
264 		lws_pt_unlock(pt);
265 
266 		return en;
267 	}
268 
269 skip:
270 	lws_pt_unlock(pt);
271 
272 	return 0;
273 }
274 
275 void
lws_rx_flow_allow_all_protocol(const struct lws_context * context,const struct lws_protocols * protocol)276 lws_rx_flow_allow_all_protocol(const struct lws_context *context,
277 			       const struct lws_protocols *protocol)
278 {
279 	const struct lws_context_per_thread *pt = &context->pt[0];
280 	struct lws *wsi;
281 	unsigned int n, m = context->count_threads;
282 
283 	while (m--) {
284 		for (n = 0; n < pt->fds_count; n++) {
285 			wsi = wsi_from_fd(context, pt->fds[n].fd);
286 			if (!wsi)
287 				continue;
288 			if (wsi->protocol == protocol)
289 				lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
290 		}
291 		pt++;
292 	}
293 }
294 
user_callback_handle_rxflow(lws_callback_function callback_function,struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)295 int user_callback_handle_rxflow(lws_callback_function callback_function,
296 				struct lws *wsi,
297 				enum lws_callback_reasons reason, void *user,
298 				void *in, size_t len)
299 {
300 	int n;
301 
302 	wsi->rxflow_will_be_applied = 1;
303 	n = callback_function(wsi, reason, user, in, len);
304 	wsi->rxflow_will_be_applied = 0;
305 	if (!n)
306 		n = __lws_rx_flow_control(wsi);
307 
308 	return n;
309 }
310 
311 int
__lws_rx_flow_control(struct lws * wsi)312 __lws_rx_flow_control(struct lws *wsi)
313 {
314 	struct lws *wsic = wsi->child_list;
315 
316 	// h2 ignores rx flow control atm
317 	if (lwsi_role_h2(wsi) || wsi->mux_substream ||
318 	    lwsi_role_h2_ENCAPSULATION(wsi))
319 		return 0; // !!!
320 
321 	/* if he has children, do those if they were changed */
322 	while (wsic) {
323 		if (wsic->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)
324 			__lws_rx_flow_control(wsic);
325 
326 		wsic = wsic->sibling_list;
327 	}
328 
329 	/* there is no pending change */
330 	if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
331 		return 0;
332 
333 	/* stuff is still buffered, not ready to really accept new input */
334 	if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
335 		/* get ourselves called back to deal with stashed buffer */
336 		lws_callback_on_writable(wsi);
337 		// return 0;
338 	}
339 
340 	/* now the pending is cleared, we can change rxflow state */
341 
342 	wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
343 
344 	lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
345 		  wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
346 
347 	/* adjust the pollfd for this wsi */
348 
349 	if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
350 		lwsl_info("%s: reenable POLLIN\n", __func__);
351 		// lws_buflist_describe(&wsi->buflist, NULL, __func__);
352 		if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
353 			lwsl_info("%s: fail\n", __func__);
354 			return -1;
355 		}
356 	} else
357 		if (__lws_change_pollfd(wsi, LWS_POLLIN, 0))
358 			return -1;
359 
360 	return 0;
361 }
362 
363 
364 const struct lws_protocols *
lws_get_protocol(struct lws * wsi)365 lws_get_protocol(struct lws *wsi)
366 {
367 	return wsi->protocol;
368 }
369 
370 
371 int
lws_ensure_user_space(struct lws * wsi)372 lws_ensure_user_space(struct lws *wsi)
373 {
374 	if (!wsi->protocol)
375 		return 0;
376 
377 	/* allocate the per-connection user memory (if any) */
378 
379 	if (wsi->protocol->per_session_data_size && !wsi->user_space) {
380 		wsi->user_space = lws_zalloc(
381 			    wsi->protocol->per_session_data_size, "user space");
382 		if (wsi->user_space == NULL) {
383 			lwsl_err("%s: OOM\n", __func__);
384 			return 1;
385 		}
386 	} else
387 		lwsl_debug("%s: %p protocol pss %lu, user_space=%p\n", __func__,
388 			   wsi, (long)wsi->protocol->per_session_data_size,
389 			   wsi->user_space);
390 	return 0;
391 }
392 
393 void *
lws_adjust_protocol_psds(struct lws * wsi,size_t new_size)394 lws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
395 {
396 	((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size =
397 		new_size;
398 
399 	if (lws_ensure_user_space(wsi))
400 			return NULL;
401 
402 	return wsi->user_space;
403 }
404 
405 int
lws_get_tsi(struct lws * wsi)406 lws_get_tsi(struct lws *wsi)
407 {
408         return (int)wsi->tsi;
409 }
410 
411 int
lws_is_ssl(struct lws * wsi)412 lws_is_ssl(struct lws *wsi)
413 {
414 #if defined(LWS_WITH_TLS)
415 	return wsi->tls.use_ssl & LCCSCF_USE_SSL;
416 #else
417 	(void)wsi;
418 	return 0;
419 #endif
420 }
421 
422 #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
423 lws_tls_conn*
lws_get_ssl(struct lws * wsi)424 lws_get_ssl(struct lws *wsi)
425 {
426 	return wsi->tls.ssl;
427 }
428 #endif
429 
430 int
lws_partial_buffered(struct lws * wsi)431 lws_partial_buffered(struct lws *wsi)
432 {
433 	return lws_has_buffered_out(wsi);
434 }
435 
436 lws_fileofs_t
lws_get_peer_write_allowance(struct lws * wsi)437 lws_get_peer_write_allowance(struct lws *wsi)
438 {
439 	if (!wsi->role_ops->tx_credit)
440 		return -1;
441 	return wsi->role_ops->tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
442 }
443 
444 void
lws_role_transition(struct lws * wsi,enum lwsi_role role,enum lwsi_state state,const struct lws_role_ops * ops)445 lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
446 		    const struct lws_role_ops *ops)
447 {
448 #if defined(_DEBUG)
449 	const char *name = "(unset)";
450 #endif
451 	wsi->wsistate = role | state;
452 	if (ops)
453 		wsi->role_ops = ops;
454 #if defined(_DEBUG)
455 	if (wsi->role_ops)
456 		name = wsi->role_ops->name;
457 	lwsl_debug("%s: %p: wsistate 0x%lx, ops %s\n", __func__, wsi,
458 		   (unsigned long)wsi->wsistate, name);
459 #endif
460 }
461 
462 int
lws_parse_uri(char * p,const char ** prot,const char ** ads,int * port,const char ** path)463 lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
464 	      const char **path)
465 {
466 	const char *end;
467 	char unix_skt = 0;
468 
469 	/* cut up the location into address, port and path */
470 	*prot = p;
471 	while (*p && (*p != ':' || p[1] != '/' || p[2] != '/'))
472 		p++;
473 	if (!*p) {
474 		end = p;
475 		p = (char *)*prot;
476 		*prot = end;
477 	} else {
478 		*p = '\0';
479 		p += 3;
480 	}
481 	if (*p == '+') /* unix skt */
482 		unix_skt = 1;
483 
484 	*ads = p;
485 	if (!strcmp(*prot, "http") || !strcmp(*prot, "ws"))
486 		*port = 80;
487 	else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
488 		*port = 443;
489 
490 	if (*p == '[') {
491 		++(*ads);
492 		while (*p && *p != ']')
493 			p++;
494 		if (*p)
495 			*p++ = '\0';
496 	} else
497 		while (*p && *p != ':' && (unix_skt || *p != '/'))
498 			p++;
499 
500 	if (*p == ':') {
501 		*p++ = '\0';
502 		*port = atoi(p);
503 		while (*p && *p != '/')
504 			p++;
505 	}
506 	*path = "/";
507 	if (*p) {
508 		*p++ = '\0';
509 		if (*p)
510 			*path = p;
511 	}
512 
513 	return 0;
514 }
515 
516 /* ... */
517 
518 const char *
lws_get_urlarg_by_name(struct lws * wsi,const char * name,char * buf,int len)519 lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
520 {
521 	int n = 0, sl = (int)strlen(name);
522 
523 	while (lws_hdr_copy_fragment(wsi, buf, len,
524 			  WSI_TOKEN_HTTP_URI_ARGS, n) >= 0) {
525 
526 		if (!strncmp(buf, name, sl))
527 			return buf + sl;
528 
529 		n++;
530 	}
531 
532 	return NULL;
533 }
534 
535 
536 #if defined(LWS_WITHOUT_EXTENSIONS)
537 
538 /* we need to provide dummy callbacks for internal exts
539  * so user code runs when faced with a lib compiled with
540  * extensions disabled.
541  */
542 
543 int
lws_extension_callback_pm_deflate(struct lws_context * context,const struct lws_extension * ext,struct lws * wsi,enum lws_extension_callback_reasons reason,void * user,void * in,size_t len)544 lws_extension_callback_pm_deflate(struct lws_context *context,
545                                   const struct lws_extension *ext,
546                                   struct lws *wsi,
547                                   enum lws_extension_callback_reasons reason,
548                                   void *user, void *in, size_t len)
549 {
550 	(void)context;
551 	(void)ext;
552 	(void)wsi;
553 	(void)reason;
554 	(void)user;
555 	(void)in;
556 	(void)len;
557 
558 	return 0;
559 }
560 
561 int
lws_set_extension_option(struct lws * wsi,const char * ext_name,const char * opt_name,const char * opt_val)562 lws_set_extension_option(struct lws *wsi, const char *ext_name,
563 			 const char *opt_name, const char *opt_val)
564 {
565 	return -1;
566 }
567 #endif
568 
569 int
lws_is_cgi(struct lws * wsi)570 lws_is_cgi(struct lws *wsi) {
571 #ifdef LWS_WITH_CGI
572 	return !!wsi->http.cgi;
573 #else
574 	return 0;
575 #endif
576 }
577 
578 const struct lws_protocol_vhost_options *
lws_pvo_search(const struct lws_protocol_vhost_options * pvo,const char * name)579 lws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name)
580 {
581 	while (pvo) {
582 		if (!strcmp(pvo->name, name))
583 			break;
584 
585 		pvo = pvo->next;
586 	}
587 
588 	return pvo;
589 }
590 
591 int
lws_pvo_get_str(void * in,const char * name,const char ** result)592 lws_pvo_get_str(void *in, const char *name, const char **result)
593 {
594 	const struct lws_protocol_vhost_options *pv =
595 		lws_pvo_search((const struct lws_protocol_vhost_options *)in,
596 				name);
597 
598 	if (!pv)
599 		return 1;
600 
601 	*result = (const char *)pv->value;
602 
603 	return 0;
604 }
605 
606 int
lws_broadcast(struct lws_context_per_thread * pt,int reason,void * in,size_t len)607 lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len)
608 {
609 	struct lws_vhost *v = pt->context->vhost_list;
610 	int n, ret = 0;
611 
612 	pt->fake_wsi->context = pt->context;
613 
614 	while (v) {
615 		const struct lws_protocols *p = v->protocols;
616 		pt->fake_wsi->vhost = v; /* not a real bound wsi */
617 
618 		for (n = 0; n < v->count_protocols; n++) {
619 			pt->fake_wsi->protocol = p;
620 			if (p->callback &&
621 			    p->callback(pt->fake_wsi, reason, NULL, in, len))
622 				ret |= 1;
623 			p++;
624 		}
625 		v = v->vhost_next;
626 	}
627 
628 	return ret;
629 }
630 
631 void *
lws_wsi_user(struct lws * wsi)632 lws_wsi_user(struct lws *wsi)
633 {
634 	return wsi->user_space;
635 }
636 
637 void
lws_set_wsi_user(struct lws * wsi,void * data)638 lws_set_wsi_user(struct lws *wsi, void *data)
639 {
640 	if (!wsi->user_space_externally_allocated && wsi->user_space)
641 		lws_free(wsi->user_space);
642 
643 	wsi->user_space_externally_allocated = 1;
644 	wsi->user_space = data;
645 }
646 
647 struct lws *
lws_get_parent(const struct lws * wsi)648 lws_get_parent(const struct lws *wsi)
649 {
650 	return wsi->parent;
651 }
652 
653 struct lws *
lws_get_child(const struct lws * wsi)654 lws_get_child(const struct lws *wsi)
655 {
656 	return wsi->child_list;
657 }
658 
659 void *
lws_get_opaque_parent_data(const struct lws * wsi)660 lws_get_opaque_parent_data(const struct lws *wsi)
661 {
662 	return wsi->opaque_parent_data;
663 }
664 
665 void
lws_set_opaque_parent_data(struct lws * wsi,void * data)666 lws_set_opaque_parent_data(struct lws *wsi, void *data)
667 {
668 	wsi->opaque_parent_data = data;
669 }
670 
671 void *
lws_get_opaque_user_data(const struct lws * wsi)672 lws_get_opaque_user_data(const struct lws *wsi)
673 {
674 	return wsi->opaque_user_data;
675 }
676 
677 void
lws_set_opaque_user_data(struct lws * wsi,void * data)678 lws_set_opaque_user_data(struct lws *wsi, void *data)
679 {
680 	wsi->opaque_user_data = data;
681 }
682 
683 int
lws_get_child_pending_on_writable(const struct lws * wsi)684 lws_get_child_pending_on_writable(const struct lws *wsi)
685 {
686 	return wsi->parent_pending_cb_on_writable;
687 }
688 
689 void
lws_clear_child_pending_on_writable(struct lws * wsi)690 lws_clear_child_pending_on_writable(struct lws *wsi)
691 {
692 	wsi->parent_pending_cb_on_writable = 0;
693 }
694 
695 
696 
697 const char *
lws_get_vhost_name(struct lws_vhost * vhost)698 lws_get_vhost_name(struct lws_vhost *vhost)
699 {
700 	return vhost->name;
701 }
702 
703 int
lws_get_vhost_port(struct lws_vhost * vhost)704 lws_get_vhost_port(struct lws_vhost *vhost)
705 {
706 	return vhost->listen_port;
707 }
708 
709 void *
lws_get_vhost_user(struct lws_vhost * vhost)710 lws_get_vhost_user(struct lws_vhost *vhost)
711 {
712 	return vhost->user;
713 }
714 
715 const char *
lws_get_vhost_iface(struct lws_vhost * vhost)716 lws_get_vhost_iface(struct lws_vhost *vhost)
717 {
718 	return vhost->iface;
719 }
720 
721 lws_sockfd_type
lws_get_socket_fd(struct lws * wsi)722 lws_get_socket_fd(struct lws *wsi)
723 {
724 	if (!wsi)
725 		return -1;
726 	return wsi->desc.sockfd;
727 }
728 
729 
730 struct lws_vhost *
lws_vhost_get(struct lws * wsi)731 lws_vhost_get(struct lws *wsi)
732 {
733 	return wsi->vhost;
734 }
735 
736 struct lws_vhost *
lws_get_vhost(struct lws * wsi)737 lws_get_vhost(struct lws *wsi)
738 {
739 	return wsi->vhost;
740 }
741 
742 const struct lws_protocols *
lws_protocol_get(struct lws * wsi)743 lws_protocol_get(struct lws *wsi)
744 {
745 	return wsi->protocol;
746 }
747 
748 #if defined(LWS_WITH_UDP)
749 const struct lws_udp *
lws_get_udp(const struct lws * wsi)750 lws_get_udp(const struct lws *wsi)
751 {
752 	return wsi->udp;
753 }
754 #endif
755 
756 struct lws_context *
lws_get_context(const struct lws * wsi)757 lws_get_context(const struct lws *wsi)
758 {
759 	return wsi->context;
760 }
761 
762 #if defined(LWS_WITH_CLIENT)
763 int
_lws_generic_transaction_completed_active_conn(struct lws ** _wsi)764 _lws_generic_transaction_completed_active_conn(struct lws **_wsi)
765 {
766 	struct lws *wnew, *wsi = *_wsi;
767 
768 	/*
769 	 * Are we constitutionally capable of having a queue, ie, we are on
770 	 * the "active client connections" list?
771 	 *
772 	 * If not, that's it for us.
773 	 */
774 
775 	if (lws_dll2_is_detached(&wsi->dll_cli_active_conns))
776 		return 0; /* no new transaction */
777 
778 	/*
779 	 * With h1 queuing, the original "active client" moves his attributes
780 	 * like fd, ssl, queue and active client list entry to the next guy in
781 	 * the queue before closing... it's because the user code knows the
782 	 * individual wsi and the action must take place in the correct wsi
783 	 * context.  Note this means we don't truly pipeline headers.
784 	 *
785 	 * Trying to keep the original "active client" in place to do the work
786 	 * of the wsi breaks down when dealing with queued POSTs otherwise; it's
787 	 * also competing with the real mux child arrangements and complicating
788 	 * the code.
789 	 *
790 	 * For that reason, see if we have any queued child now...
791 	 */
792 
793 	if (!wsi->dll2_cli_txn_queue_owner.head) {
794 		/*
795 		 * Nothing pipelined... we should hang around a bit
796 		 * in case something turns up... otherwise we'll close
797 		 */
798 		lwsl_info("%s: nothing pipelined waiting\n", __func__);
799 		lwsi_set_state(wsi, LRS_IDLING);
800 
801 		lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
802 
803 		return 0; /* no new transaction right now */
804 	}
805 
806 	/*
807 	 * We have a queued child wsi we should bequeath our assets to, before
808 	 * closing ourself
809 	 */
810 
811 	lws_vhost_lock(wsi->vhost);
812 
813 	wnew = lws_container_of(wsi->dll2_cli_txn_queue_owner.head, struct lws,
814 				dll2_cli_txn_queue);
815 
816 	assert(wsi != wnew);
817 
818 	lws_dll2_remove(&wnew->dll2_cli_txn_queue);
819 
820 	assert(lws_socket_is_valid(wsi->desc.sockfd));
821 
822 	/* copy the fd */
823 	wnew->desc = wsi->desc;
824 
825 	assert(lws_socket_is_valid(wnew->desc.sockfd));
826 
827 	/* disconnect the fd from association with old wsi */
828 
829 	if (__remove_wsi_socket_from_fds(wsi))
830 		return -1;
831 	wsi->desc.sockfd = LWS_SOCK_INVALID;
832 
833 	/* point the fd table entry to new guy */
834 
835 	assert(lws_socket_is_valid(wnew->desc.sockfd));
836 
837 	if (__insert_wsi_socket_into_fds(wsi->context, wnew))
838 		return -1;
839 
840 #if defined(LWS_WITH_TLS)
841 	/* pass on the tls */
842 
843 	wnew->tls = wsi->tls;
844 	wsi->tls.client_bio = NULL;
845 	wsi->tls.ssl = NULL;
846 	wsi->tls.use_ssl = 0;
847 #endif
848 
849 	/* take over his copy of his endpoint as an active connection */
850 
851 	wnew->cli_hostname_copy = wsi->cli_hostname_copy;
852 	wsi->cli_hostname_copy = NULL;
853 
854 
855 	/*
856 	 * selected queued guy now replaces the original leader on the
857 	 * active client conn list
858 	 */
859 
860 	lws_dll2_remove(&wsi->dll_cli_active_conns);
861 	lws_dll2_add_tail(&wnew->dll_cli_active_conns,
862 			  &wsi->vhost->dll_cli_active_conns_owner);
863 
864 	/* move any queued guys to queue on new active conn */
865 
866 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
867 				   wsi->dll2_cli_txn_queue_owner.head) {
868 		struct lws *ww = lws_container_of(d, struct lws,
869 					  dll2_cli_txn_queue);
870 
871 		lws_dll2_remove(&ww->dll2_cli_txn_queue);
872 		lws_dll2_add_tail(&ww->dll2_cli_txn_queue,
873 				  &wnew->dll2_cli_txn_queue_owner);
874 
875 	} lws_end_foreach_dll_safe(d, d1);
876 
877 	lws_vhost_unlock(wsi->vhost);
878 
879 	/*
880 	 * The original leader who passed on all his powers already can die...
881 	 * in the call stack above us there are guys who still want to touch
882 	 * him, so have him die next time around the event loop, not now.
883 	 */
884 
885 	wsi->already_did_cce = 1; /* so the close doesn't trigger a CCE */
886 	lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
887 
888 	/* after the first one, they can only be coming from the queue */
889 	wnew->transaction_from_pipeline_queue = 1;
890 
891 	lwsl_notice("%s: pipeline queue passed wsi %p on to queued wsi %p\n",
892 			__func__, wsi, wnew);
893 
894 	*_wsi = wnew; /* inform caller we swapped */
895 
896 	return 1; /* new transaction */
897 }
898 #endif
899 
900 int LWS_WARN_UNUSED_RESULT
lws_raw_transaction_completed(struct lws * wsi)901 lws_raw_transaction_completed(struct lws *wsi)
902 {
903 	if (lws_has_buffered_out(wsi)) {
904 		/*
905 		 * ...so he tried to send something large, but it went out
906 		 * as a partial, but he immediately called us to say he wants
907 		 * to close the connection.
908 		 *
909 		 * Defer the close until the last part of the partial is sent.
910 		 *
911 		 */
912 		lwsl_debug("%s: %p: deferring due to partial\n", __func__, wsi);
913 		wsi->close_when_buffered_out_drained = 1;
914 		lws_callback_on_writable(wsi);
915 
916 		return 0;
917 	}
918 
919 	return -1;
920 }
921 
922 int
lws_bind_protocol(struct lws * wsi,const struct lws_protocols * p,const char * reason)923 lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
924 		  const char *reason)
925 {
926 //	if (wsi->protocol == p)
927 //		return 0;
928 	const struct lws_protocols *vp = wsi->vhost->protocols, *vpo;
929 
930 	if (wsi->protocol && wsi->protocol_bind_balance) {
931 		wsi->protocol->callback(wsi,
932 		       wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)],
933 					wsi->user_space, (void *)reason, 0);
934 		wsi->protocol_bind_balance = 0;
935 	}
936 	if (!wsi->user_space_externally_allocated)
937 		lws_free_set_NULL(wsi->user_space);
938 
939 	lws_same_vh_protocol_remove(wsi);
940 
941 	wsi->protocol = p;
942 	if (!p)
943 		return 0;
944 
945 	if (lws_ensure_user_space(wsi))
946 		return 1;
947 
948 	if (p > vp && p < &vp[wsi->vhost->count_protocols])
949 		lws_same_vh_protocol_insert(wsi, (int)(p - vp));
950 	else {
951 		int n = wsi->vhost->count_protocols;
952 		int hit = 0;
953 
954 		vpo = vp;
955 
956 		while (n--) {
957 			if (p->name && vp->name && !strcmp(p->name, vp->name)) {
958 				hit = 1;
959 				lws_same_vh_protocol_insert(wsi, (int)(vp - vpo));
960 				break;
961 			}
962 			vp++;
963 		}
964 		if (!hit)
965 			lwsl_err("%s: %p is not in vhost '%s' protocols list\n",
966 				 __func__, p, wsi->vhost->name);
967 	}
968 
969 	if (wsi->protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
970 				    !!lwsi_role_server(wsi)],
971 				    wsi->user_space, NULL, 0))
972 		return 1;
973 
974 	wsi->protocol_bind_balance = 1;
975 
976 	return 0;
977 }
978 
979 void
lws_http_close_immortal(struct lws * wsi)980 lws_http_close_immortal(struct lws *wsi)
981 {
982 	struct lws *nwsi;
983 
984 	if (!wsi->mux_substream)
985 		return;
986 
987 	assert(wsi->mux_stream_immortal);
988 	wsi->mux_stream_immortal = 0;
989 
990 	nwsi = lws_get_network_wsi(wsi);
991 	lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi,
992 				     nwsi->immortal_substream_count);
993 	assert(nwsi->immortal_substream_count);
994 	nwsi->immortal_substream_count--;
995 	if (!nwsi->immortal_substream_count)
996 		/*
997 		 * since we closed the only immortal stream on this nwsi, we
998 		 * need to reapply a normal timeout regime to the nwsi
999 		 */
1000 		lws_set_timeout(nwsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
1001 				wsi->vhost->keepalive_timeout ?
1002 				    wsi->vhost->keepalive_timeout : 31);
1003 }
1004 
1005 void
lws_mux_mark_immortal(struct lws * wsi)1006 lws_mux_mark_immortal(struct lws *wsi)
1007 {
1008 	struct lws *nwsi;
1009 
1010 	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
1011 
1012 	if (!wsi->mux_substream
1013 #if defined(LWS_WITH_CLIENT)
1014 			&& !wsi->client_mux_substream
1015 #endif
1016 	) {
1017 		lwsl_err("%s: not h2 substream\n", __func__);
1018 		return;
1019 	}
1020 
1021 	nwsi = lws_get_network_wsi(wsi);
1022 
1023 	lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi,
1024 				     nwsi->immortal_substream_count);
1025 
1026 	wsi->mux_stream_immortal = 1;
1027 	assert(nwsi->immortal_substream_count < 255); /* largest count */
1028 	nwsi->immortal_substream_count++;
1029 	if (nwsi->immortal_substream_count == 1)
1030 		lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
1031 }
1032 
1033 
1034 int
lws_http_mark_sse(struct lws * wsi)1035 lws_http_mark_sse(struct lws *wsi)
1036 {
1037 	lws_http_headers_detach(wsi);
1038 	lws_mux_mark_immortal(wsi);
1039 
1040 	if (wsi->mux_substream)
1041 		wsi->h2_stream_carries_sse = 1;
1042 
1043 	return 0;
1044 }
1045 
1046 #if defined(LWS_WITH_CLIENT)
1047 
1048 const char *
lws_wsi_client_stash_item(struct lws * wsi,int stash_idx,int hdr_idx)1049 lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx)
1050 {
1051 	/* try the generic client stash */
1052 	if (wsi->stash)
1053 		return wsi->stash->cis[stash_idx];
1054 
1055 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
1056 	/* if not, use the ah stash if applicable */
1057 	return lws_hdr_simple_ptr(wsi, hdr_idx);
1058 #else
1059 	return NULL;
1060 #endif
1061 }
1062 #endif
1063 
1064 #if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
1065 
1066 void
lws_wsi_mux_insert(struct lws * wsi,struct lws * parent_wsi,int sid)1067 lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, int sid)
1068 {
1069 	wsi->mux.my_sid = sid;
1070 	wsi->mux.parent_wsi = parent_wsi;
1071 	wsi->role_ops = parent_wsi->role_ops;
1072 
1073 	/* new guy's sibling is whoever was the first child before */
1074 	wsi->mux.sibling_list = parent_wsi->mux.child_list;
1075 
1076 	/* first child is now the new guy */
1077 	parent_wsi->mux.child_list = wsi;
1078 
1079 	parent_wsi->mux.child_count++;
1080 }
1081 
1082 struct lws *
lws_wsi_mux_from_id(struct lws * parent_wsi,unsigned int sid)1083 lws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid)
1084 {
1085 	lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) {
1086 		if (wsi->mux.my_sid == sid)
1087 			return wsi;
1088 	} lws_end_foreach_ll(wsi, mux.sibling_list);
1089 
1090 	return NULL;
1091 }
1092 
1093 void
lws_wsi_mux_dump_children(struct lws * wsi)1094 lws_wsi_mux_dump_children(struct lws *wsi)
1095 {
1096 #if defined(_DEBUG)
1097 	if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO))
1098 		return;
1099 
1100 	lws_start_foreach_llp(struct lws **, w,
1101 			      wsi->mux.parent_wsi->mux.child_list) {
1102 		lwsl_info("   \\---- child %s %p\n",
1103 			  (*w)->role_ops ? (*w)->role_ops->name : "?", *w);
1104 		assert(*w != (*w)->mux.sibling_list);
1105 	} lws_end_foreach_llp(w, mux.sibling_list);
1106 #endif
1107 }
1108 
1109 void
lws_wsi_mux_close_children(struct lws * wsi,int reason)1110 lws_wsi_mux_close_children(struct lws *wsi, int reason)
1111 {
1112 	struct lws *wsi2;
1113 
1114 	if (!wsi->mux.child_list)
1115 		return;
1116 
1117 	lws_start_foreach_llp(struct lws **, w, wsi->mux.child_list) {
1118 		lwsl_info("   closing child %p\n", *w);
1119 		/* disconnect from siblings */
1120 		wsi2 = (*w)->mux.sibling_list;
1121 		assert (wsi2 != *w);
1122 		(*w)->mux.sibling_list = NULL;
1123 		(*w)->socket_is_permanently_unusable = 1;
1124 		__lws_close_free_wsi(*w, reason, "mux child recurse");
1125 		*w = wsi2;
1126 		continue;
1127 	} lws_end_foreach_llp(w, mux.sibling_list);
1128 }
1129 
1130 
1131 void
lws_wsi_mux_sibling_disconnect(struct lws * wsi)1132 lws_wsi_mux_sibling_disconnect(struct lws *wsi)
1133 {
1134 	struct lws *wsi2;
1135 
1136 	lws_start_foreach_llp(struct lws **, w,
1137 			      wsi->mux.parent_wsi->mux.child_list) {
1138 
1139 		/* disconnect from siblings */
1140 		if (*w == wsi) {
1141 			wsi2 = (*w)->mux.sibling_list;
1142 			(*w)->mux.sibling_list = NULL;
1143 			*w = wsi2;
1144 			lwsl_debug("  %p disentangled from sibling %p\n",
1145 				  wsi, wsi2);
1146 			break;
1147 		}
1148 	} lws_end_foreach_llp(w, mux.sibling_list);
1149 	wsi->mux.parent_wsi->mux.child_count--;
1150 
1151 	wsi->mux.parent_wsi = NULL;
1152 }
1153 
1154 void
lws_wsi_mux_dump_waiting_children(struct lws * wsi)1155 lws_wsi_mux_dump_waiting_children(struct lws *wsi)
1156 {
1157 #if defined(_DEBUG)
1158 	lwsl_info("%s: %p: children waiting for POLLOUT service:\n",
1159 		  __func__, wsi);
1160 
1161 	wsi = wsi->mux.child_list;
1162 	while (wsi) {
1163 		lwsl_info("  %c %p: sid %u: 0x%x %s %s\n",
1164 			  wsi->mux.requested_POLLOUT ? '*' : ' ',
1165 			  wsi, wsi->mux.my_sid, lwsi_state(wsi),
1166 			  wsi->role_ops->name,
1167 			  wsi->protocol ? wsi->protocol->name : "noprotocol");
1168 
1169 		wsi = wsi->mux.sibling_list;
1170 	}
1171 #endif
1172 }
1173 
1174 int
lws_wsi_mux_mark_parents_needing_writeable(struct lws * wsi)1175 lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi)
1176 {
1177 	struct lws /* *network_wsi = lws_get_network_wsi(wsi), */ *wsi2;
1178 	//int already = network_wsi->mux.requested_POLLOUT;
1179 
1180 	/* mark everybody above him as requesting pollout */
1181 
1182 	wsi2 = wsi;
1183 	while (wsi2) {
1184 		wsi2->mux.requested_POLLOUT = 1;
1185 		lwsl_info("%s: mark %p (sid %u) pending writable\n", __func__,
1186 				wsi2, wsi2->mux.my_sid);
1187 		wsi2 = wsi2->mux.parent_wsi;
1188 	}
1189 
1190 	return 0; // already;
1191 }
1192 
1193 struct lws *
lws_wsi_mux_move_child_to_tail(struct lws ** wsi2)1194 lws_wsi_mux_move_child_to_tail(struct lws **wsi2)
1195 {
1196 	struct lws *w = *wsi2;
1197 
1198 	while (w) {
1199 		if (!w->mux.sibling_list) { /* w is the current last */
1200 			lwsl_debug("w=%p, *wsi2 = %p\n", w, *wsi2);
1201 
1202 			if (w == *wsi2) /* we are already last */
1203 				break;
1204 
1205 			/* last points to us as new last */
1206 			w->mux.sibling_list = *wsi2;
1207 
1208 			/* guy pointing to us until now points to
1209 			 * our old next */
1210 			*wsi2 = (*wsi2)->mux.sibling_list;
1211 
1212 			/* we point to nothing because we are last */
1213 			w->mux.sibling_list->mux.sibling_list = NULL;
1214 
1215 			/* w becomes us */
1216 			w = w->mux.sibling_list;
1217 			break;
1218 		}
1219 		w = w->mux.sibling_list;
1220 	}
1221 
1222 	/* clear the waiting for POLLOUT on the guy that was chosen */
1223 
1224 	if (w)
1225 		w->mux.requested_POLLOUT = 0;
1226 
1227 	return w;
1228 }
1229 
1230 int
lws_wsi_mux_action_pending_writeable_reqs(struct lws * wsi)1231 lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi)
1232 {
1233 	struct lws *w = wsi->mux.child_list;
1234 
1235 	while (w) {
1236 		if (w->mux.requested_POLLOUT) {
1237 			if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
1238 				return -1;
1239 			return 0;
1240 		}
1241 		w = w->mux.sibling_list;
1242 	}
1243 
1244 	if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
1245 		return -1;
1246 
1247 	return 0;
1248 }
1249 
1250 int
lws_wsi_txc_check_skint(struct lws_tx_credit * txc,int32_t tx_cr)1251 lws_wsi_txc_check_skint(struct lws_tx_credit *txc, int32_t tx_cr)
1252 {
1253 	if (txc->tx_cr <= 0) {
1254 		/*
1255 		 * If other side is not able to cope with us sending any DATA
1256 		 * so no matter if we have POLLOUT on our side if it's DATA we
1257 		 * want to send.
1258 		 */
1259 
1260 		if (!txc->skint)
1261 			lwsl_info("%s: %p: skint (%d)\n", __func__, txc,
1262 				  (int)txc->tx_cr);
1263 
1264 		txc->skint = 1;
1265 
1266 		return 1;
1267 	}
1268 
1269 	if (txc->skint)
1270 		lwsl_info("%s: %p: unskint (%d)\n", __func__, txc,
1271 			  (int)txc->tx_cr);
1272 
1273 	txc->skint = 0;
1274 
1275 	return 0;
1276 }
1277 
1278 #if defined(_DEBUG)
1279 void
lws_wsi_txc_describe(struct lws_tx_credit * txc,const char * at,uint32_t sid)1280 lws_wsi_txc_describe(struct lws_tx_credit *txc, const char *at, uint32_t sid)
1281 {
1282 	lwsl_info("%s: %p: %s: sid %d: %speer-to-us: %d, us-to-peer: %d\n",
1283 		  __func__, txc, at, (int)sid, txc->skint ? "SKINT, " : "",
1284 		  (int)txc->peer_tx_cr_est, (int)txc->tx_cr);
1285 }
1286 #endif
1287 
1288 int
lws_wsi_tx_credit(struct lws * wsi,char peer_to_us,int add)1289 lws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add)
1290 {
1291 	if (wsi->role_ops && wsi->role_ops->tx_credit)
1292 		return wsi->role_ops->tx_credit(wsi, peer_to_us, add);
1293 
1294 	return 0;
1295 }
1296 
1297 /*
1298  * Let the protocol know about incoming tx credit window updates if it's
1299  * managing the flow control manually (it may want to proxy this information)
1300  */
1301 
1302 int
lws_wsi_txc_report_manual_txcr_in(struct lws * wsi,int32_t bump)1303 lws_wsi_txc_report_manual_txcr_in(struct lws *wsi, int32_t bump)
1304 {
1305 	if (!wsi->txc.manual)
1306 		/*
1307 		 * If we don't care about managing it manually, no need to
1308 		 * report it
1309 		 */
1310 		return 0;
1311 
1312 	return user_callback_handle_rxflow(wsi->protocol->callback,
1313 					   wsi, LWS_CALLBACK_WSI_TX_CREDIT_GET,
1314 					   wsi->user_space, NULL, (size_t)bump);
1315 }
1316 
1317 #if defined(LWS_WITH_CLIENT)
1318 
1319 int
lws_wsi_mux_apply_queue(struct lws * wsi)1320 lws_wsi_mux_apply_queue(struct lws *wsi)
1321 {
1322 	/* we have a transaction queue that wants to pipeline */
1323 
1324 	lws_vhost_lock(wsi->vhost);
1325 
1326 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1327 				   wsi->dll2_cli_txn_queue_owner.head) {
1328 		struct lws *w = lws_container_of(d, struct lws,
1329 						 dll2_cli_txn_queue);
1330 
1331 #if defined(LWS_ROLE_H2)
1332 		if (lwsi_role_http(wsi) &&
1333 		    lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
1334 			lwsl_info("%s: cli pipeq %p to be h2\n", __func__, w);
1335 
1336 			lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
1337 
1338 			/* remove ourselves from client queue */
1339 			lws_dll2_remove(&w->dll2_cli_txn_queue);
1340 
1341 			/* attach ourselves as an h2 stream */
1342 			lws_wsi_h2_adopt(wsi, w);
1343 		}
1344 #endif
1345 
1346 #if defined(LWS_ROLE_MQTT)
1347 		if (lwsi_role_mqtt(wsi) &&
1348 		    lwsi_state(wsi) == LRS_ESTABLISHED) {
1349 			lwsl_info("%s: cli pipeq %p to be mqtt\n", __func__, w);
1350 
1351 			/* remove ourselves from client queue */
1352 			lws_dll2_remove(&w->dll2_cli_txn_queue);
1353 
1354 			/* attach ourselves as an h2 stream */
1355 			lws_wsi_mqtt_adopt(wsi, w);
1356 		}
1357 #endif
1358 
1359 	} lws_end_foreach_dll_safe(d, d1);
1360 
1361 	lws_vhost_unlock(wsi->vhost);
1362 
1363 	return 0;
1364 }
1365 
1366 #endif
1367 
1368 #endif
1369