1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include <private-lib-core.h>
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci/*
28d4afb5ceSopenharmony_ci * These are the standardized defaults.
29d4afb5ceSopenharmony_ci * Override what actually goes in the vhost settings in platform or user code.
30d4afb5ceSopenharmony_ci * Leave these alone because they are used to determine "what is different
31d4afb5ceSopenharmony_ci * from the protocol defaults".
32d4afb5ceSopenharmony_ci */
33d4afb5ceSopenharmony_ciconst struct http2_settings lws_h2_defaults = { {
34d4afb5ceSopenharmony_ci	1,
35d4afb5ceSopenharmony_ci	/* H2SET_HEADER_TABLE_SIZE */			4096,
36d4afb5ceSopenharmony_ci	/* *** This controls how many entries in the dynamic table ***
37d4afb5ceSopenharmony_ci	 * Allows the sender to inform the remote endpoint of the maximum
38d4afb5ceSopenharmony_ci	 * size of the header compression table used to decode header
39d4afb5ceSopenharmony_ci	 * blocks, in octets.  The encoder can select any size equal to or
40d4afb5ceSopenharmony_ci	 * less than this value by using signaling specific to the header
41d4afb5ceSopenharmony_ci	 * compression format inside a header block (see [COMPRESSION]).
42d4afb5ceSopenharmony_ci	 * The initial value is 4,096 octets.
43d4afb5ceSopenharmony_ci	 */
44d4afb5ceSopenharmony_ci	/* H2SET_ENABLE_PUSH */				   1,
45d4afb5ceSopenharmony_ci	/* H2SET_MAX_CONCURRENT_STREAMS */	  0x7fffffff,
46d4afb5ceSopenharmony_ci	/* H2SET_INITIAL_WINDOW_SIZE */		       65535,
47d4afb5ceSopenharmony_ci	/* H2SET_MAX_FRAME_SIZE */		       16384,
48d4afb5ceSopenharmony_ci	/* H2SET_MAX_HEADER_LIST_SIZE */	  0x7fffffff,
49d4afb5ceSopenharmony_ci	/*< This advisory setting informs a peer of the maximum size of
50d4afb5ceSopenharmony_ci	 * header list that the sender is prepared to accept, in octets.
51d4afb5ceSopenharmony_ci	 * The value is based on the uncompressed size of header fields,
52d4afb5ceSopenharmony_ci	 * including the length of the name and value in octets plus an
53d4afb5ceSopenharmony_ci	 * overhead of 32 octets for each header field.
54d4afb5ceSopenharmony_ci	 */
55d4afb5ceSopenharmony_ci	/* H2SET_RESERVED7 */				   0,
56d4afb5ceSopenharmony_ci	/* H2SET_ENABLE_CONNECT_PROTOCOL */		   0,
57d4afb5ceSopenharmony_ci}};
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_ci/* these are the "lws defaults"... they can be overridden in plat */
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_ciconst struct http2_settings lws_h2_stock_settings = { {
62d4afb5ceSopenharmony_ci	1,
63d4afb5ceSopenharmony_ci	/* H2SET_HEADER_TABLE_SIZE */			65536, /* ffox */
64d4afb5ceSopenharmony_ci	/* *** This controls how many entries in the dynamic table ***
65d4afb5ceSopenharmony_ci	 * Allows the sender to inform the remote endpoint of the maximum
66d4afb5ceSopenharmony_ci	 * size of the header compression table used to decode header
67d4afb5ceSopenharmony_ci	 * blocks, in octets.  The encoder can select any size equal to or
68d4afb5ceSopenharmony_ci	 * less than this value by using signaling specific to the header
69d4afb5ceSopenharmony_ci	 * compression format inside a header block (see [COMPRESSION]).
70d4afb5ceSopenharmony_ci	 * The initial value is 4,096 octets.
71d4afb5ceSopenharmony_ci	 *
72d4afb5ceSopenharmony_ci	 * Can't pass h2spec with less than 4096 here...
73d4afb5ceSopenharmony_ci	 */
74d4afb5ceSopenharmony_ci	/* H2SET_ENABLE_PUSH */				   0,
75d4afb5ceSopenharmony_ci	/* H2SET_MAX_CONCURRENT_STREAMS */		  24,
76d4afb5ceSopenharmony_ci	/* H2SET_INITIAL_WINDOW_SIZE */		           0,
77d4afb5ceSopenharmony_ci	/*< This is managed by explicit WINDOW_UPDATE.  Because otherwise no
78d4afb5ceSopenharmony_ci	 * way to precisely control it when we do want to.
79d4afb5ceSopenharmony_ci	 */
80d4afb5ceSopenharmony_ci	/* H2SET_MAX_FRAME_SIZE */		       16384,
81d4afb5ceSopenharmony_ci	/* H2SET_MAX_HEADER_LIST_SIZE */	        4096,
82d4afb5ceSopenharmony_ci	/*< This advisory setting informs a peer of the maximum size of
83d4afb5ceSopenharmony_ci	 * header list that the sender is prepared to accept, in octets.
84d4afb5ceSopenharmony_ci	 * The value is based on the uncompressed size of header fields,
85d4afb5ceSopenharmony_ci	 * including the length of the name and value in octets plus an
86d4afb5ceSopenharmony_ci	 * overhead of 32 octets for each header field.
87d4afb5ceSopenharmony_ci	 */
88d4afb5ceSopenharmony_ci	/* H2SET_RESERVED7 */				   0,
89d4afb5ceSopenharmony_ci	/* H2SET_ENABLE_CONNECT_PROTOCOL */		   1,
90d4afb5ceSopenharmony_ci}};
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci/*
93d4afb5ceSopenharmony_ci * The wsi at this level is normally the network wsi... we can get called on
94d4afb5ceSopenharmony_ci * another path via lws_service_do_ripe_rxflow() on mux children too tho...
95d4afb5ceSopenharmony_ci */
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_cistatic int
98d4afb5ceSopenharmony_cirops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
99d4afb5ceSopenharmony_ci		       struct lws_pollfd *pollfd)
100d4afb5ceSopenharmony_ci{
101d4afb5ceSopenharmony_ci	struct lws_tokens ebuf;
102d4afb5ceSopenharmony_ci	unsigned int pending = 0;
103d4afb5ceSopenharmony_ci	char buffered = 0;
104d4afb5ceSopenharmony_ci	struct lws *wsi1;
105d4afb5ceSopenharmony_ci	int n, m;
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI
108d4afb5ceSopenharmony_ci	if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) {
109d4afb5ceSopenharmony_ci		if (lws_handle_POLLOUT_event(wsi, pollfd))
110d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		return LWS_HPI_RET_HANDLED;
113d4afb5ceSopenharmony_ci	}
114d4afb5ceSopenharmony_ci#endif
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci	 lwsl_info("%s: %s wsistate 0x%x, events %d, revents %d, pollout %d\n", __func__,
117d4afb5ceSopenharmony_ci		   wsi->lc.gutag, (unsigned int)wsi->wsistate,
118d4afb5ceSopenharmony_ci		   pollfd->events, pollfd->revents,
119d4afb5ceSopenharmony_ci		   pollfd->revents & LWS_POLLOUT);
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	 /* !!! */
122d4afb5ceSopenharmony_ci	 if (wsi->wsistate == 0x10000013) {
123d4afb5ceSopenharmony_ci		 wsi->bugcatcher++;
124d4afb5ceSopenharmony_ci		 if (wsi->bugcatcher == 250) {
125d4afb5ceSopenharmony_ci			 lwsl_err("%s: BUGCATCHER\n", __func__);
126d4afb5ceSopenharmony_ci			 return LWS_HPI_RET_PLEASE_CLOSE_ME;
127d4afb5ceSopenharmony_ci		 }
128d4afb5ceSopenharmony_ci	 } else
129d4afb5ceSopenharmony_ci		 wsi->bugcatcher = 0;
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ci	/*
132d4afb5ceSopenharmony_ci	 * something went wrong with parsing the handshake, and
133d4afb5ceSopenharmony_ci	 * we ended up back in the event loop without completing it
134d4afb5ceSopenharmony_ci	 */
135d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) == LRS_PRE_WS_SERVING_ACCEPT) {
136d4afb5ceSopenharmony_ci		wsi->socket_is_permanently_unusable = 1;
137d4afb5ceSopenharmony_ci		return LWS_HPI_RET_PLEASE_CLOSE_ME;
138d4afb5ceSopenharmony_ci	}
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
141d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
142d4afb5ceSopenharmony_ci		if ((pollfd->revents & LWS_POLLOUT) &&
143d4afb5ceSopenharmony_ci		    lws_handle_POLLOUT_event(wsi, pollfd)) {
144d4afb5ceSopenharmony_ci			lwsl_debug("POLLOUT event closed it\n");
145d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
146d4afb5ceSopenharmony_ci		}
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci		n = lws_http_client_socket_service(wsi, pollfd);
149d4afb5ceSopenharmony_ci		if (n)
150d4afb5ceSopenharmony_ci			return LWS_HPI_RET_WSI_ALREADY_DIED;
151d4afb5ceSopenharmony_ci#endif
152d4afb5ceSopenharmony_ci		return LWS_HPI_RET_HANDLED;
153d4afb5ceSopenharmony_ci	}
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci	/* 1: something requested a callback when it was OK to write */
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	if ((pollfd->revents & LWS_POLLOUT) &&
158d4afb5ceSopenharmony_ci	    lwsi_state_can_handle_POLLOUT(wsi) &&
159d4afb5ceSopenharmony_ci	    lws_handle_POLLOUT_event(wsi, pollfd)) {
160d4afb5ceSopenharmony_ci		if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
161d4afb5ceSopenharmony_ci			lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
162d4afb5ceSopenharmony_ci		/* the write failed... it's had it */
163d4afb5ceSopenharmony_ci		wsi->socket_is_permanently_unusable = 1;
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci		return LWS_HPI_RET_PLEASE_CLOSE_ME;
166d4afb5ceSopenharmony_ci	}
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
169d4afb5ceSopenharmony_ci	    lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE ||
170d4afb5ceSopenharmony_ci	    lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) {
171d4afb5ceSopenharmony_ci		/*
172d4afb5ceSopenharmony_ci		 * we stopped caring about anything except control
173d4afb5ceSopenharmony_ci		 * packets.  Force flow control off, defeat tx
174d4afb5ceSopenharmony_ci		 * draining.
175d4afb5ceSopenharmony_ci		 */
176d4afb5ceSopenharmony_ci		lws_rx_flow_control(wsi, 1);
177d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
178d4afb5ceSopenharmony_ci		if (wsi->ws)
179d4afb5ceSopenharmony_ci			wsi->ws->tx_draining_ext = 0;
180d4afb5ceSopenharmony_ci#endif
181d4afb5ceSopenharmony_ci	}
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci	if (wsi->mux_substream || wsi->upgraded_to_http2) {
184d4afb5ceSopenharmony_ci		wsi1 = lws_get_network_wsi(wsi);
185d4afb5ceSopenharmony_ci		if (wsi1 && lws_has_buffered_out(wsi1)) {
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci			lwsl_info("%s: has buffered out\n", __func__);
188d4afb5ceSopenharmony_ci			/*
189d4afb5ceSopenharmony_ci			 * We cannot deal with any kind of new RX
190d4afb5ceSopenharmony_ci			 * because we are dealing with a partial send
191d4afb5ceSopenharmony_ci			 * (new RX may trigger new http_action() that
192d4afb5ceSopenharmony_ci			 * expect to be able to send)
193d4afb5ceSopenharmony_ci			 */
194d4afb5ceSopenharmony_ci			return LWS_HPI_RET_HANDLED;
195d4afb5ceSopenharmony_ci		}
196d4afb5ceSopenharmony_ci	}
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ciread:
199d4afb5ceSopenharmony_ci	/* 3: network wsi buflist needs to be drained */
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	// lws_buflist_describe(&wsi->buflist, wsi, __func__);
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
204d4afb5ceSopenharmony_ci						&ebuf.token);
205d4afb5ceSopenharmony_ci	if (ebuf.len) {
206d4afb5ceSopenharmony_ci		lwsl_info("draining buflist (len %d)\n", ebuf.len);
207d4afb5ceSopenharmony_ci		buffered = 1;
208d4afb5ceSopenharmony_ci		goto drain;
209d4afb5ceSopenharmony_ci	} else {
210d4afb5ceSopenharmony_ci
211d4afb5ceSopenharmony_ci		if (wsi->mux_substream) {
212d4afb5ceSopenharmony_ci			lwsl_warn("%s: uh... %s mux child with nothing to drain\n", __func__, lws_wsi_tag(wsi));
213d4afb5ceSopenharmony_ci			// assert(0);
214d4afb5ceSopenharmony_ci			lws_dll2_remove(&wsi->dll_buflist);
215d4afb5ceSopenharmony_ci			return LWS_HPI_RET_HANDLED;
216d4afb5ceSopenharmony_ci		}
217d4afb5ceSopenharmony_ci	}
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	if (!lws_ssl_pending(wsi) &&
220d4afb5ceSopenharmony_ci	    !(pollfd->revents & pollfd->events & LWS_POLLIN))
221d4afb5ceSopenharmony_ci		return LWS_HPI_RET_HANDLED;
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	/* We have something to read... */
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	if (!(lwsi_role_client(wsi) &&
226d4afb5ceSopenharmony_ci	      (lwsi_state(wsi) != LRS_ESTABLISHED &&
227d4afb5ceSopenharmony_ci	       // lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2 &&
228d4afb5ceSopenharmony_ci	       lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) {
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci		ebuf.token = pt->serv_buf;
231d4afb5ceSopenharmony_ci		ebuf.len = lws_ssl_capable_read(wsi,
232d4afb5ceSopenharmony_ci					ebuf.token,
233d4afb5ceSopenharmony_ci					wsi->a.context->pt_serv_buf_size);
234d4afb5ceSopenharmony_ci		switch (ebuf.len) {
235d4afb5ceSopenharmony_ci		case 0:
236d4afb5ceSopenharmony_ci			lwsl_info("%s: zero length read\n", __func__);
237d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
238d4afb5ceSopenharmony_ci		case LWS_SSL_CAPABLE_MORE_SERVICE:
239d4afb5ceSopenharmony_ci			lwsl_info("SSL Capable more service\n");
240d4afb5ceSopenharmony_ci			return LWS_HPI_RET_HANDLED;
241d4afb5ceSopenharmony_ci		case LWS_SSL_CAPABLE_ERROR:
242d4afb5ceSopenharmony_ci			lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n", __func__);
243d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
244d4afb5ceSopenharmony_ci		}
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci		// lwsl_notice("%s: Actual RX %d\n", __func__, ebuf.len);
247d4afb5ceSopenharmony_ci		// if (ebuf.len > 0)
248d4afb5ceSopenharmony_ci		//	lwsl_hexdump_notice(ebuf.token, ebuf.len);
249d4afb5ceSopenharmony_ci	} else
250d4afb5ceSopenharmony_ci		lwsl_info("%s: skipped read\n", __func__);
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	if (ebuf.len < 0)
253d4afb5ceSopenharmony_ci		return LWS_HPI_RET_PLEASE_CLOSE_ME;
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_cidrain:
256d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
257d4afb5ceSopenharmony_ci	if (lwsi_role_http(wsi) && lwsi_role_client(wsi) &&
258d4afb5ceSopenharmony_ci	    wsi->hdr_parsing_completed && !wsi->told_user_closed) {
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci		/*
261d4afb5ceSopenharmony_ci		 * In SSL mode we get POLLIN notification about
262d4afb5ceSopenharmony_ci		 * encrypted data in.
263d4afb5ceSopenharmony_ci		 *
264d4afb5ceSopenharmony_ci		 * But that is not necessarily related to decrypted
265d4afb5ceSopenharmony_ci		 * data out becoming available; in may need to perform
266d4afb5ceSopenharmony_ci		 * other in or out before that happens.
267d4afb5ceSopenharmony_ci		 *
268d4afb5ceSopenharmony_ci		 * simply mark ourselves as having readable data
269d4afb5ceSopenharmony_ci		 * and turn off our POLLIN
270d4afb5ceSopenharmony_ci		 */
271d4afb5ceSopenharmony_ci		wsi->client_rx_avail = 1;
272d4afb5ceSopenharmony_ci		if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
273d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci		/* let user code know, he'll usually ask for writeable
276d4afb5ceSopenharmony_ci		 * callback and drain / re-enable it there
277d4afb5ceSopenharmony_ci		 */
278d4afb5ceSopenharmony_ci		if (user_callback_handle_rxflow(
279d4afb5ceSopenharmony_ci				wsi->a.protocol->callback,
280d4afb5ceSopenharmony_ci				wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
281d4afb5ceSopenharmony_ci				wsi->user_space, NULL, 0)) {
282d4afb5ceSopenharmony_ci			lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
283d4afb5ceSopenharmony_ci			return LWS_HPI_RET_PLEASE_CLOSE_ME;
284d4afb5ceSopenharmony_ci		}
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci		return LWS_HPI_RET_HANDLED;
287d4afb5ceSopenharmony_ci	}
288d4afb5ceSopenharmony_ci#endif
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci	/* service incoming data */
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci	if (ebuf.len) {
293d4afb5ceSopenharmony_ci		n = 0;
294d4afb5ceSopenharmony_ci		if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY &&
295d4afb5ceSopenharmony_ci		    lwsi_state(wsi) != LRS_DISCARD_BODY)
296d4afb5ceSopenharmony_ci			n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len);
297d4afb5ceSopenharmony_ci		else
298d4afb5ceSopenharmony_ci			n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len);
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci		if (n < 0) {
301d4afb5ceSopenharmony_ci			/* we closed wsi */
302d4afb5ceSopenharmony_ci			return LWS_HPI_RET_WSI_ALREADY_DIED;
303d4afb5ceSopenharmony_ci		}
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci		if (n && buffered) {
306d4afb5ceSopenharmony_ci			// lwsl_notice("%s: h2 use %d\n", __func__, n);
307d4afb5ceSopenharmony_ci			m = (int)lws_buflist_use_segment(&wsi->buflist, (size_t)n);
308d4afb5ceSopenharmony_ci			lwsl_info("%s: draining rxflow: used %d, next %d\n",
309d4afb5ceSopenharmony_ci				    __func__, n, m);
310d4afb5ceSopenharmony_ci			if (!m) {
311d4afb5ceSopenharmony_ci				lwsl_notice("%s: removed %s from dll_buflist\n",
312d4afb5ceSopenharmony_ci					    __func__, lws_wsi_tag(wsi));
313d4afb5ceSopenharmony_ci				lws_dll2_remove(&wsi->dll_buflist);
314d4afb5ceSopenharmony_ci			}
315d4afb5ceSopenharmony_ci		} else
316d4afb5ceSopenharmony_ci			if (n && n < ebuf.len && ebuf.len > 0) {
317d4afb5ceSopenharmony_ci				// lwsl_notice("%s: h2 append seg %d\n", __func__, ebuf.len - n);
318d4afb5ceSopenharmony_ci				m = lws_buflist_append_segment(&wsi->buflist,
319d4afb5ceSopenharmony_ci						ebuf.token + n,
320d4afb5ceSopenharmony_ci						(unsigned int)(ebuf.len - n));
321d4afb5ceSopenharmony_ci				if (m < 0)
322d4afb5ceSopenharmony_ci					return LWS_HPI_RET_PLEASE_CLOSE_ME;
323d4afb5ceSopenharmony_ci				if (m) {
324d4afb5ceSopenharmony_ci					lwsl_debug("%s: added %s to rxflow list\n",
325d4afb5ceSopenharmony_ci						   __func__, lws_wsi_tag(wsi));
326d4afb5ceSopenharmony_ci					if (lws_dll2_is_detached(&wsi->dll_buflist))
327d4afb5ceSopenharmony_ci						lws_dll2_add_head(&wsi->dll_buflist,
328d4afb5ceSopenharmony_ci							 &pt->dll_buflist_owner);
329d4afb5ceSopenharmony_ci				}
330d4afb5ceSopenharmony_ci			}
331d4afb5ceSopenharmony_ci	}
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci	// lws_buflist_describe(&wsi->buflist, wsi, __func__);
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci#if 0
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	/*
338d4afb5ceSopenharmony_ci	 * This seems to be too aggressive... we don't want the ah stuck
339d4afb5ceSopenharmony_ci	 * there but eg, WINDOW_UPDATE may come and detach it if we leave
340d4afb5ceSopenharmony_ci	 * it like that... it will get detached at stream close
341d4afb5ceSopenharmony_ci	 */
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci	if (wsi->http.ah
344d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
345d4afb5ceSopenharmony_ci			&& !wsi->client_h2_alpn
346d4afb5ceSopenharmony_ci#endif
347d4afb5ceSopenharmony_ci			) {
348d4afb5ceSopenharmony_ci		lwsl_err("xxx\n");
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci		lws_header_table_detach(wsi, 0);
351d4afb5ceSopenharmony_ci	}
352d4afb5ceSopenharmony_ci#endif
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	pending = (unsigned int)lws_ssl_pending(wsi);
355d4afb5ceSopenharmony_ci	if (pending) {
356d4afb5ceSopenharmony_ci		// lwsl_info("going around\n");
357d4afb5ceSopenharmony_ci		goto read;
358d4afb5ceSopenharmony_ci	}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	return LWS_HPI_RET_HANDLED;
361d4afb5ceSopenharmony_ci}
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ciint rops_handle_POLLOUT_h2(struct lws *wsi)
364d4afb5ceSopenharmony_ci{
365d4afb5ceSopenharmony_ci	// lwsl_notice("%s\n", __func__);
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY)
368d4afb5ceSopenharmony_ci		return LWS_HP_RET_USER_SERVICE;
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci	/*
371d4afb5ceSopenharmony_ci	 * Priority 1: H2 protocol packets
372d4afb5ceSopenharmony_ci	 */
373d4afb5ceSopenharmony_ci	if ((wsi->upgraded_to_http2
374d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
375d4afb5ceSopenharmony_ci			|| wsi->client_h2_alpn
376d4afb5ceSopenharmony_ci#endif
377d4afb5ceSopenharmony_ci			) && wsi->h2.h2n->pps) {
378d4afb5ceSopenharmony_ci		lwsl_info("servicing pps\n");
379d4afb5ceSopenharmony_ci		/*
380d4afb5ceSopenharmony_ci		 * this is called on the network connection, but may close
381d4afb5ceSopenharmony_ci		 * substreams... that may affect callers
382d4afb5ceSopenharmony_ci		 */
383d4afb5ceSopenharmony_ci		if (lws_h2_do_pps_send(wsi)) {
384d4afb5ceSopenharmony_ci			wsi->socket_is_permanently_unusable = 1;
385d4afb5ceSopenharmony_ci			return LWS_HP_RET_BAIL_DIE;
386d4afb5ceSopenharmony_ci		}
387d4afb5ceSopenharmony_ci		if (wsi->h2.h2n->pps)
388d4afb5ceSopenharmony_ci			return LWS_HP_RET_BAIL_OK;
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci		/* we can resume whatever we were doing */
391d4afb5ceSopenharmony_ci		lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_ENABLE |
392d4afb5ceSopenharmony_ci					 LWS_RXFLOW_REASON_H2_PPS_PENDING);
393d4afb5ceSopenharmony_ci
394d4afb5ceSopenharmony_ci		return LWS_HP_RET_BAIL_OK; /* leave POLLOUT active */
395d4afb5ceSopenharmony_ci	}
396d4afb5ceSopenharmony_ci
397d4afb5ceSopenharmony_ci	/* Priority 2: if we are closing, not allowed to send more data frags
398d4afb5ceSopenharmony_ci	 *	       which means user callback or tx ext flush banned now
399d4afb5ceSopenharmony_ci	 */
400d4afb5ceSopenharmony_ci	if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
401d4afb5ceSopenharmony_ci		return LWS_HP_RET_USER_SERVICE;
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci	return LWS_HP_RET_USER_SERVICE;
404d4afb5ceSopenharmony_ci}
405d4afb5ceSopenharmony_ci
406d4afb5ceSopenharmony_cistatic int
407d4afb5ceSopenharmony_cirops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
408d4afb5ceSopenharmony_ci			    enum lws_write_protocol *wp)
409d4afb5ceSopenharmony_ci{
410d4afb5ceSopenharmony_ci	unsigned char flags = 0, base = (*wp) & 0x1f;
411d4afb5ceSopenharmony_ci	size_t olen = len;
412d4afb5ceSopenharmony_ci	int n;
413d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
414d4afb5ceSopenharmony_ci	unsigned char mtubuf[4096 + LWS_PRE];
415d4afb5ceSopenharmony_ci#endif
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_ci	/* if not in a state to send stuff, then just send nothing */
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	if (!lwsi_role_ws(wsi) && !wsi->mux_stream_immortal &&
420d4afb5ceSopenharmony_ci	    base != LWS_WRITE_HTTP &&
421d4afb5ceSopenharmony_ci	    base != LWS_WRITE_HTTP_FINAL &&
422d4afb5ceSopenharmony_ci	    base != LWS_WRITE_HTTP_HEADERS_CONTINUATION &&
423d4afb5ceSopenharmony_ci	    base != LWS_WRITE_HTTP_HEADERS && lwsi_state(wsi) != LRS_BODY &&
424d4afb5ceSopenharmony_ci	    ((lwsi_state(wsi) != LRS_RETURNED_CLOSE &&
425d4afb5ceSopenharmony_ci	      lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE &&
426d4afb5ceSopenharmony_ci	      lwsi_state(wsi) != LRS_ESTABLISHED &&
427d4afb5ceSopenharmony_ci	      lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK)
428d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
429d4afb5ceSopenharmony_ci	   || base != LWS_WRITE_CLOSE
430d4afb5ceSopenharmony_ci#endif
431d4afb5ceSopenharmony_ci	)) {
432d4afb5ceSopenharmony_ci		//assert(0);
433d4afb5ceSopenharmony_ci		lwsl_notice("%s: binning wsistate 0x%x %d: %s\n", __func__,
434d4afb5ceSopenharmony_ci				(unsigned int)wsi->wsistate, *wp, wsi->a.protocol ?
435d4afb5ceSopenharmony_ci					wsi->a.protocol->name : "no protocol");
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci		return 0;
438d4afb5ceSopenharmony_ci	}
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	/* compression transform... */
441d4afb5ceSopenharmony_ci
442d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
443d4afb5ceSopenharmony_ci	if (wsi->http.lcs) {
444d4afb5ceSopenharmony_ci		unsigned char *out = mtubuf + LWS_PRE;
445d4afb5ceSopenharmony_ci		size_t o = sizeof(mtubuf) - LWS_PRE;
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ci		n = lws_http_compression_transform(wsi, buf, len, wp, &out, &o);
448d4afb5ceSopenharmony_ci		if (n)
449d4afb5ceSopenharmony_ci			return n;
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci		lwsl_info("%s: %s: transformed %d bytes to %d "
452d4afb5ceSopenharmony_ci			   "(wp 0x%x, more %d)\n", __func__,
453d4afb5ceSopenharmony_ci			   lws_wsi_tag(wsi), (int)len, (int)o, (int)*wp,
454d4afb5ceSopenharmony_ci			   wsi->http.comp_ctx.may_have_more);
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci		buf = out;
457d4afb5ceSopenharmony_ci		len = o;
458d4afb5ceSopenharmony_ci		base = (*wp) & 0x1f;
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci		if (!len)
461d4afb5ceSopenharmony_ci			return (int)olen;
462d4afb5ceSopenharmony_ci	}
463d4afb5ceSopenharmony_ci#endif
464d4afb5ceSopenharmony_ci
465d4afb5ceSopenharmony_ci	/*
466d4afb5ceSopenharmony_ci	 * ws-over-h2 also ends up here after the ws framing applied
467d4afb5ceSopenharmony_ci	 */
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci	n = LWS_H2_FRAME_TYPE_DATA;
470d4afb5ceSopenharmony_ci	if (base == LWS_WRITE_HTTP_HEADERS) {
471d4afb5ceSopenharmony_ci		n = LWS_H2_FRAME_TYPE_HEADERS;
472d4afb5ceSopenharmony_ci		if (!((*wp) & LWS_WRITE_NO_FIN))
473d4afb5ceSopenharmony_ci			flags = LWS_H2_FLAG_END_HEADERS;
474d4afb5ceSopenharmony_ci		if (wsi->h2.send_END_STREAM ||
475d4afb5ceSopenharmony_ci		    ((*wp) & LWS_WRITE_H2_STREAM_END)) {
476d4afb5ceSopenharmony_ci			flags |= LWS_H2_FLAG_END_STREAM;
477d4afb5ceSopenharmony_ci			wsi->h2.send_END_STREAM = 1;
478d4afb5ceSopenharmony_ci		}
479d4afb5ceSopenharmony_ci	}
480d4afb5ceSopenharmony_ci
481d4afb5ceSopenharmony_ci	if (base == LWS_WRITE_HTTP_HEADERS_CONTINUATION) {
482d4afb5ceSopenharmony_ci		n = LWS_H2_FRAME_TYPE_CONTINUATION;
483d4afb5ceSopenharmony_ci		if (!((*wp) & LWS_WRITE_NO_FIN))
484d4afb5ceSopenharmony_ci			flags = LWS_H2_FLAG_END_HEADERS;
485d4afb5ceSopenharmony_ci		if (wsi->h2.send_END_STREAM ||
486d4afb5ceSopenharmony_ci		    ((*wp) & LWS_WRITE_H2_STREAM_END)) {
487d4afb5ceSopenharmony_ci			flags |= LWS_H2_FLAG_END_STREAM;
488d4afb5ceSopenharmony_ci			wsi->h2.send_END_STREAM = 1;
489d4afb5ceSopenharmony_ci		}
490d4afb5ceSopenharmony_ci	}
491d4afb5ceSopenharmony_ci
492d4afb5ceSopenharmony_ci	if ((base == LWS_WRITE_HTTP ||
493d4afb5ceSopenharmony_ci	     base == LWS_WRITE_HTTP_FINAL) &&
494d4afb5ceSopenharmony_ci	     wsi->http.tx_content_length) {
495d4afb5ceSopenharmony_ci		wsi->http.tx_content_remain -= len;
496d4afb5ceSopenharmony_ci		lwsl_info("%s: %s: tx_content_rem = %llu\n", __func__,
497d4afb5ceSopenharmony_ci			  lws_wsi_tag(wsi),
498d4afb5ceSopenharmony_ci			  (unsigned long long)wsi->http.tx_content_remain);
499d4afb5ceSopenharmony_ci		if (!wsi->http.tx_content_remain) {
500d4afb5ceSopenharmony_ci			lwsl_info("%s: selecting final write mode\n", __func__);
501d4afb5ceSopenharmony_ci			base = *wp = LWS_WRITE_HTTP_FINAL;
502d4afb5ceSopenharmony_ci		}
503d4afb5ceSopenharmony_ci	}
504d4afb5ceSopenharmony_ci
505d4afb5ceSopenharmony_ci	if (base == LWS_WRITE_HTTP_FINAL || ((*wp) & LWS_WRITE_H2_STREAM_END)) {
506d4afb5ceSopenharmony_ci		flags |= LWS_H2_FLAG_END_STREAM;
507d4afb5ceSopenharmony_ci		lwsl_info("%s: %s: setting END_STREAM, 0x%x\n", __func__,
508d4afb5ceSopenharmony_ci				lws_wsi_tag(wsi), flags);
509d4afb5ceSopenharmony_ci		wsi->h2.send_END_STREAM = 1;
510d4afb5ceSopenharmony_ci	}
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci	n = lws_h2_frame_write(wsi, n, flags, wsi->mux.my_sid, (unsigned int)len, buf);
513d4afb5ceSopenharmony_ci	if (n < 0)
514d4afb5ceSopenharmony_ci		return n;
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci	/* hide it may have been compressed... */
517d4afb5ceSopenharmony_ci
518d4afb5ceSopenharmony_ci	return (int)olen;
519d4afb5ceSopenharmony_ci}
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
522d4afb5ceSopenharmony_cistatic int
523d4afb5ceSopenharmony_cirops_check_upgrades_h2(struct lws *wsi)
524d4afb5ceSopenharmony_ci{
525d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
526d4afb5ceSopenharmony_ci	char *p;
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci	/*
529d4afb5ceSopenharmony_ci	 * with H2 there's also a way to upgrade a stream to something
530d4afb5ceSopenharmony_ci	 * else... :method is CONNECT and :protocol says the name of
531d4afb5ceSopenharmony_ci	 * the new protocol we want to carry.  We have to have sent a
532d4afb5ceSopenharmony_ci	 * SETTINGS saying that we support it though.
533d4afb5ceSopenharmony_ci	 */
534d4afb5ceSopenharmony_ci	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
535d4afb5ceSopenharmony_ci	if (!wsi->a.vhost->h2.set.s[H2SET_ENABLE_CONNECT_PROTOCOL] ||
536d4afb5ceSopenharmony_ci	    !wsi->mux_substream || !p || strcmp(p, "CONNECT"))
537d4afb5ceSopenharmony_ci		return LWS_UPG_RET_CONTINUE;
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ci	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL);
540d4afb5ceSopenharmony_ci	if (!p || strcmp(p, "websocket"))
541d4afb5ceSopenharmony_ci		return LWS_UPG_RET_CONTINUE;
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_ci	lwsl_info("Upgrade h2 to ws\n");
544d4afb5ceSopenharmony_ci	lws_mux_mark_immortal(wsi);
545d4afb5ceSopenharmony_ci	wsi->h2_stream_carries_ws = 1;
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci	lws_metrics_tag_wsi_add(wsi, "upg", "ws_over_h2");
548d4afb5ceSopenharmony_ci
549d4afb5ceSopenharmony_ci	if (lws_process_ws_upgrade(wsi))
550d4afb5ceSopenharmony_ci		return LWS_UPG_RET_BAIL;
551d4afb5ceSopenharmony_ci
552d4afb5ceSopenharmony_ci	lwsl_info("Upgraded h2 to ws OK\n");
553d4afb5ceSopenharmony_ci
554d4afb5ceSopenharmony_ci	return LWS_UPG_RET_DONE;
555d4afb5ceSopenharmony_ci#else
556d4afb5ceSopenharmony_ci	return LWS_UPG_RET_CONTINUE;
557d4afb5ceSopenharmony_ci#endif
558d4afb5ceSopenharmony_ci}
559d4afb5ceSopenharmony_ci#endif
560d4afb5ceSopenharmony_ci
561d4afb5ceSopenharmony_cistatic int
562d4afb5ceSopenharmony_cirops_init_vhost_h2(struct lws_vhost *vh,
563d4afb5ceSopenharmony_ci		   const struct lws_context_creation_info *info)
564d4afb5ceSopenharmony_ci{
565d4afb5ceSopenharmony_ci	vh->h2.set = vh->context->set;
566d4afb5ceSopenharmony_ci	if (info->http2_settings[0]) {
567d4afb5ceSopenharmony_ci		int n;
568d4afb5ceSopenharmony_ci
569d4afb5ceSopenharmony_ci		for (n = 1; n < LWS_H2_SETTINGS_LEN; n++)
570d4afb5ceSopenharmony_ci			vh->h2.set.s[n] = info->http2_settings[n];
571d4afb5ceSopenharmony_ci	}
572d4afb5ceSopenharmony_ci
573d4afb5ceSopenharmony_ci	return 0;
574d4afb5ceSopenharmony_ci}
575d4afb5ceSopenharmony_ci
576d4afb5ceSopenharmony_ciint
577d4afb5ceSopenharmony_cirops_pt_init_destroy_h2(struct lws_context *context,
578d4afb5ceSopenharmony_ci		    const struct lws_context_creation_info *info,
579d4afb5ceSopenharmony_ci		    struct lws_context_per_thread *pt, int destroy)
580d4afb5ceSopenharmony_ci{
581d4afb5ceSopenharmony_ci	/* if not already set by plat, use lws default SETTINGS */
582d4afb5ceSopenharmony_ci	if (!context->set.s[0])
583d4afb5ceSopenharmony_ci		context->set = lws_h2_stock_settings;
584d4afb5ceSopenharmony_ci
585d4afb5ceSopenharmony_ci	/*
586d4afb5ceSopenharmony_ci	 * We only want to do this once... we will do it if we are built
587d4afb5ceSopenharmony_ci	 * otherwise h1 ops will do it (or nobody if no http at all)
588d4afb5ceSopenharmony_ci	 */
589d4afb5ceSopenharmony_ci#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
590d4afb5ceSopenharmony_ci	if (!destroy) {
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci		pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
593d4afb5ceSopenharmony_ci
594d4afb5ceSopenharmony_ci		__lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
595d4afb5ceSopenharmony_ci				 &pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC);
596d4afb5ceSopenharmony_ci	} else
597d4afb5ceSopenharmony_ci		lws_dll2_remove(&pt->sul_ah_lifecheck.list);
598d4afb5ceSopenharmony_ci#endif
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ci	return 0;
601d4afb5ceSopenharmony_ci}
602d4afb5ceSopenharmony_ci
603d4afb5ceSopenharmony_ci
604d4afb5ceSopenharmony_cistatic int
605d4afb5ceSopenharmony_cirops_tx_credit_h2(struct lws *wsi, char peer_to_us, int add)
606d4afb5ceSopenharmony_ci{
607d4afb5ceSopenharmony_ci	struct lws *nwsi = lws_get_network_wsi(wsi);
608d4afb5ceSopenharmony_ci	int n;
609d4afb5ceSopenharmony_ci
610d4afb5ceSopenharmony_ci	if (add) {
611d4afb5ceSopenharmony_ci		if (peer_to_us == LWSTXCR_PEER_TO_US) {
612d4afb5ceSopenharmony_ci			/*
613d4afb5ceSopenharmony_ci			 * We want to tell the peer they can write an additional
614d4afb5ceSopenharmony_ci			 * "add" bytes to us
615d4afb5ceSopenharmony_ci			 */
616d4afb5ceSopenharmony_ci			return lws_h2_update_peer_txcredit(wsi, (unsigned int)-1, add);
617d4afb5ceSopenharmony_ci		}
618d4afb5ceSopenharmony_ci
619d4afb5ceSopenharmony_ci		/*
620d4afb5ceSopenharmony_ci		 * We're being told we can write an additional "add" bytes
621d4afb5ceSopenharmony_ci		 * to the peer
622d4afb5ceSopenharmony_ci		 */
623d4afb5ceSopenharmony_ci
624d4afb5ceSopenharmony_ci		wsi->txc.tx_cr += add;
625d4afb5ceSopenharmony_ci		nwsi->txc.tx_cr += add;
626d4afb5ceSopenharmony_ci
627d4afb5ceSopenharmony_ci		return 0;
628d4afb5ceSopenharmony_ci	}
629d4afb5ceSopenharmony_ci
630d4afb5ceSopenharmony_ci	if (peer_to_us == LWSTXCR_US_TO_PEER)
631d4afb5ceSopenharmony_ci		return lws_h2_tx_cr_get(wsi);
632d4afb5ceSopenharmony_ci
633d4afb5ceSopenharmony_ci	n = wsi->txc.peer_tx_cr_est;
634d4afb5ceSopenharmony_ci	if (n > nwsi->txc.peer_tx_cr_est)
635d4afb5ceSopenharmony_ci		n = nwsi->txc.peer_tx_cr_est;
636d4afb5ceSopenharmony_ci
637d4afb5ceSopenharmony_ci	return n;
638d4afb5ceSopenharmony_ci}
639d4afb5ceSopenharmony_ci
640d4afb5ceSopenharmony_cistatic int
641d4afb5ceSopenharmony_cirops_destroy_role_h2(struct lws *wsi)
642d4afb5ceSopenharmony_ci{
643d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
644d4afb5ceSopenharmony_ci	struct allocated_headers *ah;
645d4afb5ceSopenharmony_ci
646d4afb5ceSopenharmony_ci	/* we may not have an ah, but may be on the waiting list... */
647d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: ah det due to close\n", __func__, lws_wsi_tag(wsi));
648d4afb5ceSopenharmony_ci	__lws_header_table_detach(wsi, 0);
649d4afb5ceSopenharmony_ci
650d4afb5ceSopenharmony_ci	ah = pt->http.ah_list;
651d4afb5ceSopenharmony_ci
652d4afb5ceSopenharmony_ci	while (ah) {
653d4afb5ceSopenharmony_ci		if (ah->in_use && ah->wsi == wsi) {
654d4afb5ceSopenharmony_ci			lwsl_err("%s: ah leak: %s\n", __func__, lws_wsi_tag(wsi));
655d4afb5ceSopenharmony_ci			ah->in_use = 0;
656d4afb5ceSopenharmony_ci			ah->wsi = NULL;
657d4afb5ceSopenharmony_ci			pt->http.ah_count_in_use--;
658d4afb5ceSopenharmony_ci			break;
659d4afb5ceSopenharmony_ci		}
660d4afb5ceSopenharmony_ci		ah = ah->next;
661d4afb5ceSopenharmony_ci	}
662d4afb5ceSopenharmony_ci
663d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
664d4afb5ceSopenharmony_ci	lws_http_compression_destroy(wsi);
665d4afb5ceSopenharmony_ci#endif
666d4afb5ceSopenharmony_ci
667d4afb5ceSopenharmony_ci	if (wsi->upgraded_to_http2 || wsi->mux_substream) {
668d4afb5ceSopenharmony_ci		lws_hpack_destroy_dynamic_header(wsi);
669d4afb5ceSopenharmony_ci
670d4afb5ceSopenharmony_ci		if (wsi->h2.h2n)
671d4afb5ceSopenharmony_ci			lws_free_set_NULL(wsi->h2.h2n);
672d4afb5ceSopenharmony_ci	}
673d4afb5ceSopenharmony_ci
674d4afb5ceSopenharmony_ci	return 0;
675d4afb5ceSopenharmony_ci}
676d4afb5ceSopenharmony_ci
677d4afb5ceSopenharmony_cistatic int
678d4afb5ceSopenharmony_cirops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
679d4afb5ceSopenharmony_ci{
680d4afb5ceSopenharmony_ci
681d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY)
682d4afb5ceSopenharmony_ci	if (wsi->http.proxy_clientside) {
683d4afb5ceSopenharmony_ci
684d4afb5ceSopenharmony_ci		wsi->http.proxy_clientside = 0;
685d4afb5ceSopenharmony_ci
686d4afb5ceSopenharmony_ci		if (user_callback_handle_rxflow(wsi->a.protocol->callback,
687d4afb5ceSopenharmony_ci						wsi,
688d4afb5ceSopenharmony_ci					    LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
689d4afb5ceSopenharmony_ci						wsi->user_space, NULL, 0))
690d4afb5ceSopenharmony_ci			wsi->http.proxy_clientside = 0;
691d4afb5ceSopenharmony_ci	}
692d4afb5ceSopenharmony_ci#endif
693d4afb5ceSopenharmony_ci
694d4afb5ceSopenharmony_ci	if (wsi->mux_substream && wsi->h2_stream_carries_ws)
695d4afb5ceSopenharmony_ci		lws_h2_rst_stream(wsi, 0, "none");
696d4afb5ceSopenharmony_ci/*	else
697d4afb5ceSopenharmony_ci		if (wsi->mux_substream)
698d4afb5ceSopenharmony_ci			lws_h2_rst_stream(wsi, H2_ERR_STREAM_CLOSED, "swsi got closed");
699d4afb5ceSopenharmony_ci*/
700d4afb5ceSopenharmony_ci
701d4afb5ceSopenharmony_ci	lwsl_info(" %s, his parent %s: siblings:\n", lws_wsi_tag(wsi), lws_wsi_tag(wsi->mux.parent_wsi));
702d4afb5ceSopenharmony_ci	lws_wsi_mux_dump_children(wsi);
703d4afb5ceSopenharmony_ci
704d4afb5ceSopenharmony_ci	if (wsi->upgraded_to_http2 || wsi->mux_substream
705d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
706d4afb5ceSopenharmony_ci			|| wsi->client_mux_substream
707d4afb5ceSopenharmony_ci#endif
708d4afb5ceSopenharmony_ci	) {
709d4afb5ceSopenharmony_ci		lwsl_info("closing %s: parent %s\n", lws_wsi_tag(wsi),
710d4afb5ceSopenharmony_ci				lws_wsi_tag(wsi->mux.parent_wsi));
711d4afb5ceSopenharmony_ci
712d4afb5ceSopenharmony_ci		if (wsi->mux.child_list && lwsl_visible(LLL_INFO)) {
713d4afb5ceSopenharmony_ci			lwsl_info(" parent %s: closing children: list:\n", lws_wsi_tag(wsi));
714d4afb5ceSopenharmony_ci			lws_wsi_mux_dump_children(wsi);
715d4afb5ceSopenharmony_ci		}
716d4afb5ceSopenharmony_ci		lws_wsi_mux_close_children(wsi, (int)reason);
717d4afb5ceSopenharmony_ci	}
718d4afb5ceSopenharmony_ci
719d4afb5ceSopenharmony_ci	if (wsi->upgraded_to_http2) {
720d4afb5ceSopenharmony_ci		/* remove pps */
721d4afb5ceSopenharmony_ci		struct lws_h2_protocol_send *w = wsi->h2.h2n->pps, *w1;
722d4afb5ceSopenharmony_ci
723d4afb5ceSopenharmony_ci		while (w) {
724d4afb5ceSopenharmony_ci			w1 = w->next;
725d4afb5ceSopenharmony_ci			free(w);
726d4afb5ceSopenharmony_ci			w = w1;
727d4afb5ceSopenharmony_ci		}
728d4afb5ceSopenharmony_ci		wsi->h2.h2n->pps = NULL;
729d4afb5ceSopenharmony_ci	}
730d4afb5ceSopenharmony_ci
731d4afb5ceSopenharmony_ci	if ((
732d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
733d4afb5ceSopenharmony_ci			wsi->client_mux_substream ||
734d4afb5ceSopenharmony_ci#endif
735d4afb5ceSopenharmony_ci			wsi->mux_substream) &&
736d4afb5ceSopenharmony_ci	     wsi->mux.parent_wsi) {
737d4afb5ceSopenharmony_ci		lws_wsi_mux_sibling_disconnect(wsi);
738d4afb5ceSopenharmony_ci		if (wsi->h2.pending_status_body)
739d4afb5ceSopenharmony_ci			lws_free_set_NULL(wsi->h2.pending_status_body);
740d4afb5ceSopenharmony_ci	}
741d4afb5ceSopenharmony_ci
742d4afb5ceSopenharmony_ci	return 0;
743d4afb5ceSopenharmony_ci}
744d4afb5ceSopenharmony_ci
745d4afb5ceSopenharmony_cistatic int
746d4afb5ceSopenharmony_cirops_callback_on_writable_h2(struct lws *wsi)
747d4afb5ceSopenharmony_ci{
748d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
749d4afb5ceSopenharmony_ci	struct lws *network_wsi;
750d4afb5ceSopenharmony_ci#endif
751d4afb5ceSopenharmony_ci	int already;
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci//	if (!lwsi_role_h2(wsi) && !lwsi_role_h2_ENCAPSULATION(wsi))
754d4afb5ceSopenharmony_ci//		return 0;
755d4afb5ceSopenharmony_ci
756d4afb5ceSopenharmony_ci	if (wsi->mux.requested_POLLOUT
757d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
758d4afb5ceSopenharmony_ci			&& !wsi->client_h2_alpn
759d4afb5ceSopenharmony_ci#endif
760d4afb5ceSopenharmony_ci	) {
761d4afb5ceSopenharmony_ci		lwsl_debug("already pending writable\n");
762d4afb5ceSopenharmony_ci		// return 1;
763d4afb5ceSopenharmony_ci	}
764d4afb5ceSopenharmony_ci
765d4afb5ceSopenharmony_ci	/* is this for DATA or for control messages? */
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ci	if (wsi->upgraded_to_http2 && !wsi->h2.h2n->pps &&
768d4afb5ceSopenharmony_ci	    lws_wsi_txc_check_skint(&wsi->txc, lws_h2_tx_cr_get(wsi))) {
769d4afb5ceSopenharmony_ci		/*
770d4afb5ceSopenharmony_ci		 * refuse his efforts to get WRITABLE if we have no credit and
771d4afb5ceSopenharmony_ci		 * no non-DATA pps to send
772d4afb5ceSopenharmony_ci		 */
773d4afb5ceSopenharmony_ci		lwsl_err("%s: skint\n", __func__);
774d4afb5ceSopenharmony_ci		return 0;
775d4afb5ceSopenharmony_ci	}
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
778d4afb5ceSopenharmony_ci	network_wsi = lws_get_network_wsi(wsi);
779d4afb5ceSopenharmony_ci#endif
780d4afb5ceSopenharmony_ci	already = lws_wsi_mux_mark_parents_needing_writeable(wsi);
781d4afb5ceSopenharmony_ci
782d4afb5ceSopenharmony_ci	/* for network action, act only on the network wsi */
783d4afb5ceSopenharmony_ci
784d4afb5ceSopenharmony_ci	if (already
785d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
786d4afb5ceSopenharmony_ci			&& !network_wsi->client_h2_alpn
787d4afb5ceSopenharmony_ci			&& !network_wsi->client_mux_substream
788d4afb5ceSopenharmony_ci#endif
789d4afb5ceSopenharmony_ci			)
790d4afb5ceSopenharmony_ci		return 1;
791d4afb5ceSopenharmony_ci
792d4afb5ceSopenharmony_ci	return 0;
793d4afb5ceSopenharmony_ci}
794d4afb5ceSopenharmony_ci
795d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
796d4afb5ceSopenharmony_cistatic int
797d4afb5ceSopenharmony_cilws_h2_bind_for_post_before_action(struct lws *wsi)
798d4afb5ceSopenharmony_ci{
799d4afb5ceSopenharmony_ci	const struct lws_http_mount *hit;
800d4afb5ceSopenharmony_ci	int uri_len = 0, methidx;
801d4afb5ceSopenharmony_ci	char *uri_ptr = NULL;
802d4afb5ceSopenharmony_ci	uint8_t *buffered;
803d4afb5ceSopenharmony_ci	const char *p;
804d4afb5ceSopenharmony_ci	size_t blen;
805d4afb5ceSopenharmony_ci
806d4afb5ceSopenharmony_ci	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
807d4afb5ceSopenharmony_ci	if (!p || strcmp(p, "POST"))
808d4afb5ceSopenharmony_ci		return 0;
809d4afb5ceSopenharmony_ci
810d4afb5ceSopenharmony_ci
811d4afb5ceSopenharmony_ci	if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH) ||
812d4afb5ceSopenharmony_ci	    !lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH))
813d4afb5ceSopenharmony_ci		/*
814d4afb5ceSopenharmony_ci		 * There must be a path.  Actually this is checked at
815d4afb5ceSopenharmony_ci		 * http2.c along with the other required header
816d4afb5ceSopenharmony_ci		 * presence before we can get here.
817d4afb5ceSopenharmony_ci		 *
818d4afb5ceSopenharmony_ci		 * But Coverity insists to see us check it.
819d4afb5ceSopenharmony_ci		 */
820d4afb5ceSopenharmony_ci		return 1;
821d4afb5ceSopenharmony_ci
822d4afb5ceSopenharmony_ci	hit = lws_find_mount(wsi,
823d4afb5ceSopenharmony_ci		  lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
824d4afb5ceSopenharmony_ci		  lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH));
825d4afb5ceSopenharmony_ci
826d4afb5ceSopenharmony_ci	lwsl_debug("%s: %s: hit %p: %s\n", __func__,
827d4afb5ceSopenharmony_ci		    lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
828d4afb5ceSopenharmony_ci		    hit, hit ? hit->origin : "null");
829d4afb5ceSopenharmony_ci	if (hit) {
830d4afb5ceSopenharmony_ci		const struct lws_protocols *pp;
831d4afb5ceSopenharmony_ci		const char *name = hit->origin;
832d4afb5ceSopenharmony_ci
833d4afb5ceSopenharmony_ci		if (hit->origin_protocol == LWSMPRO_CGI ||
834d4afb5ceSopenharmony_ci		    hit->origin_protocol == LWSMPRO_HTTP ||
835d4afb5ceSopenharmony_ci		    hit->origin_protocol == LWSMPRO_HTTPS)
836d4afb5ceSopenharmony_ci			return 0;
837d4afb5ceSopenharmony_ci
838d4afb5ceSopenharmony_ci		if (hit->protocol)
839d4afb5ceSopenharmony_ci			name = hit->protocol;
840d4afb5ceSopenharmony_ci		else
841d4afb5ceSopenharmony_ci			if (hit->origin_protocol == LWSMPRO_FILE)
842d4afb5ceSopenharmony_ci				return 0;
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci		pp = lws_vhost_name_to_protocol(wsi->a.vhost, name);
845d4afb5ceSopenharmony_ci		if (!pp) {
846d4afb5ceSopenharmony_ci			lwsl_info("Unable to find protocol '%s'\n", name);
847d4afb5ceSopenharmony_ci			return 1;
848d4afb5ceSopenharmony_ci		}
849d4afb5ceSopenharmony_ci
850d4afb5ceSopenharmony_ci		if (lws_bind_protocol(wsi, pp, __func__))
851d4afb5ceSopenharmony_ci			return 1;
852d4afb5ceSopenharmony_ci	}
853d4afb5ceSopenharmony_ci
854d4afb5ceSopenharmony_ci	methidx = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
855d4afb5ceSopenharmony_ci
856d4afb5ceSopenharmony_ci	if (methidx >= 0)
857d4afb5ceSopenharmony_ci		if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
858d4afb5ceSopenharmony_ci					      wsi->user_space,
859d4afb5ceSopenharmony_ci					      hit ? uri_ptr +
860d4afb5ceSopenharmony_ci						  hit->mountpoint_len : uri_ptr,
861d4afb5ceSopenharmony_ci					      (size_t)(hit ? uri_len -
862d4afb5ceSopenharmony_ci							  hit->mountpoint_len :
863d4afb5ceSopenharmony_ci							  uri_len)))
864d4afb5ceSopenharmony_ci			return 1;
865d4afb5ceSopenharmony_ci
866d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ACCESS_LOG)
867d4afb5ceSopenharmony_ci	lws_prepare_access_log_info(wsi, uri_ptr, uri_len, methidx);
868d4afb5ceSopenharmony_ci#endif
869d4afb5ceSopenharmony_ci
870d4afb5ceSopenharmony_ci	lwsl_info("%s: setting LRS_BODY from 0x%x (%s)\n", __func__,
871d4afb5ceSopenharmony_ci		    (int)wsi->wsistate, wsi->a.protocol->name);
872d4afb5ceSopenharmony_ci
873d4afb5ceSopenharmony_ci	lwsi_set_state(wsi, LRS_BODY);
874d4afb5ceSopenharmony_ci
875d4afb5ceSopenharmony_ci	if (wsi->http.content_length_explicitly_zero)
876d4afb5ceSopenharmony_ci		return 0;
877d4afb5ceSopenharmony_ci
878d4afb5ceSopenharmony_ci	/*
879d4afb5ceSopenharmony_ci	 * Dump any stashed body
880d4afb5ceSopenharmony_ci	 */
881d4afb5ceSopenharmony_ci
882d4afb5ceSopenharmony_ci	while (((!wsi->http.content_length_given) ||
883d4afb5ceSopenharmony_ci		  wsi->http.rx_content_length) &&
884d4afb5ceSopenharmony_ci	       (blen = lws_buflist_next_segment_len(&wsi->buflist, &buffered))) {
885d4afb5ceSopenharmony_ci
886d4afb5ceSopenharmony_ci		if ((size_t)wsi->http.rx_content_length < blen)
887d4afb5ceSopenharmony_ci			blen = (size_t)wsi->http.rx_content_length;
888d4afb5ceSopenharmony_ci
889d4afb5ceSopenharmony_ci		if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY,
890d4afb5ceSopenharmony_ci				wsi->user_space, buffered, blen))
891d4afb5ceSopenharmony_ci			return 1;
892d4afb5ceSopenharmony_ci		lws_buflist_use_segment(&wsi->buflist, blen);
893d4afb5ceSopenharmony_ci
894d4afb5ceSopenharmony_ci		wsi->http.rx_content_length -= blen;
895d4afb5ceSopenharmony_ci	}
896d4afb5ceSopenharmony_ci
897d4afb5ceSopenharmony_ci	if (!wsi->buflist)
898d4afb5ceSopenharmony_ci		/* Take us off the pt's "wsi holding input buflist" list */
899d4afb5ceSopenharmony_ci		lws_dll2_remove(&wsi->dll_buflist);
900d4afb5ceSopenharmony_ci
901d4afb5ceSopenharmony_ci	if (wsi->http.content_length_given && wsi->http.rx_content_length)
902d4afb5ceSopenharmony_ci		/* still a-ways to go */
903d4afb5ceSopenharmony_ci		return 0;
904d4afb5ceSopenharmony_ci
905d4afb5ceSopenharmony_ci	if (!wsi->http.content_length_given && !wsi->h2.END_STREAM)
906d4afb5ceSopenharmony_ci		return 0;
907d4afb5ceSopenharmony_ci
908d4afb5ceSopenharmony_ci	if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION,
909d4afb5ceSopenharmony_ci				      wsi->user_space, NULL, 0))
910d4afb5ceSopenharmony_ci		return 1;
911d4afb5ceSopenharmony_ci
912d4afb5ceSopenharmony_ci	return 0;
913d4afb5ceSopenharmony_ci}
914d4afb5ceSopenharmony_ci#endif
915d4afb5ceSopenharmony_ci
916d4afb5ceSopenharmony_ci/*
917d4afb5ceSopenharmony_ci * we are the 'network wsi' for potentially many muxed child wsi with
918d4afb5ceSopenharmony_ci * no network connection of their own, who have to use us for all their
919d4afb5ceSopenharmony_ci * network actions.  So we use a round-robin scheme to share out the
920d4afb5ceSopenharmony_ci * POLLOUT notifications to our children.
921d4afb5ceSopenharmony_ci *
922d4afb5ceSopenharmony_ci * But because any child could exhaust the socket's ability to take
923d4afb5ceSopenharmony_ci * writes, we can only let one child get notified each time.
924d4afb5ceSopenharmony_ci *
925d4afb5ceSopenharmony_ci * In addition children may be closed / deleted / added between POLLOUT
926d4afb5ceSopenharmony_ci * notifications, so we can't hold pointers
927d4afb5ceSopenharmony_ci */
928d4afb5ceSopenharmony_ci
929d4afb5ceSopenharmony_cistatic int
930d4afb5ceSopenharmony_cirops_perform_user_POLLOUT_h2(struct lws *wsi)
931d4afb5ceSopenharmony_ci{
932d4afb5ceSopenharmony_ci	struct lws **wsi2;
933d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
934d4afb5ceSopenharmony_ci	int write_type = LWS_WRITE_PONG;
935d4afb5ceSopenharmony_ci#endif
936d4afb5ceSopenharmony_ci	int n;
937d4afb5ceSopenharmony_ci
938d4afb5ceSopenharmony_ci	wsi = lws_get_network_wsi(wsi);
939d4afb5ceSopenharmony_ci
940d4afb5ceSopenharmony_ci	wsi->mux.requested_POLLOUT = 0;
941d4afb5ceSopenharmony_ci//	if (!wsi->h2.initialized) {
942d4afb5ceSopenharmony_ci//		lwsl_info("pollout on uninitialized http2 conn\n");
943d4afb5ceSopenharmony_ci//		return 0;
944d4afb5ceSopenharmony_ci//	}
945d4afb5ceSopenharmony_ci
946d4afb5ceSopenharmony_ci	lws_wsi_mux_dump_waiting_children(wsi);
947d4afb5ceSopenharmony_ci
948d4afb5ceSopenharmony_ci	wsi2 = &wsi->mux.child_list;
949d4afb5ceSopenharmony_ci	if (!*wsi2)
950d4afb5ceSopenharmony_ci		return 0;
951d4afb5ceSopenharmony_ci
952d4afb5ceSopenharmony_ci	do {
953d4afb5ceSopenharmony_ci		struct lws *w, **wa;
954d4afb5ceSopenharmony_ci
955d4afb5ceSopenharmony_ci		wa = &(*wsi2)->mux.sibling_list;
956d4afb5ceSopenharmony_ci		if (!(*wsi2)->mux.requested_POLLOUT)
957d4afb5ceSopenharmony_ci			goto next_child;
958d4afb5ceSopenharmony_ci
959d4afb5ceSopenharmony_ci		/*
960d4afb5ceSopenharmony_ci		 * we're going to do writable callback for this child.
961d4afb5ceSopenharmony_ci		 * move him to be the last child
962d4afb5ceSopenharmony_ci		 */
963d4afb5ceSopenharmony_ci
964d4afb5ceSopenharmony_ci		lwsl_debug("servicing child %s\n", lws_wsi_tag(*wsi2));
965d4afb5ceSopenharmony_ci
966d4afb5ceSopenharmony_ci		w = lws_wsi_mux_move_child_to_tail(wsi2);
967d4afb5ceSopenharmony_ci
968d4afb5ceSopenharmony_ci		if (!w) {
969d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
970d4afb5ceSopenharmony_ci			goto next_child;
971d4afb5ceSopenharmony_ci		}
972d4afb5ceSopenharmony_ci
973d4afb5ceSopenharmony_ci		lwsl_info("%s: child %s, sid %d, (wsistate 0x%x)\n",
974d4afb5ceSopenharmony_ci			  __func__, lws_wsi_tag(w), w->mux.my_sid,
975d4afb5ceSopenharmony_ci			  (unsigned int)w->wsistate);
976d4afb5ceSopenharmony_ci
977d4afb5ceSopenharmony_ci		/* priority 1: post compression-transform buffered output */
978d4afb5ceSopenharmony_ci
979d4afb5ceSopenharmony_ci		if (lws_has_buffered_out(w)) {
980d4afb5ceSopenharmony_ci			lwsl_debug("%s: completing partial\n", __func__);
981d4afb5ceSopenharmony_ci			if (lws_issue_raw(w, NULL, 0) < 0) {
982d4afb5ceSopenharmony_ci				lwsl_info("%s signalling to close\n", __func__);
983d4afb5ceSopenharmony_ci				lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
984d4afb5ceSopenharmony_ci						   "h2 end stream 1");
985d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
986d4afb5ceSopenharmony_ci				goto next_child;
987d4afb5ceSopenharmony_ci			}
988d4afb5ceSopenharmony_ci			lws_callback_on_writable(w);
989d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
990d4afb5ceSopenharmony_ci			goto next_child;
991d4afb5ceSopenharmony_ci		}
992d4afb5ceSopenharmony_ci
993d4afb5ceSopenharmony_ci		/* priority 2: pre compression-transform buffered output */
994d4afb5ceSopenharmony_ci
995d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
996d4afb5ceSopenharmony_ci		if (w->http.comp_ctx.buflist_comp ||
997d4afb5ceSopenharmony_ci		    w->http.comp_ctx.may_have_more) {
998d4afb5ceSopenharmony_ci			enum lws_write_protocol wp = LWS_WRITE_HTTP;
999d4afb5ceSopenharmony_ci
1000d4afb5ceSopenharmony_ci			lwsl_info("%s: completing comp partial"
1001d4afb5ceSopenharmony_ci				   "(buflist_comp %p, may %d)\n",
1002d4afb5ceSopenharmony_ci				   __func__, w->http.comp_ctx.buflist_comp,
1003d4afb5ceSopenharmony_ci				    w->http.comp_ctx.may_have_more);
1004d4afb5ceSopenharmony_ci
1005d4afb5ceSopenharmony_ci			if (rops_write_role_protocol_h2(w, NULL, 0, &wp) < 0) {
1006d4afb5ceSopenharmony_ci				lwsl_info("%s signalling to close\n", __func__);
1007d4afb5ceSopenharmony_ci				lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1008d4afb5ceSopenharmony_ci						   "comp write fail");
1009d4afb5ceSopenharmony_ci			}
1010d4afb5ceSopenharmony_ci			lws_callback_on_writable(w);
1011d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
1012d4afb5ceSopenharmony_ci			goto next_child;
1013d4afb5ceSopenharmony_ci		}
1014d4afb5ceSopenharmony_ci#endif
1015d4afb5ceSopenharmony_ci
1016d4afb5ceSopenharmony_ci		/* priority 3: if no buffered out and waiting for that... */
1017d4afb5ceSopenharmony_ci
1018d4afb5ceSopenharmony_ci		if (lwsi_state(w) == LRS_FLUSHING_BEFORE_CLOSE) {
1019d4afb5ceSopenharmony_ci			w->socket_is_permanently_unusable = 1;
1020d4afb5ceSopenharmony_ci			lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1021d4afb5ceSopenharmony_ci					   "h2 end stream 1");
1022d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
1023d4afb5ceSopenharmony_ci			goto next_child;
1024d4afb5ceSopenharmony_ci		}
1025d4afb5ceSopenharmony_ci
1026d4afb5ceSopenharmony_ci		/* if we arrived here, even by looping, we checked choked */
1027d4afb5ceSopenharmony_ci		w->could_have_pending = 0;
1028d4afb5ceSopenharmony_ci		wsi->could_have_pending = 0;
1029d4afb5ceSopenharmony_ci
1030d4afb5ceSopenharmony_ci		if (w->h2.pending_status_body) {
1031d4afb5ceSopenharmony_ci			w->h2.send_END_STREAM = 1;
1032d4afb5ceSopenharmony_ci			n = lws_write(w, (uint8_t *)w->h2.pending_status_body +
1033d4afb5ceSopenharmony_ci					 LWS_PRE,
1034d4afb5ceSopenharmony_ci				         strlen(w->h2.pending_status_body +
1035d4afb5ceSopenharmony_ci					        LWS_PRE), LWS_WRITE_HTTP_FINAL);
1036d4afb5ceSopenharmony_ci			lws_free_set_NULL(w->h2.pending_status_body);
1037d4afb5ceSopenharmony_ci			lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1038d4afb5ceSopenharmony_ci					   "h2 end stream 1");
1039d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
1040d4afb5ceSopenharmony_ci			goto next_child;
1041d4afb5ceSopenharmony_ci		}
1042d4afb5ceSopenharmony_ci
1043d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1044d4afb5ceSopenharmony_ci		if (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
1045d4afb5ceSopenharmony_ci			if (lws_h2_client_handshake(w))
1046d4afb5ceSopenharmony_ci				return -1;
1047d4afb5ceSopenharmony_ci
1048d4afb5ceSopenharmony_ci			goto next_child;
1049d4afb5ceSopenharmony_ci		}
1050d4afb5ceSopenharmony_ci#endif
1051d4afb5ceSopenharmony_ci
1052d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1053d4afb5ceSopenharmony_ci		if (lwsi_state(w) == LRS_DEFERRING_ACTION) {
1054d4afb5ceSopenharmony_ci
1055d4afb5ceSopenharmony_ci			/*
1056d4afb5ceSopenharmony_ci			 * we had to defer the http_action to the POLLOUT
1057d4afb5ceSopenharmony_ci			 * handler, because we know it will send something and
1058d4afb5ceSopenharmony_ci			 * only in the POLLOUT handler do we know for sure
1059d4afb5ceSopenharmony_ci			 * that there is no partial pending on the network wsi.
1060d4afb5ceSopenharmony_ci			 */
1061d4afb5ceSopenharmony_ci
1062d4afb5ceSopenharmony_ci			lwsi_set_state(w, LRS_ESTABLISHED);
1063d4afb5ceSopenharmony_ci
1064d4afb5ceSopenharmony_ci			if (w->buflist) {
1065d4afb5ceSopenharmony_ci				struct lws_context_per_thread *pt;
1066d4afb5ceSopenharmony_ci
1067d4afb5ceSopenharmony_ci				pt = &w->a.context->pt[(int)w->tsi];
1068d4afb5ceSopenharmony_ci				lwsl_debug("%s: added %s to rxflow list\n",
1069d4afb5ceSopenharmony_ci					   __func__, lws_wsi_tag(w));
1070d4afb5ceSopenharmony_ci				lws_dll2_add_head(
1071d4afb5ceSopenharmony_ci					&w->dll_buflist,
1072d4afb5ceSopenharmony_ci					&pt->dll_buflist_owner);
1073d4afb5ceSopenharmony_ci			}
1074d4afb5ceSopenharmony_ci
1075d4afb5ceSopenharmony_ci			if (lws_h2_bind_for_post_before_action(w))
1076d4afb5ceSopenharmony_ci				return -1;
1077d4afb5ceSopenharmony_ci
1078d4afb5ceSopenharmony_ci			/*
1079d4afb5ceSopenharmony_ci			 * Well, we could be getting a POST from the client, it
1080d4afb5ceSopenharmony_ci			 * may not have any content-length.  In that case, we
1081d4afb5ceSopenharmony_ci			 * will be in LRS_BODY state, we can't actually start
1082d4afb5ceSopenharmony_ci			 * the action until we had the body and the stream is
1083d4afb5ceSopenharmony_ci			 * half-closed, indicating that we can reply
1084d4afb5ceSopenharmony_ci			 */
1085d4afb5ceSopenharmony_ci
1086d4afb5ceSopenharmony_ci			if (lwsi_state(w) == LRS_BODY &&
1087d4afb5ceSopenharmony_ci			    w->h2.h2_state != LWS_H2_STATE_HALF_CLOSED_REMOTE)
1088d4afb5ceSopenharmony_ci				goto next_child;
1089d4afb5ceSopenharmony_ci
1090d4afb5ceSopenharmony_ci			lwsl_info("  h2 action start...\n");
1091d4afb5ceSopenharmony_ci			n = lws_http_action(w);
1092d4afb5ceSopenharmony_ci			if (n < 0)
1093d4afb5ceSopenharmony_ci				lwsl_info ("   h2 action result %d\n", n);
1094d4afb5ceSopenharmony_ci			else
1095d4afb5ceSopenharmony_ci			lwsl_info("  h2 action result %d "
1096d4afb5ceSopenharmony_ci				  "(wsi->http.rx_content_remain %lld)\n",
1097d4afb5ceSopenharmony_ci				  n, w->http.rx_content_remain);
1098d4afb5ceSopenharmony_ci
1099d4afb5ceSopenharmony_ci			/*
1100d4afb5ceSopenharmony_ci			 * Commonly we only managed to start a larger transfer
1101d4afb5ceSopenharmony_ci			 * that will complete asynchronously under its own wsi
1102d4afb5ceSopenharmony_ci			 * states.  In those cases we will hear about
1103d4afb5ceSopenharmony_ci			 * END_STREAM going out in the POLLOUT handler.
1104d4afb5ceSopenharmony_ci			 */
1105d4afb5ceSopenharmony_ci			if (n >= 0 && !w->h2.pending_status_body &&
1106d4afb5ceSopenharmony_ci			    (n || w->h2.send_END_STREAM)) {
1107d4afb5ceSopenharmony_ci				lwsl_info("closing stream after h2 action\n");
1108d4afb5ceSopenharmony_ci				lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1109d4afb5ceSopenharmony_ci						   "h2 end stream");
1110d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
1111d4afb5ceSopenharmony_ci			}
1112d4afb5ceSopenharmony_ci
1113d4afb5ceSopenharmony_ci			if (n < 0)
1114d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
1115d4afb5ceSopenharmony_ci
1116d4afb5ceSopenharmony_ci			goto next_child;
1117d4afb5ceSopenharmony_ci		}
1118d4afb5ceSopenharmony_ci
1119d4afb5ceSopenharmony_ci#if defined(LWS_WITH_FILE_OPS)
1120d4afb5ceSopenharmony_ci
1121d4afb5ceSopenharmony_ci		if (lwsi_state(w) == LRS_ISSUING_FILE) {
1122d4afb5ceSopenharmony_ci
1123d4afb5ceSopenharmony_ci			if (lws_wsi_txc_check_skint(&w->txc,
1124d4afb5ceSopenharmony_ci						    lws_h2_tx_cr_get(w))) {
1125d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
1126d4afb5ceSopenharmony_ci				goto next_child;
1127d4afb5ceSopenharmony_ci			}
1128d4afb5ceSopenharmony_ci
1129d4afb5ceSopenharmony_ci			((volatile struct lws *)w)->leave_pollout_active = 0;
1130d4afb5ceSopenharmony_ci
1131d4afb5ceSopenharmony_ci			/* >0 == completion, <0 == error
1132d4afb5ceSopenharmony_ci			 *
1133d4afb5ceSopenharmony_ci			 * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION
1134d4afb5ceSopenharmony_ci			 * callback when it's done.  That's the case even if we
1135d4afb5ceSopenharmony_ci			 * just completed the send, so wait for that.
1136d4afb5ceSopenharmony_ci			 */
1137d4afb5ceSopenharmony_ci			n = lws_serve_http_file_fragment(w);
1138d4afb5ceSopenharmony_ci			lwsl_debug("lws_serve_http_file_fragment says %d\n", n);
1139d4afb5ceSopenharmony_ci
1140d4afb5ceSopenharmony_ci			/*
1141d4afb5ceSopenharmony_ci			 * We will often hear about out having sent the final
1142d4afb5ceSopenharmony_ci			 * DATA here... if so close the actual wsi
1143d4afb5ceSopenharmony_ci			 */
1144d4afb5ceSopenharmony_ci			if (n < 0 || w->h2.send_END_STREAM) {
1145d4afb5ceSopenharmony_ci				lwsl_debug("Closing POLLOUT child %s\n",
1146d4afb5ceSopenharmony_ci						lws_wsi_tag(w));
1147d4afb5ceSopenharmony_ci				lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1148d4afb5ceSopenharmony_ci						   "h2 end stream file");
1149d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
1150d4afb5ceSopenharmony_ci				goto next_child;
1151d4afb5ceSopenharmony_ci			}
1152d4afb5ceSopenharmony_ci			if (n > 0)
1153d4afb5ceSopenharmony_ci				if (lws_http_transaction_completed(w))
1154d4afb5ceSopenharmony_ci					return -1;
1155d4afb5ceSopenharmony_ci			if (!n) {
1156d4afb5ceSopenharmony_ci				lws_callback_on_writable(w);
1157d4afb5ceSopenharmony_ci				(w)->mux.requested_POLLOUT = 1;
1158d4afb5ceSopenharmony_ci			}
1159d4afb5ceSopenharmony_ci
1160d4afb5ceSopenharmony_ci			goto next_child;
1161d4afb5ceSopenharmony_ci		}
1162d4afb5ceSopenharmony_ci#endif
1163d4afb5ceSopenharmony_ci#endif
1164d4afb5ceSopenharmony_ci
1165d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_WS)
1166d4afb5ceSopenharmony_ci
1167d4afb5ceSopenharmony_ci		/* Notify peer that we decided to close */
1168d4afb5ceSopenharmony_ci
1169d4afb5ceSopenharmony_ci		if (lwsi_role_ws(w) &&
1170d4afb5ceSopenharmony_ci		    lwsi_state(w) == LRS_WAITING_TO_SEND_CLOSE) {
1171d4afb5ceSopenharmony_ci			lwsl_debug("sending close packet\n");
1172d4afb5ceSopenharmony_ci			w->waiting_to_send_close_frame = 0;
1173d4afb5ceSopenharmony_ci			n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
1174d4afb5ceSopenharmony_ci				      w->ws->close_in_ping_buffer_len,
1175d4afb5ceSopenharmony_ci				      LWS_WRITE_CLOSE);
1176d4afb5ceSopenharmony_ci			if (n >= 0) {
1177d4afb5ceSopenharmony_ci				lwsi_set_state(w, LRS_AWAITING_CLOSE_ACK);
1178d4afb5ceSopenharmony_ci				lws_set_timeout(w, PENDING_TIMEOUT_CLOSE_ACK, 5);
1179d4afb5ceSopenharmony_ci				lwsl_debug("sent close frame, awaiting ack\n");
1180d4afb5ceSopenharmony_ci			}
1181d4afb5ceSopenharmony_ci
1182d4afb5ceSopenharmony_ci			goto next_child;
1183d4afb5ceSopenharmony_ci		}
1184d4afb5ceSopenharmony_ci
1185d4afb5ceSopenharmony_ci		/*
1186d4afb5ceSopenharmony_ci		 * Acknowledge receipt of peer's notification he closed,
1187d4afb5ceSopenharmony_ci		 * then logically close ourself
1188d4afb5ceSopenharmony_ci		 */
1189d4afb5ceSopenharmony_ci
1190d4afb5ceSopenharmony_ci		if ((lwsi_role_ws(w) && w->ws->pong_pending_flag) ||
1191d4afb5ceSopenharmony_ci		    (lwsi_state(w) == LRS_RETURNED_CLOSE &&
1192d4afb5ceSopenharmony_ci		     w->ws->payload_is_close)) {
1193d4afb5ceSopenharmony_ci
1194d4afb5ceSopenharmony_ci			if (w->ws->payload_is_close)
1195d4afb5ceSopenharmony_ci				write_type = LWS_WRITE_CLOSE |
1196d4afb5ceSopenharmony_ci					     LWS_WRITE_H2_STREAM_END;
1197d4afb5ceSopenharmony_ci
1198d4afb5ceSopenharmony_ci			n = lws_write(w, &w->ws->pong_payload_buf[LWS_PRE],
1199d4afb5ceSopenharmony_ci				      w->ws->pong_payload_len, (enum lws_write_protocol)write_type);
1200d4afb5ceSopenharmony_ci			if (n < 0)
1201d4afb5ceSopenharmony_ci				return -1;
1202d4afb5ceSopenharmony_ci
1203d4afb5ceSopenharmony_ci			/* well he is sent, mark him done */
1204d4afb5ceSopenharmony_ci			w->ws->pong_pending_flag = 0;
1205d4afb5ceSopenharmony_ci			if (w->ws->payload_is_close) {
1206d4afb5ceSopenharmony_ci				/* oh... a close frame... then we are done */
1207d4afb5ceSopenharmony_ci				lwsl_debug("Ack'd peer's close packet\n");
1208d4afb5ceSopenharmony_ci				w->ws->payload_is_close = 0;
1209d4afb5ceSopenharmony_ci				lwsi_set_state(w, LRS_RETURNED_CLOSE);
1210d4afb5ceSopenharmony_ci				lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1211d4afb5ceSopenharmony_ci						   "returned close packet");
1212d4afb5ceSopenharmony_ci				wa = &wsi->mux.child_list;
1213d4afb5ceSopenharmony_ci				goto next_child;
1214d4afb5ceSopenharmony_ci			}
1215d4afb5ceSopenharmony_ci
1216d4afb5ceSopenharmony_ci			lws_callback_on_writable(w);
1217d4afb5ceSopenharmony_ci			(w)->mux.requested_POLLOUT = 1;
1218d4afb5ceSopenharmony_ci
1219d4afb5ceSopenharmony_ci			/* otherwise for PING, leave POLLOUT active both ways */
1220d4afb5ceSopenharmony_ci			goto next_child;
1221d4afb5ceSopenharmony_ci		}
1222d4afb5ceSopenharmony_ci#endif
1223d4afb5ceSopenharmony_ci
1224d4afb5ceSopenharmony_ci		/*
1225d4afb5ceSopenharmony_ci		 * set client wsi to immortal long-poll mode; send END_STREAM
1226d4afb5ceSopenharmony_ci		 * flag on headers to indicate to a server, that allows
1227d4afb5ceSopenharmony_ci		 * it, that you want them to leave the stream in a long poll
1228d4afb5ceSopenharmony_ci		 * ro immortal state.  We have to send headers so the client
1229d4afb5ceSopenharmony_ci		 * understands the http connection is ongoing.
1230d4afb5ceSopenharmony_ci		 */
1231d4afb5ceSopenharmony_ci
1232d4afb5ceSopenharmony_ci		if (w->h2.send_END_STREAM && w->h2.long_poll) {
1233d4afb5ceSopenharmony_ci			uint8_t buf[LWS_PRE + 1];
1234d4afb5ceSopenharmony_ci			enum lws_write_protocol wp = 0;
1235d4afb5ceSopenharmony_ci
1236d4afb5ceSopenharmony_ci			if (!rops_write_role_protocol_h2(w, buf + LWS_PRE, 0,
1237d4afb5ceSopenharmony_ci							 &wp)) {
1238d4afb5ceSopenharmony_ci				lwsl_info("%s: %s: entering ro long poll\n",
1239d4afb5ceSopenharmony_ci					  __func__, lws_wsi_tag(w));
1240d4afb5ceSopenharmony_ci				lws_mux_mark_immortal(w);
1241d4afb5ceSopenharmony_ci			} else
1242d4afb5ceSopenharmony_ci				lwsl_err("%s: %s: failed to set long poll\n",
1243d4afb5ceSopenharmony_ci						__func__, lws_wsi_tag(w));
1244d4afb5ceSopenharmony_ci			goto next_child;
1245d4afb5ceSopenharmony_ci		}
1246d4afb5ceSopenharmony_ci
1247d4afb5ceSopenharmony_ci		if (lws_callback_as_writeable(w)) {
1248d4afb5ceSopenharmony_ci			lwsl_info("Closing POLLOUT child (end stream %d)\n",
1249d4afb5ceSopenharmony_ci				  w->h2.send_END_STREAM);
1250d4afb5ceSopenharmony_ci			lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1251d4afb5ceSopenharmony_ci					   "h2 pollout handle");
1252d4afb5ceSopenharmony_ci			wa = &wsi->mux.child_list;
1253d4afb5ceSopenharmony_ci		} else
1254d4afb5ceSopenharmony_ci			 if (w->h2.send_END_STREAM)
1255d4afb5ceSopenharmony_ci				lws_h2_state(w, LWS_H2_STATE_HALF_CLOSED_LOCAL);
1256d4afb5ceSopenharmony_ci
1257d4afb5ceSopenharmony_cinext_child:
1258d4afb5ceSopenharmony_ci		wsi2 = wa;
1259d4afb5ceSopenharmony_ci	} while (wsi2 && *wsi2 && !lws_send_pipe_choked(wsi));
1260d4afb5ceSopenharmony_ci
1261d4afb5ceSopenharmony_ci	// lws_wsi_mux_dump_waiting_children(wsi);
1262d4afb5ceSopenharmony_ci
1263d4afb5ceSopenharmony_ci	if (lws_wsi_mux_action_pending_writeable_reqs(wsi))
1264d4afb5ceSopenharmony_ci		return -1;
1265d4afb5ceSopenharmony_ci
1266d4afb5ceSopenharmony_ci	return 0;
1267d4afb5ceSopenharmony_ci}
1268d4afb5ceSopenharmony_ci
1269d4afb5ceSopenharmony_cistatic struct lws *
1270d4afb5ceSopenharmony_cirops_encapsulation_parent_h2(struct lws *wsi)
1271d4afb5ceSopenharmony_ci{
1272d4afb5ceSopenharmony_ci	if (wsi->mux.parent_wsi)
1273d4afb5ceSopenharmony_ci		return wsi->mux.parent_wsi;
1274d4afb5ceSopenharmony_ci
1275d4afb5ceSopenharmony_ci	return NULL;
1276d4afb5ceSopenharmony_ci}
1277d4afb5ceSopenharmony_ci
1278d4afb5ceSopenharmony_cistatic int
1279d4afb5ceSopenharmony_cirops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
1280d4afb5ceSopenharmony_ci{
1281d4afb5ceSopenharmony_ci	struct allocated_headers *ah;
1282d4afb5ceSopenharmony_ci
1283d4afb5ceSopenharmony_ci	lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
1284d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CLIENT)
1285d4afb5ceSopenharmony_ci	if (lwsi_role_client(wsi)) {
1286d4afb5ceSopenharmony_ci		lwsl_info("%s: upgraded to H2\n", __func__);
1287d4afb5ceSopenharmony_ci		wsi->client_h2_alpn = 1;
1288d4afb5ceSopenharmony_ci	}
1289d4afb5ceSopenharmony_ci#endif
1290d4afb5ceSopenharmony_ci
1291d4afb5ceSopenharmony_ci	wsi->upgraded_to_http2 = 1;
1292d4afb5ceSopenharmony_ci
1293d4afb5ceSopenharmony_ci	/* adopt the header info */
1294d4afb5ceSopenharmony_ci
1295d4afb5ceSopenharmony_ci	ah = wsi->http.ah;
1296d4afb5ceSopenharmony_ci
1297d4afb5ceSopenharmony_ci	lws_role_transition(wsi, lwsi_role_client(wsi) ? LWSIFR_CLIENT : LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
1298d4afb5ceSopenharmony_ci			    &role_ops_h2);
1299d4afb5ceSopenharmony_ci
1300d4afb5ceSopenharmony_ci	/* http2 union member has http union struct at start */
1301d4afb5ceSopenharmony_ci	wsi->http.ah = ah;
1302d4afb5ceSopenharmony_ci
1303d4afb5ceSopenharmony_ci	if (!wsi->h2.h2n)
1304d4afb5ceSopenharmony_ci		wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
1305d4afb5ceSopenharmony_ci	if (!wsi->h2.h2n)
1306d4afb5ceSopenharmony_ci		return 1;
1307d4afb5ceSopenharmony_ci
1308d4afb5ceSopenharmony_ci	lws_h2_init(wsi);
1309d4afb5ceSopenharmony_ci
1310d4afb5ceSopenharmony_ci	/* HTTP2 union */
1311d4afb5ceSopenharmony_ci
1312d4afb5ceSopenharmony_ci	if (lws_hpack_dynamic_size(wsi,
1313d4afb5ceSopenharmony_ci			   (int)wsi->h2.h2n->our_set.s[H2SET_HEADER_TABLE_SIZE]))
1314d4afb5ceSopenharmony_ci		return 1;
1315d4afb5ceSopenharmony_ci	wsi->txc.tx_cr = 65535;
1316d4afb5ceSopenharmony_ci
1317d4afb5ceSopenharmony_ci	lwsl_info("%s: %s: configured for h2\n", __func__, lws_wsi_tag(wsi));
1318d4afb5ceSopenharmony_ci
1319d4afb5ceSopenharmony_ci	return 0;
1320d4afb5ceSopenharmony_ci}
1321d4afb5ceSopenharmony_ci
1322d4afb5ceSopenharmony_cistatic int
1323d4afb5ceSopenharmony_cirops_issue_keepalive_h2(struct lws *wsi, int isvalid)
1324d4afb5ceSopenharmony_ci{
1325d4afb5ceSopenharmony_ci	struct lws *nwsi = lws_get_network_wsi(wsi);
1326d4afb5ceSopenharmony_ci	struct lws_h2_protocol_send *pps;
1327d4afb5ceSopenharmony_ci	uint64_t us = (uint64_t)lws_now_usecs();
1328d4afb5ceSopenharmony_ci
1329d4afb5ceSopenharmony_ci	if (isvalid) {
1330d4afb5ceSopenharmony_ci		_lws_validity_confirmed_role(nwsi);
1331d4afb5ceSopenharmony_ci
1332d4afb5ceSopenharmony_ci		return 0;
1333d4afb5ceSopenharmony_ci	}
1334d4afb5ceSopenharmony_ci
1335d4afb5ceSopenharmony_ci	/*
1336d4afb5ceSopenharmony_ci	 * We can only send these frames on the network connection itself...
1337d4afb5ceSopenharmony_ci	 * we shouldn't be tracking validity on anything else
1338d4afb5ceSopenharmony_ci	 */
1339d4afb5ceSopenharmony_ci
1340d4afb5ceSopenharmony_ci	assert(wsi == nwsi);
1341d4afb5ceSopenharmony_ci
1342d4afb5ceSopenharmony_ci	pps = lws_h2_new_pps(LWS_H2_PPS_PING);
1343d4afb5ceSopenharmony_ci	if (!pps)
1344d4afb5ceSopenharmony_ci		return 1;
1345d4afb5ceSopenharmony_ci
1346d4afb5ceSopenharmony_ci	/*
1347d4afb5ceSopenharmony_ci	 * The peer is defined to copy us back the unchanged payload in another
1348d4afb5ceSopenharmony_ci	 * PING frame this time with ACK set.  So by sending that out with the
1349d4afb5ceSopenharmony_ci	 * current time, it's an interesting opportunity to learn the effective
1350d4afb5ceSopenharmony_ci	 * RTT on the link when the PONG comes in, plus or minus the time to
1351d4afb5ceSopenharmony_ci	 * schedule the PPS.
1352d4afb5ceSopenharmony_ci	 */
1353d4afb5ceSopenharmony_ci
1354d4afb5ceSopenharmony_ci	memcpy(pps->u.ping.ping_payload, &us, 8);
1355d4afb5ceSopenharmony_ci	lws_pps_schedule(nwsi, pps);
1356d4afb5ceSopenharmony_ci
1357d4afb5ceSopenharmony_ci	return 0;
1358d4afb5ceSopenharmony_ci}
1359d4afb5ceSopenharmony_ci
1360d4afb5ceSopenharmony_cistatic const lws_rops_t rops_table_h2[] = {
1361d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1362d4afb5ceSopenharmony_ci	/*  1 */ { .check_upgrades	  = rops_check_upgrades_h2 },
1363d4afb5ceSopenharmony_ci#else
1364d4afb5ceSopenharmony_ci	/*  1 */ { .check_upgrades	  = NULL },
1365d4afb5ceSopenharmony_ci#endif
1366d4afb5ceSopenharmony_ci	/*  2 */ { .pt_init_destroy	  = rops_pt_init_destroy_h2 },
1367d4afb5ceSopenharmony_ci	/*  3 */ { .init_vhost		  = rops_init_vhost_h2 },
1368d4afb5ceSopenharmony_ci	/*  4 */ { .handle_POLLIN	  = rops_handle_POLLIN_h2 },
1369d4afb5ceSopenharmony_ci	/*  5 */ { .handle_POLLOUT	  = rops_handle_POLLOUT_h2 },
1370d4afb5ceSopenharmony_ci	/*  6 */ { .perform_user_POLLOUT  = rops_perform_user_POLLOUT_h2 },
1371d4afb5ceSopenharmony_ci	/*  7 */ { .callback_on_writable  = rops_callback_on_writable_h2 },
1372d4afb5ceSopenharmony_ci	/*  8 */ { .tx_credit		  = rops_tx_credit_h2 },
1373d4afb5ceSopenharmony_ci	/*  9 */ { .write_role_protocol	  = rops_write_role_protocol_h2 },
1374d4afb5ceSopenharmony_ci	/* 10 */ { .encapsulation_parent  = rops_encapsulation_parent_h2 },
1375d4afb5ceSopenharmony_ci	/* 11 */ { .alpn_negotiated	  = rops_alpn_negotiated_h2 },
1376d4afb5ceSopenharmony_ci	/* 12 */ { .close_kill_connection = rops_close_kill_connection_h2 },
1377d4afb5ceSopenharmony_ci	/* 13 */ { .destroy_role	  = rops_destroy_role_h2 },
1378d4afb5ceSopenharmony_ci	/* 14 */ { .issue_keepalive	  = rops_issue_keepalive_h2 },
1379d4afb5ceSopenharmony_ci};
1380d4afb5ceSopenharmony_ci
1381d4afb5ceSopenharmony_ci
1382d4afb5ceSopenharmony_ciconst struct lws_role_ops role_ops_h2 = {
1383d4afb5ceSopenharmony_ci	/* role name */			"h2",
1384d4afb5ceSopenharmony_ci	/* alpn id */			"h2",
1385d4afb5ceSopenharmony_ci
1386d4afb5ceSopenharmony_ci	/* rops_table */		rops_table_h2,
1387d4afb5ceSopenharmony_ci	/* rops_idx */			{
1388d4afb5ceSopenharmony_ci	  /* LWS_ROPS_check_upgrades */
1389d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
1390d4afb5ceSopenharmony_ci	  /* LWS_ROPS_pt_init_destroy */		0x12,
1391d4afb5ceSopenharmony_ci#else
1392d4afb5ceSopenharmony_ci	  /* LWS_ROPS_pt_init_destroy */		0x02,
1393d4afb5ceSopenharmony_ci#endif
1394d4afb5ceSopenharmony_ci	  /* LWS_ROPS_init_vhost */
1395d4afb5ceSopenharmony_ci	  /* LWS_ROPS_destroy_vhost */			0x30,
1396d4afb5ceSopenharmony_ci	  /* LWS_ROPS_service_flag_pending */
1397d4afb5ceSopenharmony_ci	  /* LWS_ROPS_handle_POLLIN */			0x04,
1398d4afb5ceSopenharmony_ci	  /* LWS_ROPS_handle_POLLOUT */
1399d4afb5ceSopenharmony_ci	  /* LWS_ROPS_perform_user_POLLOUT */		0x56,
1400d4afb5ceSopenharmony_ci	  /* LWS_ROPS_callback_on_writable */
1401d4afb5ceSopenharmony_ci	  /* LWS_ROPS_tx_credit */			0x78,
1402d4afb5ceSopenharmony_ci	  /* LWS_ROPS_write_role_protocol */
1403d4afb5ceSopenharmony_ci	  /* LWS_ROPS_encapsulation_parent */		0x9a,
1404d4afb5ceSopenharmony_ci	  /* LWS_ROPS_alpn_negotiated */
1405d4afb5ceSopenharmony_ci	  /* LWS_ROPS_close_via_role_protocol */	0xb0,
1406d4afb5ceSopenharmony_ci	  /* LWS_ROPS_close_role */
1407d4afb5ceSopenharmony_ci	  /* LWS_ROPS_close_kill_connection */		0x0c,
1408d4afb5ceSopenharmony_ci	  /* LWS_ROPS_destroy_role */
1409d4afb5ceSopenharmony_ci	  /* LWS_ROPS_adoption_bind */			0xd0,
1410d4afb5ceSopenharmony_ci	  /* LWS_ROPS_client_bind */
1411d4afb5ceSopenharmony_ci	  /* LWS_ROPS_issue_keepalive */		0x0e,
1412d4afb5ceSopenharmony_ci					},
1413d4afb5ceSopenharmony_ci	/* adoption_cb clnt, srv */	{ LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
1414d4afb5ceSopenharmony_ci					  LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
1415d4afb5ceSopenharmony_ci	/* rx cb clnt, srv */		{ LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
1416d4afb5ceSopenharmony_ci					  0 /* may be POST, etc */ },
1417d4afb5ceSopenharmony_ci	/* writeable cb clnt, srv */	{ LWS_CALLBACK_CLIENT_HTTP_WRITEABLE,
1418d4afb5ceSopenharmony_ci					  LWS_CALLBACK_HTTP_WRITEABLE },
1419d4afb5ceSopenharmony_ci	/* close cb clnt, srv */	{ LWS_CALLBACK_CLOSED_CLIENT_HTTP,
1420d4afb5ceSopenharmony_ci					  LWS_CALLBACK_CLOSED_HTTP },
1421d4afb5ceSopenharmony_ci	/* protocol_bind cb c, srv */	{ LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL,
1422d4afb5ceSopenharmony_ci					  LWS_CALLBACK_HTTP_BIND_PROTOCOL },
1423d4afb5ceSopenharmony_ci	/* protocol_unbind cb c, srv */	{ LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL,
1424d4afb5ceSopenharmony_ci					  LWS_CALLBACK_HTTP_DROP_PROTOCOL },
1425d4afb5ceSopenharmony_ci	/* file_handle */		0,
1426d4afb5ceSopenharmony_ci};
1427