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 * parsers.c: lws_ws_rx_sm() needs to be roughly kept in
29d4afb5ceSopenharmony_ci *   sync with changes here, esp related to ext draining
30d4afb5ceSopenharmony_ci */
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_ciint lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
33d4afb5ceSopenharmony_ci{
34d4afb5ceSopenharmony_ci	int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
35d4afb5ceSopenharmony_ci	struct lws_ext_pm_deflate_rx_ebufs pmdrx;
36d4afb5ceSopenharmony_ci	unsigned short close_code;
37d4afb5ceSopenharmony_ci	unsigned char *pp;
38d4afb5ceSopenharmony_ci	int handled, m, n;
39d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
40d4afb5ceSopenharmony_ci	int rx_draining_ext = 0;
41d4afb5ceSopenharmony_ci#endif
42d4afb5ceSopenharmony_ci
43d4afb5ceSopenharmony_ci	pmdrx.eb_in.token = NULL;
44d4afb5ceSopenharmony_ci	pmdrx.eb_in.len = 0;
45d4afb5ceSopenharmony_ci	pmdrx.eb_out.token = NULL;
46d4afb5ceSopenharmony_ci	pmdrx.eb_out.len = 0;
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
49d4afb5ceSopenharmony_ci	if (wsi->ws->rx_draining_ext) {
50d4afb5ceSopenharmony_ci		assert(!c);
51d4afb5ceSopenharmony_ci
52d4afb5ceSopenharmony_ci		lws_remove_wsi_from_draining_ext_list(wsi);
53d4afb5ceSopenharmony_ci		rx_draining_ext = 1;
54d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "doing draining flow");
55d4afb5ceSopenharmony_ci
56d4afb5ceSopenharmony_ci		goto drain_extension;
57d4afb5ceSopenharmony_ci	}
58d4afb5ceSopenharmony_ci#endif
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci	switch (wsi->lws_rx_parse_state) {
61d4afb5ceSopenharmony_ci	case LWS_RXPS_NEW:
62d4afb5ceSopenharmony_ci		/* control frames (PING) may interrupt checkable sequences */
63d4afb5ceSopenharmony_ci		wsi->ws->defeat_check_utf8 = 0;
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci		switch (wsi->ws->ietf_spec_revision) {
66d4afb5ceSopenharmony_ci		case 13:
67d4afb5ceSopenharmony_ci			wsi->ws->opcode = c & 0xf;
68d4afb5ceSopenharmony_ci			/* revisit if an extension wants them... */
69d4afb5ceSopenharmony_ci			switch (wsi->ws->opcode) {
70d4afb5ceSopenharmony_ci			case LWSWSOPC_TEXT_FRAME:
71d4afb5ceSopenharmony_ci				wsi->ws->rsv_first_msg = (c & 0x70);
72d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
73d4afb5ceSopenharmony_ci				/*
74d4afb5ceSopenharmony_ci				 * set the expectation that we will have to
75d4afb5ceSopenharmony_ci				 * fake up the zlib trailer to the inflator for
76d4afb5ceSopenharmony_ci				 * this frame
77d4afb5ceSopenharmony_ci				 */
78d4afb5ceSopenharmony_ci				wsi->ws->pmd_trailer_application = !!(c & 0x40);
79d4afb5ceSopenharmony_ci#endif
80d4afb5ceSopenharmony_ci				wsi->ws->continuation_possible = 1;
81d4afb5ceSopenharmony_ci				wsi->ws->check_utf8 = lws_check_opt(
82d4afb5ceSopenharmony_ci					wsi->a.context->options,
83d4afb5ceSopenharmony_ci					LWS_SERVER_OPTION_VALIDATE_UTF8);
84d4afb5ceSopenharmony_ci				wsi->ws->utf8 = 0;
85d4afb5ceSopenharmony_ci				wsi->ws->first_fragment = 1;
86d4afb5ceSopenharmony_ci				break;
87d4afb5ceSopenharmony_ci			case LWSWSOPC_BINARY_FRAME:
88d4afb5ceSopenharmony_ci				wsi->ws->rsv_first_msg = (c & 0x70);
89d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
90d4afb5ceSopenharmony_ci				/*
91d4afb5ceSopenharmony_ci				 * set the expectation that we will have to
92d4afb5ceSopenharmony_ci				 * fake up the zlib trailer to the inflator for
93d4afb5ceSopenharmony_ci				 * this frame
94d4afb5ceSopenharmony_ci				 */
95d4afb5ceSopenharmony_ci				wsi->ws->pmd_trailer_application = !!(c & 0x40);
96d4afb5ceSopenharmony_ci#endif
97d4afb5ceSopenharmony_ci				wsi->ws->check_utf8 = 0;
98d4afb5ceSopenharmony_ci				wsi->ws->continuation_possible = 1;
99d4afb5ceSopenharmony_ci				wsi->ws->first_fragment = 1;
100d4afb5ceSopenharmony_ci				break;
101d4afb5ceSopenharmony_ci			case LWSWSOPC_CONTINUATION:
102d4afb5ceSopenharmony_ci				if (!wsi->ws->continuation_possible) {
103d4afb5ceSopenharmony_ci					lwsl_wsi_info(wsi, "disordered continuation");
104d4afb5ceSopenharmony_ci					return -1;
105d4afb5ceSopenharmony_ci				}
106d4afb5ceSopenharmony_ci				wsi->ws->first_fragment = 0;
107d4afb5ceSopenharmony_ci				break;
108d4afb5ceSopenharmony_ci			case LWSWSOPC_CLOSE:
109d4afb5ceSopenharmony_ci				wsi->ws->check_utf8 = 0;
110d4afb5ceSopenharmony_ci				wsi->ws->utf8 = 0;
111d4afb5ceSopenharmony_ci				break;
112d4afb5ceSopenharmony_ci			case 3:
113d4afb5ceSopenharmony_ci			case 4:
114d4afb5ceSopenharmony_ci			case 5:
115d4afb5ceSopenharmony_ci			case 6:
116d4afb5ceSopenharmony_ci			case 7:
117d4afb5ceSopenharmony_ci			case 0xb:
118d4afb5ceSopenharmony_ci			case 0xc:
119d4afb5ceSopenharmony_ci			case 0xd:
120d4afb5ceSopenharmony_ci			case 0xe:
121d4afb5ceSopenharmony_ci			case 0xf:
122d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "illegal opcode");
123d4afb5ceSopenharmony_ci				return -1;
124d4afb5ceSopenharmony_ci			default:
125d4afb5ceSopenharmony_ci				wsi->ws->defeat_check_utf8 = 1;
126d4afb5ceSopenharmony_ci				break;
127d4afb5ceSopenharmony_ci			}
128d4afb5ceSopenharmony_ci			wsi->ws->rsv = (c & 0x70);
129d4afb5ceSopenharmony_ci			/* revisit if an extension wants them... */
130d4afb5ceSopenharmony_ci			if (
131d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
132d4afb5ceSopenharmony_ci				!wsi->ws->count_act_ext &&
133d4afb5ceSopenharmony_ci#endif
134d4afb5ceSopenharmony_ci				wsi->ws->rsv) {
135d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "illegal rsv bits set");
136d4afb5ceSopenharmony_ci				return -1;
137d4afb5ceSopenharmony_ci			}
138d4afb5ceSopenharmony_ci			wsi->ws->final = !!((c >> 7) & 1);
139d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "    This RX frame Final %d",
140d4afb5ceSopenharmony_ci				 wsi->ws->final);
141d4afb5ceSopenharmony_ci
142d4afb5ceSopenharmony_ci			if (wsi->ws->owed_a_fin &&
143d4afb5ceSopenharmony_ci			    (wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
144d4afb5ceSopenharmony_ci			     wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)) {
145d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "hey you owed us a FIN");
146d4afb5ceSopenharmony_ci				return -1;
147d4afb5ceSopenharmony_ci			}
148d4afb5ceSopenharmony_ci			if ((!(wsi->ws->opcode & 8)) && wsi->ws->final) {
149d4afb5ceSopenharmony_ci				wsi->ws->continuation_possible = 0;
150d4afb5ceSopenharmony_ci				wsi->ws->owed_a_fin = 0;
151d4afb5ceSopenharmony_ci			}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci			if ((wsi->ws->opcode & 8) && !wsi->ws->final) {
154d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "control msg can't be fragmented");
155d4afb5ceSopenharmony_ci				return -1;
156d4afb5ceSopenharmony_ci			}
157d4afb5ceSopenharmony_ci			if (!wsi->ws->final)
158d4afb5ceSopenharmony_ci				wsi->ws->owed_a_fin = 1;
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci			switch (wsi->ws->opcode) {
161d4afb5ceSopenharmony_ci			case LWSWSOPC_TEXT_FRAME:
162d4afb5ceSopenharmony_ci			case LWSWSOPC_BINARY_FRAME:
163d4afb5ceSopenharmony_ci				wsi->ws->frame_is_binary = wsi->ws->opcode ==
164d4afb5ceSopenharmony_ci						 LWSWSOPC_BINARY_FRAME;
165d4afb5ceSopenharmony_ci				break;
166d4afb5ceSopenharmony_ci			}
167d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
168d4afb5ceSopenharmony_ci			break;
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci		default:
171d4afb5ceSopenharmony_ci			lwsl_wsi_err(wsi, "unknown spec version %02d",
172d4afb5ceSopenharmony_ci				 wsi->ws->ietf_spec_revision);
173d4afb5ceSopenharmony_ci			break;
174d4afb5ceSopenharmony_ci		}
175d4afb5ceSopenharmony_ci		break;
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN:
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ci		wsi->ws->this_frame_masked = !!(c & 0x80);
180d4afb5ceSopenharmony_ci		if (wsi->ws->this_frame_masked)
181d4afb5ceSopenharmony_ci			goto server_cannot_mask;
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci		switch (c & 0x7f) {
184d4afb5ceSopenharmony_ci		case 126:
185d4afb5ceSopenharmony_ci			/* control frames are not allowed to have big lengths */
186d4afb5ceSopenharmony_ci			if (wsi->ws->opcode & 8)
187d4afb5ceSopenharmony_ci				goto illegal_ctl_length;
188d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
189d4afb5ceSopenharmony_ci			break;
190d4afb5ceSopenharmony_ci		case 127:
191d4afb5ceSopenharmony_ci			/* control frames are not allowed to have big lengths */
192d4afb5ceSopenharmony_ci			if (wsi->ws->opcode & 8)
193d4afb5ceSopenharmony_ci				goto illegal_ctl_length;
194d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
195d4afb5ceSopenharmony_ci			break;
196d4afb5ceSopenharmony_ci		default:
197d4afb5ceSopenharmony_ci			wsi->ws->rx_packet_length = c & 0x7f;
198d4afb5ceSopenharmony_ci			if (wsi->ws->this_frame_masked)
199d4afb5ceSopenharmony_ci				wsi->lws_rx_parse_state =
200d4afb5ceSopenharmony_ci						LWS_RXPS_07_COLLECT_FRAME_KEY_1;
201d4afb5ceSopenharmony_ci			else {
202d4afb5ceSopenharmony_ci				if (wsi->ws->rx_packet_length) {
203d4afb5ceSopenharmony_ci					wsi->lws_rx_parse_state =
204d4afb5ceSopenharmony_ci					LWS_RXPS_WS_FRAME_PAYLOAD;
205d4afb5ceSopenharmony_ci				} else {
206d4afb5ceSopenharmony_ci					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
207d4afb5ceSopenharmony_ci					goto spill;
208d4afb5ceSopenharmony_ci				}
209d4afb5ceSopenharmony_ci			}
210d4afb5ceSopenharmony_ci			break;
211d4afb5ceSopenharmony_ci		}
212d4afb5ceSopenharmony_ci		break;
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN16_2:
215d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length = (size_t)((unsigned int)c << 8);
216d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
217d4afb5ceSopenharmony_ci		break;
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN16_1:
220d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= c;
221d4afb5ceSopenharmony_ci		if (wsi->ws->this_frame_masked)
222d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1;
223d4afb5ceSopenharmony_ci		else {
224d4afb5ceSopenharmony_ci			if (wsi->ws->rx_packet_length)
225d4afb5ceSopenharmony_ci				wsi->lws_rx_parse_state =
226d4afb5ceSopenharmony_ci					LWS_RXPS_WS_FRAME_PAYLOAD;
227d4afb5ceSopenharmony_ci			else {
228d4afb5ceSopenharmony_ci				wsi->lws_rx_parse_state = LWS_RXPS_NEW;
229d4afb5ceSopenharmony_ci				goto spill;
230d4afb5ceSopenharmony_ci			}
231d4afb5ceSopenharmony_ci		}
232d4afb5ceSopenharmony_ci		break;
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_8:
235d4afb5ceSopenharmony_ci		if (c & 0x80) {
236d4afb5ceSopenharmony_ci			lwsl_wsi_warn(wsi, "b63 of length must be zero");
237d4afb5ceSopenharmony_ci			/* kill the connection */
238d4afb5ceSopenharmony_ci			return -1;
239d4afb5ceSopenharmony_ci		}
240d4afb5ceSopenharmony_ci#if defined __LP64__
241d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length = ((size_t)c) << 56;
242d4afb5ceSopenharmony_ci#else
243d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length = 0;
244d4afb5ceSopenharmony_ci#endif
245d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
246d4afb5ceSopenharmony_ci		break;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_7:
249d4afb5ceSopenharmony_ci#if defined __LP64__
250d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 48;
251d4afb5ceSopenharmony_ci#endif
252d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
253d4afb5ceSopenharmony_ci		break;
254d4afb5ceSopenharmony_ci
255d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_6:
256d4afb5ceSopenharmony_ci#if defined __LP64__
257d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 40;
258d4afb5ceSopenharmony_ci#endif
259d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
260d4afb5ceSopenharmony_ci		break;
261d4afb5ceSopenharmony_ci
262d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_5:
263d4afb5ceSopenharmony_ci#if defined __LP64__
264d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 32;
265d4afb5ceSopenharmony_ci#endif
266d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
267d4afb5ceSopenharmony_ci		break;
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_4:
270d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 24;
271d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
272d4afb5ceSopenharmony_ci		break;
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_3:
275d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 16;
276d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
277d4afb5ceSopenharmony_ci		break;
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_2:
280d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= ((size_t)c) << 8;
281d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
282d4afb5ceSopenharmony_ci		break;
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci	case LWS_RXPS_04_FRAME_HDR_LEN64_1:
285d4afb5ceSopenharmony_ci		wsi->ws->rx_packet_length |= (size_t)c;
286d4afb5ceSopenharmony_ci		if (wsi->ws->this_frame_masked)
287d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state =
288d4afb5ceSopenharmony_ci					LWS_RXPS_07_COLLECT_FRAME_KEY_1;
289d4afb5ceSopenharmony_ci		else {
290d4afb5ceSopenharmony_ci			if (wsi->ws->rx_packet_length)
291d4afb5ceSopenharmony_ci				wsi->lws_rx_parse_state =
292d4afb5ceSopenharmony_ci					LWS_RXPS_WS_FRAME_PAYLOAD;
293d4afb5ceSopenharmony_ci			else {
294d4afb5ceSopenharmony_ci				wsi->lws_rx_parse_state = LWS_RXPS_NEW;
295d4afb5ceSopenharmony_ci				goto spill;
296d4afb5ceSopenharmony_ci			}
297d4afb5ceSopenharmony_ci		}
298d4afb5ceSopenharmony_ci		break;
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
301d4afb5ceSopenharmony_ci		wsi->ws->mask[0] = c;
302d4afb5ceSopenharmony_ci		if (c)
303d4afb5ceSopenharmony_ci			wsi->ws->all_zero_nonce = 0;
304d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
305d4afb5ceSopenharmony_ci		break;
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
308d4afb5ceSopenharmony_ci		wsi->ws->mask[1] = c;
309d4afb5ceSopenharmony_ci		if (c)
310d4afb5ceSopenharmony_ci			wsi->ws->all_zero_nonce = 0;
311d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
312d4afb5ceSopenharmony_ci		break;
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_ci	case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
315d4afb5ceSopenharmony_ci		wsi->ws->mask[2] = c;
316d4afb5ceSopenharmony_ci		if (c)
317d4afb5ceSopenharmony_ci			wsi->ws->all_zero_nonce = 0;
318d4afb5ceSopenharmony_ci		wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
319d4afb5ceSopenharmony_ci		break;
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
322d4afb5ceSopenharmony_ci		wsi->ws->mask[3] = c;
323d4afb5ceSopenharmony_ci		if (c)
324d4afb5ceSopenharmony_ci			wsi->ws->all_zero_nonce = 0;
325d4afb5ceSopenharmony_ci
326d4afb5ceSopenharmony_ci		if (wsi->ws->rx_packet_length)
327d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state =
328d4afb5ceSopenharmony_ci					LWS_RXPS_WS_FRAME_PAYLOAD;
329d4afb5ceSopenharmony_ci		else {
330d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_NEW;
331d4afb5ceSopenharmony_ci			goto spill;
332d4afb5ceSopenharmony_ci		}
333d4afb5ceSopenharmony_ci		break;
334d4afb5ceSopenharmony_ci
335d4afb5ceSopenharmony_ci	case LWS_RXPS_WS_FRAME_PAYLOAD:
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci		assert(wsi->ws->rx_ubuf);
338d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
339d4afb5ceSopenharmony_ci		if (wsi->ws->rx_draining_ext)
340d4afb5ceSopenharmony_ci			goto drain_extension;
341d4afb5ceSopenharmony_ci#endif
342d4afb5ceSopenharmony_ci		if (wsi->ws->this_frame_masked && !wsi->ws->all_zero_nonce)
343d4afb5ceSopenharmony_ci			c ^= wsi->ws->mask[(wsi->ws->mask_idx++) & 3];
344d4afb5ceSopenharmony_ci
345d4afb5ceSopenharmony_ci		/*
346d4afb5ceSopenharmony_ci		 * unmask and collect the payload body in
347d4afb5ceSopenharmony_ci		 * rx_ubuf_head + LWS_PRE
348d4afb5ceSopenharmony_ci		 */
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci		wsi->ws->rx_ubuf[LWS_PRE + (wsi->ws->rx_ubuf_head++)] = c;
351d4afb5ceSopenharmony_ci
352d4afb5ceSopenharmony_ci		if (--wsi->ws->rx_packet_length == 0) {
353d4afb5ceSopenharmony_ci			/* spill because we have the whole frame */
354d4afb5ceSopenharmony_ci			wsi->lws_rx_parse_state = LWS_RXPS_NEW;
355d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "spilling as we have the whole frame");
356d4afb5ceSopenharmony_ci			goto spill;
357d4afb5ceSopenharmony_ci		}
358d4afb5ceSopenharmony_ci
359d4afb5ceSopenharmony_ci		/*
360d4afb5ceSopenharmony_ci		 * if there's no protocol max frame size given, we are
361d4afb5ceSopenharmony_ci		 * supposed to default to context->pt_serv_buf_size
362d4afb5ceSopenharmony_ci		 */
363d4afb5ceSopenharmony_ci		if (!wsi->a.protocol->rx_buffer_size &&
364d4afb5ceSopenharmony_ci		    wsi->ws->rx_ubuf_head != wsi->a.context->pt_serv_buf_size)
365d4afb5ceSopenharmony_ci			break;
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci		if (wsi->a.protocol->rx_buffer_size &&
368d4afb5ceSopenharmony_ci		    wsi->ws->rx_ubuf_head != wsi->a.protocol->rx_buffer_size)
369d4afb5ceSopenharmony_ci			break;
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci		/* spill because we filled our rx buffer */
372d4afb5ceSopenharmony_ci
373d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "spilling as we filled our rx buffer");
374d4afb5ceSopenharmony_cispill:
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci		handled = 0;
377d4afb5ceSopenharmony_ci
378d4afb5ceSopenharmony_ci		/*
379d4afb5ceSopenharmony_ci		 * is this frame a control packet we should take care of at this
380d4afb5ceSopenharmony_ci		 * layer?  If so service it and hide it from the user callback
381d4afb5ceSopenharmony_ci		 */
382d4afb5ceSopenharmony_ci
383d4afb5ceSopenharmony_ci		switch (wsi->ws->opcode) {
384d4afb5ceSopenharmony_ci		case LWSWSOPC_CLOSE:
385d4afb5ceSopenharmony_ci			pp = &wsi->ws->rx_ubuf[LWS_PRE];
386d4afb5ceSopenharmony_ci			if (lws_check_opt(wsi->a.context->options,
387d4afb5ceSopenharmony_ci					  LWS_SERVER_OPTION_VALIDATE_UTF8) &&
388d4afb5ceSopenharmony_ci			    wsi->ws->rx_ubuf_head > 2 &&
389d4afb5ceSopenharmony_ci			    lws_check_utf8(&wsi->ws->utf8, pp + 2,
390d4afb5ceSopenharmony_ci					   wsi->ws->rx_ubuf_head - 2))
391d4afb5ceSopenharmony_ci				goto utf8_fail;
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_ci			/* is this an acknowledgment of our close? */
394d4afb5ceSopenharmony_ci			if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) {
395d4afb5ceSopenharmony_ci				/*
396d4afb5ceSopenharmony_ci				 * fine he has told us he is closing too, let's
397d4afb5ceSopenharmony_ci				 * finish our close
398d4afb5ceSopenharmony_ci				 */
399d4afb5ceSopenharmony_ci				lwsl_wsi_parser(wsi, "seen server's close ack");
400d4afb5ceSopenharmony_ci				return -1;
401d4afb5ceSopenharmony_ci			}
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci			lwsl_wsi_parser(wsi, "client sees server close len = %d",
404d4afb5ceSopenharmony_ci						 (int)wsi->ws->rx_ubuf_head);
405d4afb5ceSopenharmony_ci			if (wsi->ws->rx_ubuf_head >= 2) {
406d4afb5ceSopenharmony_ci				close_code = (unsigned short)((pp[0] << 8) | pp[1]);
407d4afb5ceSopenharmony_ci				if (close_code < 1000 ||
408d4afb5ceSopenharmony_ci				    close_code == 1004 ||
409d4afb5ceSopenharmony_ci				    close_code == 1005 ||
410d4afb5ceSopenharmony_ci				    close_code == 1006 ||
411d4afb5ceSopenharmony_ci				    (close_code >= 1016 && close_code < 3000)
412d4afb5ceSopenharmony_ci				) {
413d4afb5ceSopenharmony_ci					pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
414d4afb5ceSopenharmony_ci					pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
415d4afb5ceSopenharmony_ci				}
416d4afb5ceSopenharmony_ci			}
417d4afb5ceSopenharmony_ci			if (user_callback_handle_rxflow(
418d4afb5ceSopenharmony_ci					wsi->a.protocol->callback, wsi,
419d4afb5ceSopenharmony_ci					LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
420d4afb5ceSopenharmony_ci					wsi->user_space, pp,
421d4afb5ceSopenharmony_ci					wsi->ws->rx_ubuf_head))
422d4afb5ceSopenharmony_ci				return -1;
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci			memcpy(wsi->ws->ping_payload_buf + LWS_PRE, pp,
425d4afb5ceSopenharmony_ci			       wsi->ws->rx_ubuf_head);
426d4afb5ceSopenharmony_ci			wsi->ws->close_in_ping_buffer_len =
427d4afb5ceSopenharmony_ci					(uint8_t)wsi->ws->rx_ubuf_head;
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "scheduling return close as ack");
430d4afb5ceSopenharmony_ci			__lws_change_pollfd(wsi, LWS_POLLIN, 0);
431d4afb5ceSopenharmony_ci			lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 3);
432d4afb5ceSopenharmony_ci			wsi->waiting_to_send_close_frame = 1;
433d4afb5ceSopenharmony_ci			wsi->close_needs_ack = 0;
434d4afb5ceSopenharmony_ci			lwsi_set_state(wsi, LRS_WAITING_TO_SEND_CLOSE);
435d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
436d4afb5ceSopenharmony_ci			handled = 1;
437d4afb5ceSopenharmony_ci			break;
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci		case LWSWSOPC_PING:
440d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "received %d byte ping, sending pong",
441d4afb5ceSopenharmony_ci				  (int)wsi->ws->rx_ubuf_head);
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci			/* he set a close reason on this guy, ignore PING */
444d4afb5ceSopenharmony_ci			if (wsi->ws->close_in_ping_buffer_len)
445d4afb5ceSopenharmony_ci				goto ping_drop;
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ci			if (wsi->ws->pong_pending_flag) {
448d4afb5ceSopenharmony_ci				/*
449d4afb5ceSopenharmony_ci				 * there is already a pending pong payload
450d4afb5ceSopenharmony_ci				 * we should just log and drop
451d4afb5ceSopenharmony_ci				 */
452d4afb5ceSopenharmony_ci				lwsl_wsi_parser(wsi, "DROP PING since one pending");
453d4afb5ceSopenharmony_ci				goto ping_drop;
454d4afb5ceSopenharmony_ci			}
455d4afb5ceSopenharmony_ci
456d4afb5ceSopenharmony_ci			/* control packets can only be < 128 bytes long */
457d4afb5ceSopenharmony_ci			if (wsi->ws->rx_ubuf_head > 128 - 3) {
458d4afb5ceSopenharmony_ci				lwsl_wsi_parser(wsi, "DROP PING payload too large");
459d4afb5ceSopenharmony_ci				goto ping_drop;
460d4afb5ceSopenharmony_ci			}
461d4afb5ceSopenharmony_ci
462d4afb5ceSopenharmony_ci			/* stash the pong payload */
463d4afb5ceSopenharmony_ci			memcpy(wsi->ws->pong_payload_buf + LWS_PRE,
464d4afb5ceSopenharmony_ci			       &wsi->ws->rx_ubuf[LWS_PRE],
465d4afb5ceSopenharmony_ci			       wsi->ws->rx_ubuf_head);
466d4afb5ceSopenharmony_ci
467d4afb5ceSopenharmony_ci			wsi->ws->pong_payload_len = (uint8_t)wsi->ws->rx_ubuf_head;
468d4afb5ceSopenharmony_ci			wsi->ws->pong_pending_flag = 1;
469d4afb5ceSopenharmony_ci
470d4afb5ceSopenharmony_ci			/* get it sent as soon as possible */
471d4afb5ceSopenharmony_ci			lws_callback_on_writable(wsi);
472d4afb5ceSopenharmony_ciping_drop:
473d4afb5ceSopenharmony_ci			wsi->ws->rx_ubuf_head = 0;
474d4afb5ceSopenharmony_ci			handled = 1;
475d4afb5ceSopenharmony_ci			break;
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci		case LWSWSOPC_PONG:
478d4afb5ceSopenharmony_ci			lwsl_wsi_info(wsi, "Received pong");
479d4afb5ceSopenharmony_ci			lwsl_hexdump_wsi_debug(wsi, &wsi->ws->rx_ubuf[LWS_PRE],
480d4afb5ceSopenharmony_ci				     wsi->ws->rx_ubuf_head);
481d4afb5ceSopenharmony_ci
482d4afb5ceSopenharmony_ci			lws_validity_confirmed(wsi);
483d4afb5ceSopenharmony_ci			/* issue it */
484d4afb5ceSopenharmony_ci			callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
485d4afb5ceSopenharmony_ci			break;
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci		case LWSWSOPC_CONTINUATION:
488d4afb5ceSopenharmony_ci		case LWSWSOPC_TEXT_FRAME:
489d4afb5ceSopenharmony_ci		case LWSWSOPC_BINARY_FRAME:
490d4afb5ceSopenharmony_ci			break;
491d4afb5ceSopenharmony_ci
492d4afb5ceSopenharmony_ci		default:
493d4afb5ceSopenharmony_ci			/* not handled or failed */
494d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "Unhandled ext opc 0x%x", wsi->ws->opcode);
495d4afb5ceSopenharmony_ci			wsi->ws->rx_ubuf_head = 0;
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci			return -1;
498d4afb5ceSopenharmony_ci		}
499d4afb5ceSopenharmony_ci
500d4afb5ceSopenharmony_ci		/*
501d4afb5ceSopenharmony_ci		 * No it's real payload, pass it up to the user callback.
502d4afb5ceSopenharmony_ci		 *
503d4afb5ceSopenharmony_ci		 * We have been statefully collecting it in the
504d4afb5ceSopenharmony_ci		 * LWS_RXPS_WS_FRAME_PAYLOAD clause above.
505d4afb5ceSopenharmony_ci		 *
506d4afb5ceSopenharmony_ci		 * It's nicely buffered with the pre-padding taken care of
507d4afb5ceSopenharmony_ci		 * so it can be sent straight out again using lws_write.
508d4afb5ceSopenharmony_ci		 *
509d4afb5ceSopenharmony_ci		 * However, now we have a chunk of it, we want to deal with it
510d4afb5ceSopenharmony_ci		 * all here.  Since this may be input to permessage-deflate and
511d4afb5ceSopenharmony_ci		 * there are block limits on that for input and output, we may
512d4afb5ceSopenharmony_ci		 * need to iterate.
513d4afb5ceSopenharmony_ci		 */
514d4afb5ceSopenharmony_ci		if (handled)
515d4afb5ceSopenharmony_ci			goto already_done;
516d4afb5ceSopenharmony_ci
517d4afb5ceSopenharmony_ci		pmdrx.eb_in.token = &wsi->ws->rx_ubuf[LWS_PRE];
518d4afb5ceSopenharmony_ci		pmdrx.eb_in.len = (int)wsi->ws->rx_ubuf_head;
519d4afb5ceSopenharmony_ci
520d4afb5ceSopenharmony_ci		/* for the non-pm-deflate case */
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci		pmdrx.eb_out = pmdrx.eb_in;
523d4afb5ceSopenharmony_ci
524d4afb5ceSopenharmony_ci		lwsl_wsi_debug(wsi, "starting disbursal of %d deframed rx",
525d4afb5ceSopenharmony_ci				(int)wsi->ws->rx_ubuf_head);
526d4afb5ceSopenharmony_ci
527d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
528d4afb5ceSopenharmony_cidrain_extension:
529d4afb5ceSopenharmony_ci#endif
530d4afb5ceSopenharmony_ci		do {
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ci		//	lwsl_wsi_notice("pmdrx.eb_in.len: %d",
533d4afb5ceSopenharmony_ci		//		    (int)pmdrx.eb_in.len);
534d4afb5ceSopenharmony_ci
535d4afb5ceSopenharmony_ci			n = PMDR_DID_NOTHING;
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
538d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "+++ passing %d %p to ext",
539d4afb5ceSopenharmony_ci				 pmdrx.eb_in.len, pmdrx.eb_in.token);
540d4afb5ceSopenharmony_ci
541d4afb5ceSopenharmony_ci			n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX,
542d4afb5ceSopenharmony_ci					      &pmdrx, 0);
543d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "Ext RX returned %d", n);
544d4afb5ceSopenharmony_ci			if (n < 0) {
545d4afb5ceSopenharmony_ci				wsi->socket_is_permanently_unusable = 1;
546d4afb5ceSopenharmony_ci				return -1;
547d4afb5ceSopenharmony_ci			}
548d4afb5ceSopenharmony_ci			if (n == PMDR_DID_NOTHING)
549d4afb5ceSopenharmony_ci				/* ie, not PMDR_NOTHING_WE_SHOULD_DO */
550d4afb5ceSopenharmony_ci				break;
551d4afb5ceSopenharmony_ci#endif
552d4afb5ceSopenharmony_ci			lwsl_wsi_ext(wsi, "post inflate ebuf in len %d / out len %d",
553d4afb5ceSopenharmony_ci				    pmdrx.eb_in.len, pmdrx.eb_out.len);
554d4afb5ceSopenharmony_ci
555d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
556d4afb5ceSopenharmony_ci			if (rx_draining_ext && !pmdrx.eb_out.len) {
557d4afb5ceSopenharmony_ci				lwsl_wsi_debug(wsi, "   --- ending drain on 0 read result");
558d4afb5ceSopenharmony_ci				goto already_done;
559d4afb5ceSopenharmony_ci			}
560d4afb5ceSopenharmony_ci
561d4afb5ceSopenharmony_ci			if (n == PMDR_HAS_PENDING) {	/* 1 means stuff to drain */
562d4afb5ceSopenharmony_ci				/* extension had more... main loop will come back */
563d4afb5ceSopenharmony_ci				lwsl_wsi_ext(wsi, "adding to draining ext list");
564d4afb5ceSopenharmony_ci				lws_add_wsi_to_draining_ext_list(wsi);
565d4afb5ceSopenharmony_ci			} else {
566d4afb5ceSopenharmony_ci				lwsl_wsi_ext(wsi, "removing from draining ext list");
567d4afb5ceSopenharmony_ci				lws_remove_wsi_from_draining_ext_list(wsi);
568d4afb5ceSopenharmony_ci			}
569d4afb5ceSopenharmony_ci			rx_draining_ext = wsi->ws->rx_draining_ext;
570d4afb5ceSopenharmony_ci#endif
571d4afb5ceSopenharmony_ci
572d4afb5ceSopenharmony_ci			if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
573d4afb5ceSopenharmony_ci
574d4afb5ceSopenharmony_ci				if (lws_check_utf8(&wsi->ws->utf8,
575d4afb5ceSopenharmony_ci						   pmdrx.eb_out.token,
576d4afb5ceSopenharmony_ci						   (unsigned int)pmdrx.eb_out.len)) {
577d4afb5ceSopenharmony_ci					lws_close_reason(wsi,
578d4afb5ceSopenharmony_ci						LWS_CLOSE_STATUS_INVALID_PAYLOAD,
579d4afb5ceSopenharmony_ci						(uint8_t *)"bad utf8", 8);
580d4afb5ceSopenharmony_ci					goto utf8_fail;
581d4afb5ceSopenharmony_ci				}
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci				/* we are ending partway through utf-8 character? */
584d4afb5ceSopenharmony_ci				if (!wsi->ws->rx_packet_length &&
585d4afb5ceSopenharmony_ci				    wsi->ws->final && wsi->ws->utf8
586d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
587d4afb5ceSopenharmony_ci				    /* if ext not negotiated, going to be UNKNOWN */
588d4afb5ceSopenharmony_ci				    && (n == PMDR_EMPTY_FINAL || n == PMDR_UNKNOWN)
589d4afb5ceSopenharmony_ci#endif
590d4afb5ceSopenharmony_ci				    ) {
591d4afb5ceSopenharmony_ci					lwsl_wsi_info(wsi, "FINAL utf8 error");
592d4afb5ceSopenharmony_ci					lws_close_reason(wsi,
593d4afb5ceSopenharmony_ci						LWS_CLOSE_STATUS_INVALID_PAYLOAD,
594d4afb5ceSopenharmony_ci						(uint8_t *)"partial utf8", 12);
595d4afb5ceSopenharmony_ciutf8_fail:
596d4afb5ceSopenharmony_ci					lwsl_wsi_info(wsi, "utf8 error");
597d4afb5ceSopenharmony_ci					lwsl_hexdump_wsi_info(wsi, pmdrx.eb_out.token,
598d4afb5ceSopenharmony_ci							  (unsigned int)pmdrx.eb_out.len);
599d4afb5ceSopenharmony_ci
600d4afb5ceSopenharmony_ci					return -1;
601d4afb5ceSopenharmony_ci				}
602d4afb5ceSopenharmony_ci			}
603d4afb5ceSopenharmony_ci
604d4afb5ceSopenharmony_ci			if (pmdrx.eb_out.len < 0 &&
605d4afb5ceSopenharmony_ci			    callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
606d4afb5ceSopenharmony_ci				goto already_done;
607d4afb5ceSopenharmony_ci
608d4afb5ceSopenharmony_ci			if (!pmdrx.eb_out.token)
609d4afb5ceSopenharmony_ci				goto already_done;
610d4afb5ceSopenharmony_ci
611d4afb5ceSopenharmony_ci			pmdrx.eb_out.token[pmdrx.eb_out.len] = '\0';
612d4afb5ceSopenharmony_ci
613d4afb5ceSopenharmony_ci			if (!wsi->a.protocol->callback)
614d4afb5ceSopenharmony_ci				goto already_done;
615d4afb5ceSopenharmony_ci
616d4afb5ceSopenharmony_ci			if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
617d4afb5ceSopenharmony_ci				lwsl_wsi_info(wsi, "Client doing pong callback");
618d4afb5ceSopenharmony_ci
619d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
620d4afb5ceSopenharmony_ci			if (n == PMDR_HAS_PENDING)
621d4afb5ceSopenharmony_ci				/* extension had more... main loop will come back
622d4afb5ceSopenharmony_ci				 * we want callback to be done with this set, if so,
623d4afb5ceSopenharmony_ci				 * because lws_is_final() hides it was final until the
624d4afb5ceSopenharmony_ci				 * last chunk
625d4afb5ceSopenharmony_ci				 */
626d4afb5ceSopenharmony_ci				lws_add_wsi_to_draining_ext_list(wsi);
627d4afb5ceSopenharmony_ci			else
628d4afb5ceSopenharmony_ci				lws_remove_wsi_from_draining_ext_list(wsi);
629d4afb5ceSopenharmony_ci#endif
630d4afb5ceSopenharmony_ci
631d4afb5ceSopenharmony_ci			if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
632d4afb5ceSopenharmony_ci			    lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE ||
633d4afb5ceSopenharmony_ci			    lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK)
634d4afb5ceSopenharmony_ci				goto already_done;
635d4afb5ceSopenharmony_ci
636d4afb5ceSopenharmony_ci			/* if pmd not enabled, in == out */
637d4afb5ceSopenharmony_ci
638d4afb5ceSopenharmony_ci			if (n == PMDR_DID_NOTHING
639d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
640d4afb5ceSopenharmony_ci			    || n == PMDR_NOTHING_WE_SHOULD_DO
641d4afb5ceSopenharmony_ci			    || n == PMDR_UNKNOWN
642d4afb5ceSopenharmony_ci#endif
643d4afb5ceSopenharmony_ci			)
644d4afb5ceSopenharmony_ci				pmdrx.eb_in.len -= pmdrx.eb_out.len;
645d4afb5ceSopenharmony_ci
646d4afb5ceSopenharmony_ci			m = wsi->a.protocol->callback(wsi,
647d4afb5ceSopenharmony_ci					(enum lws_callback_reasons)callback_action,
648d4afb5ceSopenharmony_ci					wsi->user_space, pmdrx.eb_out.token,
649d4afb5ceSopenharmony_ci					(unsigned int)pmdrx.eb_out.len);
650d4afb5ceSopenharmony_ci
651d4afb5ceSopenharmony_ci			wsi->ws->first_fragment = 0;
652d4afb5ceSopenharmony_ci
653d4afb5ceSopenharmony_ci			lwsl_wsi_debug(wsi, "bulk ws rx: inp used %d, output %d",
654d4afb5ceSopenharmony_ci				    (int)wsi->ws->rx_ubuf_head,
655d4afb5ceSopenharmony_ci				    (int)pmdrx.eb_out.len);
656d4afb5ceSopenharmony_ci
657d4afb5ceSopenharmony_ci			/* if user code wants to close, let caller know */
658d4afb5ceSopenharmony_ci			if (m)
659d4afb5ceSopenharmony_ci				return 1;
660d4afb5ceSopenharmony_ci
661d4afb5ceSopenharmony_ci		} while (pmdrx.eb_in.len
662d4afb5ceSopenharmony_ci#if !defined(LWS_WITHOUT_EXTENSIONS)
663d4afb5ceSopenharmony_ci	|| rx_draining_ext
664d4afb5ceSopenharmony_ci#endif
665d4afb5ceSopenharmony_ci		);
666d4afb5ceSopenharmony_ci
667d4afb5ceSopenharmony_cialready_done:
668d4afb5ceSopenharmony_ci		wsi->ws->rx_ubuf_head = 0;
669d4afb5ceSopenharmony_ci		break;
670d4afb5ceSopenharmony_ci	default:
671d4afb5ceSopenharmony_ci		lwsl_wsi_err(wsi, "client rx illegal state");
672d4afb5ceSopenharmony_ci		return 1;
673d4afb5ceSopenharmony_ci	}
674d4afb5ceSopenharmony_ci
675d4afb5ceSopenharmony_ci	return 0;
676d4afb5ceSopenharmony_ci
677d4afb5ceSopenharmony_ciillegal_ctl_length:
678d4afb5ceSopenharmony_ci	lwsl_wsi_warn(wsi, "Control frame asking for extended length is illegal");
679d4afb5ceSopenharmony_ci
680d4afb5ceSopenharmony_ci	/* kill the connection */
681d4afb5ceSopenharmony_ci	return -1;
682d4afb5ceSopenharmony_ci
683d4afb5ceSopenharmony_ciserver_cannot_mask:
684d4afb5ceSopenharmony_ci	lws_close_reason(wsi,
685d4afb5ceSopenharmony_ci			LWS_CLOSE_STATUS_PROTOCOL_ERR,
686d4afb5ceSopenharmony_ci			(uint8_t *)"srv mask", 8);
687d4afb5ceSopenharmony_ci
688d4afb5ceSopenharmony_ci	lwsl_wsi_warn(wsi, "Server must not mask");
689d4afb5ceSopenharmony_ci
690d4afb5ceSopenharmony_ci	/* kill the connection */
691d4afb5ceSopenharmony_ci	return -1;
692d4afb5ceSopenharmony_ci}
693d4afb5ceSopenharmony_ci
694d4afb5ceSopenharmony_ci
695