1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 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#include <tchar.h>
28d4afb5ceSopenharmony_ci#include <stdio.h>
29d4afb5ceSopenharmony_ci#include <strsafe.h>
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_civoid
32d4afb5ceSopenharmony_cilws_spawn_timeout(struct lws_sorted_usec_list *sul)
33d4afb5ceSopenharmony_ci{
34d4afb5ceSopenharmony_ci	struct lws_spawn_piped *lsp = lws_container_of(sul,
35d4afb5ceSopenharmony_ci					struct lws_spawn_piped, sul);
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_ci	lwsl_warn("%s: spawn exceeded timeout, killing\n", __func__);
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci	lws_spawn_piped_kill_child_process(lsp);
40d4afb5ceSopenharmony_ci}
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_civoid
43d4afb5ceSopenharmony_cilws_spawn_sul_reap(struct lws_sorted_usec_list *sul)
44d4afb5ceSopenharmony_ci{
45d4afb5ceSopenharmony_ci	struct lws_spawn_piped *lsp = lws_container_of(sul,
46d4afb5ceSopenharmony_ci					struct lws_spawn_piped, sul_reap);
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ci	lwsl_notice("%s: reaping spawn after last stdpipe, tries left %d\n",
49d4afb5ceSopenharmony_ci		    __func__, lsp->reap_retry_budget);
50d4afb5ceSopenharmony_ci	if (!lws_spawn_reap(lsp) && !lsp->pipes_alive) {
51d4afb5ceSopenharmony_ci		if (--lsp->reap_retry_budget) {
52d4afb5ceSopenharmony_ci			lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
53d4afb5ceSopenharmony_ci					 &lsp->sul_reap, lws_spawn_sul_reap,
54d4afb5ceSopenharmony_ci					 250 * LWS_US_PER_MS);
55d4afb5ceSopenharmony_ci		} else {
56d4afb5ceSopenharmony_ci			lwsl_err("%s: Unable to reap lsp %p, killing\n",
57d4afb5ceSopenharmony_ci				 __func__, lsp);
58d4afb5ceSopenharmony_ci			lsp->reap_retry_budget = 20;
59d4afb5ceSopenharmony_ci			lws_spawn_piped_kill_child_process(lsp);
60d4afb5ceSopenharmony_ci		}
61d4afb5ceSopenharmony_ci	}
62d4afb5ceSopenharmony_ci}
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_cistatic struct lws *
65d4afb5ceSopenharmony_cilws_create_basic_wsi(struct lws_context *context, int tsi,
66d4afb5ceSopenharmony_ci		     const struct lws_role_ops *ops)
67d4afb5ceSopenharmony_ci{
68d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &context->pt[tsi];
69d4afb5ceSopenharmony_ci	struct lws *new_wsi;
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ci	if (!context->vhost_list)
72d4afb5ceSopenharmony_ci		return NULL;
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci	if ((unsigned int)context->pt[tsi].fds_count ==
75d4afb5ceSopenharmony_ci	    context->fd_limit_per_thread - 1) {
76d4afb5ceSopenharmony_ci		lwsl_err("no space for new conn\n");
77d4afb5ceSopenharmony_ci		return NULL;
78d4afb5ceSopenharmony_ci	}
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci	lws_context_lock(context, __func__);
81d4afb5ceSopenharmony_ci	new_wsi = __lws_wsi_create_with_role(context, tsi, ops, NULL);
82d4afb5ceSopenharmony_ci	lws_context_unlock(context);
83d4afb5ceSopenharmony_ci	if (new_wsi == NULL) {
84d4afb5ceSopenharmony_ci		lwsl_err("Out of memory for new connection\n");
85d4afb5ceSopenharmony_ci		return NULL;
86d4afb5ceSopenharmony_ci	}
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_ci	new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ci	/* initialize the instance struct */
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_ci	lws_role_transition(new_wsi, 0, LRS_ESTABLISHED, ops);
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	new_wsi->hdr_parsing_completed = 0;
95d4afb5ceSopenharmony_ci	new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	/*
98d4afb5ceSopenharmony_ci	 * these can only be set once the protocol is known
99d4afb5ceSopenharmony_ci	 * we set an unestablished connection's protocol pointer
100d4afb5ceSopenharmony_ci	 * to the start of the defauly vhost supported list, so it can look
101d4afb5ceSopenharmony_ci	 * for matching ones during the handshake
102d4afb5ceSopenharmony_ci	 */
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	new_wsi->user_space = NULL;
105d4afb5ceSopenharmony_ci	new_wsi->desc.sockfd = LWS_SOCK_INVALID;
106d4afb5ceSopenharmony_ci
107d4afb5ceSopenharmony_ci	return new_wsi;
108d4afb5ceSopenharmony_ci}
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_civoid
111d4afb5ceSopenharmony_cilws_spawn_piped_destroy(struct lws_spawn_piped **_lsp)
112d4afb5ceSopenharmony_ci{
113d4afb5ceSopenharmony_ci	struct lws_spawn_piped *lsp = *_lsp;
114d4afb5ceSopenharmony_ci	struct lws *wsi;
115d4afb5ceSopenharmony_ci	int n;
116d4afb5ceSopenharmony_ci
117d4afb5ceSopenharmony_ci	if (!lsp)
118d4afb5ceSopenharmony_ci		return;
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++) {
121d4afb5ceSopenharmony_ci		if (lsp->pipe_fds[n][!!(n == 0)]) {
122d4afb5ceSopenharmony_ci			CloseHandle(lsp->pipe_fds[n][n == 0]);
123d4afb5ceSopenharmony_ci			lsp->pipe_fds[n][n == 0] = NULL;
124d4afb5ceSopenharmony_ci		}
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci		for (n = 0; n < 3; n++) {
127d4afb5ceSopenharmony_ci			if (lsp->stdwsi[n]) {
128d4afb5ceSopenharmony_ci				lwsl_notice("%s: closing stdwsi %d\n", __func__, n);
129d4afb5ceSopenharmony_ci				wsi = lsp->stdwsi[n];
130d4afb5ceSopenharmony_ci				lsp->stdwsi[n]->desc.filefd = NULL;
131d4afb5ceSopenharmony_ci				lsp->stdwsi[n] = NULL;
132d4afb5ceSopenharmony_ci				lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
133d4afb5ceSopenharmony_ci			}
134d4afb5ceSopenharmony_ci		}
135d4afb5ceSopenharmony_ci	}
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	lws_dll2_remove(&lsp->dll);
138d4afb5ceSopenharmony_ci
139d4afb5ceSopenharmony_ci	lws_sul_cancel(&lsp->sul);
140d4afb5ceSopenharmony_ci	lws_sul_cancel(&lsp->sul_reap);
141d4afb5ceSopenharmony_ci	lws_sul_cancel(&lsp->sul_poll);
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	lwsl_warn("%s: deleting lsp\n", __func__);
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ci	lws_free_set_NULL((*_lsp));
146d4afb5ceSopenharmony_ci}
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ciint
149d4afb5ceSopenharmony_cilws_spawn_reap(struct lws_spawn_piped *lsp)
150d4afb5ceSopenharmony_ci{
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	void *opaque = lsp->info.opaque;
153d4afb5ceSopenharmony_ci	lsp_cb_t cb = lsp->info.reap_cb;
154d4afb5ceSopenharmony_ci	struct _lws_siginfo_t lsi;
155d4afb5ceSopenharmony_ci	lws_usec_t acct[4];
156d4afb5ceSopenharmony_ci	DWORD ex;
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci	if (!lsp->child_pid)
159d4afb5ceSopenharmony_ci		return 0;
160d4afb5ceSopenharmony_ci
161d4afb5ceSopenharmony_ci	if (!GetExitCodeProcess(lsp->child_pid, &ex)) {
162d4afb5ceSopenharmony_ci		lwsl_notice("%s: GetExitCodeProcess failed\n", __func__);
163d4afb5ceSopenharmony_ci		return 0;
164d4afb5ceSopenharmony_ci	}
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci	/* nonzero = success */
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci	if (ex == STILL_ACTIVE) {
169d4afb5ceSopenharmony_ci		lwsl_notice("%s: still active\n", __func__);
170d4afb5ceSopenharmony_ci		return 0;
171d4afb5ceSopenharmony_ci	}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci	/* mark the earliest time we knew he had gone */
174d4afb5ceSopenharmony_ci	if (!lsp->reaped) {
175d4afb5ceSopenharmony_ci		lsp->reaped = lws_now_usecs();
176d4afb5ceSopenharmony_ci
177d4afb5ceSopenharmony_ci		/*
178d4afb5ceSopenharmony_ci		 * Switch the timeout to restrict the amount of grace time
179d4afb5ceSopenharmony_ci		 * to drain stdwsi
180d4afb5ceSopenharmony_ci		 */
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci		lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
183d4afb5ceSopenharmony_ci				 &lsp->sul, lws_spawn_timeout,
184d4afb5ceSopenharmony_ci				 5 * LWS_US_PER_SEC);
185d4afb5ceSopenharmony_ci	}
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	/*
188d4afb5ceSopenharmony_ci	 * Stage finalizing our reaction to the process going down until the
189d4afb5ceSopenharmony_ci	 * stdwsi flushed whatever is in flight and all noticed they were
190d4afb5ceSopenharmony_ci	 * closed.  For that reason, each stdwsi close must call lws_spawn_reap
191d4afb5ceSopenharmony_ci	 * to check if that was the last one and we can proceed with the reap.
192d4afb5ceSopenharmony_ci	 */
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci	if (!lsp->ungraceful && lsp->pipes_alive) {
195d4afb5ceSopenharmony_ci		lwsl_notice("%s: stdwsi alive, not reaping\n", __func__);
196d4afb5ceSopenharmony_ci		return 0;
197d4afb5ceSopenharmony_ci	}
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci	/* we reached the reap point, no need for timeout wait */
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ci	lws_sul_cancel(&lsp->sul);
202d4afb5ceSopenharmony_ci
203d4afb5ceSopenharmony_ci	/*
204d4afb5ceSopenharmony_ci	 * All the stdwsi went down, nothing more is coming... it's over
205d4afb5ceSopenharmony_ci	 * Collect the final information and then reap the dead process
206d4afb5ceSopenharmony_ci	 */
207d4afb5ceSopenharmony_ci
208d4afb5ceSopenharmony_ci	lsi.retcode = 0x10000 | (int)ex;
209d4afb5ceSopenharmony_ci	lwsl_notice("%s: process exit 0x%x\n", __func__, lsi.retcode);
210d4afb5ceSopenharmony_ci	lsp->child_pid = NULL;
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	/* destroy the lsp itself first (it's freed and plsp set NULL */
213d4afb5ceSopenharmony_ci
214d4afb5ceSopenharmony_ci	if (lsp->info.plsp)
215d4afb5ceSopenharmony_ci		lws_spawn_piped_destroy(lsp->info.plsp);
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci	/* then do the parent callback informing it's destroyed */
218d4afb5ceSopenharmony_ci
219d4afb5ceSopenharmony_ci	memset(acct, 0, sizeof(acct));
220d4afb5ceSopenharmony_ci	if (cb)
221d4afb5ceSopenharmony_ci		cb(opaque, acct, &lsi, 0);
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	lwsl_notice("%s: completed reap\n", __func__);
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci	return 1; /* was reaped */
226d4afb5ceSopenharmony_ci}
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ciint
229d4afb5ceSopenharmony_cilws_spawn_piped_kill_child_process(struct lws_spawn_piped *lsp)
230d4afb5ceSopenharmony_ci{
231d4afb5ceSopenharmony_ci	if (!lsp->child_pid)
232d4afb5ceSopenharmony_ci		return 1;
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	lsp->ungraceful = 1; /* don't wait for flushing, just kill it */
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	if (lws_spawn_reap(lsp))
237d4afb5ceSopenharmony_ci		/* that may have invalidated lsp */
238d4afb5ceSopenharmony_ci		return 0;
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci	lwsl_warn("%s: calling TerminateProcess on child pid\n", __func__);
241d4afb5ceSopenharmony_ci	TerminateProcess(lsp->child_pid, 252);
242d4afb5ceSopenharmony_ci	lws_spawn_reap(lsp);
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ci	/* that may have invalidated lsp */
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	return 0;
247d4afb5ceSopenharmony_ci}
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_cistatic void
250d4afb5ceSopenharmony_ciwindows_pipe_poll_hack(lws_sorted_usec_list_t *sul)
251d4afb5ceSopenharmony_ci{
252d4afb5ceSopenharmony_ci	struct lws_spawn_piped *lsp = lws_container_of(sul,
253d4afb5ceSopenharmony_ci					struct lws_spawn_piped, sul_poll);
254d4afb5ceSopenharmony_ci	struct lws *wsi, *wsi1;
255d4afb5ceSopenharmony_ci	DWORD br;
256d4afb5ceSopenharmony_ci	char c;
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci	/*
259d4afb5ceSopenharmony_ci	 * Do it first, we know lsp exists and if it's destroyed inbetweentimes,
260d4afb5ceSopenharmony_ci	 * it will already have cancelled this
261d4afb5ceSopenharmony_ci	 */
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci	lws_sul_schedule(lsp->context, 0, &lsp->sul_poll,
264d4afb5ceSopenharmony_ci			 windows_pipe_poll_hack, 50 * LWS_US_PER_MS);
265d4afb5ceSopenharmony_ci
266d4afb5ceSopenharmony_ci	wsi = lsp->stdwsi[LWS_STDOUT];
267d4afb5ceSopenharmony_ci	wsi1 = lsp->stdwsi[LWS_STDERR];
268d4afb5ceSopenharmony_ci	if (wsi && lsp->pipe_fds[LWS_STDOUT][0] != NULL) {
269d4afb5ceSopenharmony_ci		if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDOUT][0], &c, 1, &br,
270d4afb5ceSopenharmony_ci				   NULL, NULL)) {
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci			lwsl_notice("%s: stdout pipe errored\n", __func__);
273d4afb5ceSopenharmony_ci			CloseHandle(lsp->stdwsi[LWS_STDOUT]->desc.filefd);
274d4afb5ceSopenharmony_ci			lsp->pipe_fds[LWS_STDOUT][0] = NULL;
275d4afb5ceSopenharmony_ci			lsp->stdwsi[LWS_STDOUT]->desc.filefd = NULL;
276d4afb5ceSopenharmony_ci			lsp->stdwsi[LWS_STDOUT] = NULL;
277d4afb5ceSopenharmony_ci			lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
278d4afb5ceSopenharmony_ci
279d4afb5ceSopenharmony_ci			if (lsp->stdwsi[LWS_STDIN]) {
280d4afb5ceSopenharmony_ci				lwsl_notice("%s: closing stdin from stdout close\n",
281d4afb5ceSopenharmony_ci						__func__);
282d4afb5ceSopenharmony_ci				CloseHandle(lsp->stdwsi[LWS_STDIN]->desc.filefd);
283d4afb5ceSopenharmony_ci				wsi = lsp->stdwsi[LWS_STDIN];
284d4afb5ceSopenharmony_ci				lsp->stdwsi[LWS_STDIN]->desc.filefd = NULL;
285d4afb5ceSopenharmony_ci				lsp->stdwsi[LWS_STDIN] = NULL;
286d4afb5ceSopenharmony_ci				lsp->pipe_fds[LWS_STDIN][1] = NULL;
287d4afb5ceSopenharmony_ci				lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
288d4afb5ceSopenharmony_ci			}
289d4afb5ceSopenharmony_ci
290d4afb5ceSopenharmony_ci			/*
291d4afb5ceSopenharmony_ci			 * lsp may be destroyed by here... if we wanted to
292d4afb5ceSopenharmony_ci			 * handle a still-extant stderr we'll get it next time
293d4afb5ceSopenharmony_ci			 */
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ci			return;
296d4afb5ceSopenharmony_ci		} else
297d4afb5ceSopenharmony_ci			if (br)
298d4afb5ceSopenharmony_ci				wsi->a.protocol->callback(wsi,
299d4afb5ceSopenharmony_ci							LWS_CALLBACK_RAW_RX_FILE,
300d4afb5ceSopenharmony_ci							NULL, NULL, 0);
301d4afb5ceSopenharmony_ci	}
302d4afb5ceSopenharmony_ci
303d4afb5ceSopenharmony_ci	/*
304d4afb5ceSopenharmony_ci	 * lsp may have been destroyed above
305d4afb5ceSopenharmony_ci	 */
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	if (wsi1 && lsp->pipe_fds[LWS_STDERR][0]) {
308d4afb5ceSopenharmony_ci		if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDERR][0], &c, 1, &br,
309d4afb5ceSopenharmony_ci				   NULL, NULL)) {
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci			lwsl_notice("%s: stderr pipe errored\n", __func__);
312d4afb5ceSopenharmony_ci			CloseHandle(wsi1->desc.filefd);
313d4afb5ceSopenharmony_ci			/*
314d4afb5ceSopenharmony_ci			 * Assume is stderr still extant on entry, lsp can't
315d4afb5ceSopenharmony_ci			 * have been destroyed by stdout/stdin processing
316d4afb5ceSopenharmony_ci			 */
317d4afb5ceSopenharmony_ci			lsp->stdwsi[LWS_STDERR]->desc.filefd = NULL;
318d4afb5ceSopenharmony_ci			lsp->stdwsi[LWS_STDERR] = NULL;
319d4afb5ceSopenharmony_ci			lsp->pipe_fds[LWS_STDERR][0] = NULL;
320d4afb5ceSopenharmony_ci			lws_set_timeout(wsi1, 1, LWS_TO_KILL_SYNC);
321d4afb5ceSopenharmony_ci			/*
322d4afb5ceSopenharmony_ci			 * lsp may have been destroyed above
323d4afb5ceSopenharmony_ci			 */
324d4afb5ceSopenharmony_ci		} else
325d4afb5ceSopenharmony_ci			if (br)
326d4afb5ceSopenharmony_ci				wsi1->a.protocol->callback(wsi1,
327d4afb5ceSopenharmony_ci							LWS_CALLBACK_RAW_RX_FILE,
328d4afb5ceSopenharmony_ci							NULL, NULL, 0);
329d4afb5ceSopenharmony_ci	}
330d4afb5ceSopenharmony_ci}
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci/*
335d4afb5ceSopenharmony_ci * Deals with spawning a subprocess and executing it securely with stdin/out/err
336d4afb5ceSopenharmony_ci * diverted into pipes
337d4afb5ceSopenharmony_ci */
338d4afb5ceSopenharmony_ci
339d4afb5ceSopenharmony_cistruct lws_spawn_piped *
340d4afb5ceSopenharmony_cilws_spawn_piped(const struct lws_spawn_piped_info *i)
341d4afb5ceSopenharmony_ci{
342d4afb5ceSopenharmony_ci	const struct lws_protocols *pcol = i->vh->context->vhost_list->protocols;
343d4afb5ceSopenharmony_ci	struct lws_context *context = i->vh->context;
344d4afb5ceSopenharmony_ci	struct lws_spawn_piped *lsp;
345d4afb5ceSopenharmony_ci	PROCESS_INFORMATION pi;
346d4afb5ceSopenharmony_ci	SECURITY_ATTRIBUTES sa;
347d4afb5ceSopenharmony_ci	char cli[300], *p;
348d4afb5ceSopenharmony_ci	STARTUPINFO si;
349d4afb5ceSopenharmony_ci	int n;
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci	if (i->protocol_name)
352d4afb5ceSopenharmony_ci		pcol = lws_vhost_name_to_protocol(i->vh, i->protocol_name);
353d4afb5ceSopenharmony_ci	if (!pcol) {
354d4afb5ceSopenharmony_ci		lwsl_err("%s: unknown protocol %s\n", __func__,
355d4afb5ceSopenharmony_ci			 i->protocol_name ? i->protocol_name : "default");
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci		return NULL;
358d4afb5ceSopenharmony_ci	}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	lsp = lws_zalloc(sizeof(*lsp), __func__);
361d4afb5ceSopenharmony_ci	if (!lsp) {
362d4afb5ceSopenharmony_ci		lwsl_err("%s: OOM\n", __func__);
363d4afb5ceSopenharmony_ci		return NULL;
364d4afb5ceSopenharmony_ci	}
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ci	/* wholesale take a copy of info */
367d4afb5ceSopenharmony_ci	lsp->info = *i;
368d4afb5ceSopenharmony_ci	lsp->context = context;
369d4afb5ceSopenharmony_ci	lsp->reap_retry_budget = 20;
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci	/*
372d4afb5ceSopenharmony_ci	 * Prepare the stdin / out / err pipes
373d4afb5ceSopenharmony_ci	 */
374d4afb5ceSopenharmony_ci
375d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++) {
376d4afb5ceSopenharmony_ci		lsp->pipe_fds[n][0] = NULL;
377d4afb5ceSopenharmony_ci		lsp->pipe_fds[n][1] = NULL;
378d4afb5ceSopenharmony_ci	}
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci	/* create pipes for [stdin|stdout] and [stderr] */
381d4afb5ceSopenharmony_ci
382d4afb5ceSopenharmony_ci	memset(&sa, 0, sizeof(sa));
383d4afb5ceSopenharmony_ci	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
384d4afb5ceSopenharmony_ci	sa.bInheritHandle = TRUE; /* inherit the pipes */
385d4afb5ceSopenharmony_ci	sa.lpSecurityDescriptor = NULL;
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++) {
388d4afb5ceSopenharmony_ci		DWORD waitmode = PIPE_NOWAIT;
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci		if (!CreatePipe(&lsp->pipe_fds[n][0], &lsp->pipe_fds[n][1],
391d4afb5ceSopenharmony_ci				&sa, 0)) {
392d4afb5ceSopenharmony_ci			lwsl_err("%s: CreatePipe() failed\n", __func__);
393d4afb5ceSopenharmony_ci			goto bail1;
394d4afb5ceSopenharmony_ci		}
395d4afb5ceSopenharmony_ci
396d4afb5ceSopenharmony_ci		SetNamedPipeHandleState(lsp->pipe_fds[1][0], &waitmode, NULL, NULL);
397d4afb5ceSopenharmony_ci		SetNamedPipeHandleState(lsp->pipe_fds[2][0], &waitmode, NULL, NULL);
398d4afb5ceSopenharmony_ci
399d4afb5ceSopenharmony_ci		/* don't inherit the pipe side that belongs to the parent */
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci		if (!SetHandleInformation(&lsp->pipe_fds[n][!n],
402d4afb5ceSopenharmony_ci					  HANDLE_FLAG_INHERIT, 0)) {
403d4afb5ceSopenharmony_ci			lwsl_err("%s: SetHandleInformation() failed\n", __func__);
404d4afb5ceSopenharmony_ci			//goto bail1;
405d4afb5ceSopenharmony_ci		}
406d4afb5ceSopenharmony_ci	}
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	/* create wsis for each stdin/out/err fd */
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++) {
411d4afb5ceSopenharmony_ci		lsp->stdwsi[n] = lws_create_basic_wsi(i->vh->context, i->tsi,
412d4afb5ceSopenharmony_ci					  i->ops ? i->ops : &role_ops_raw_file);
413d4afb5ceSopenharmony_ci		if (!lsp->stdwsi[n]) {
414d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to create lsp stdwsi\n", __func__);
415d4afb5ceSopenharmony_ci			goto bail2;
416d4afb5ceSopenharmony_ci		}
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci                __lws_lc_tag(i->vh->context, &i->vh->context->lcg[LWSLCG_WSI],
419d4afb5ceSopenharmony_ci                	     &lsp->stdwsi[n]->lc, "nspawn-stdwsi-%d", n);
420d4afb5ceSopenharmony_ci
421d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->lsp_channel = n;
422d4afb5ceSopenharmony_ci		lws_vhost_bind_wsi(i->vh, lsp->stdwsi[n]);
423d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->a.protocol = pcol;
424d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->a.opaque_user_data = i->opaque;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!n];
427d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->file_desc = 1;
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci		lwsl_debug("%s: lsp stdwsi %p: pipe idx %d -> fd %d / %d\n",
430d4afb5ceSopenharmony_ci			   __func__, lsp->stdwsi[n], n,
431d4afb5ceSopenharmony_ci			   lsp->pipe_fds[n][!!(n == 0)],
432d4afb5ceSopenharmony_ci			   lsp->pipe_fds[n][!(n == 0)]);
433d4afb5ceSopenharmony_ci
434d4afb5ceSopenharmony_ci#if 0
435d4afb5ceSopenharmony_ci
436d4afb5ceSopenharmony_ci		/* read side is 0, stdin we want the write side, others read */
437d4afb5ceSopenharmony_ci
438d4afb5ceSopenharmony_ci		lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!!(n == 0)];
439d4afb5ceSopenharmony_ci		if (fcntl(lsp->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) {
440d4afb5ceSopenharmony_ci			lwsl_err("%s: setting NONBLOCK failed\n", __func__);
441d4afb5ceSopenharmony_ci			goto bail2;
442d4afb5ceSopenharmony_ci		}
443d4afb5ceSopenharmony_ci#endif
444d4afb5ceSopenharmony_ci	}
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++)
447d4afb5ceSopenharmony_ci		if (i->opt_parent) {
448d4afb5ceSopenharmony_ci			lsp->stdwsi[n]->parent = i->opt_parent;
449d4afb5ceSopenharmony_ci			lsp->stdwsi[n]->sibling_list = i->opt_parent->child_list;
450d4afb5ceSopenharmony_ci			i->opt_parent->child_list = lsp->stdwsi[n];
451d4afb5ceSopenharmony_ci		}
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci	lwsl_notice("%s: pipe handles in %p, out %p, err %p\n", __func__,
454d4afb5ceSopenharmony_ci		   lsp->stdwsi[LWS_STDIN]->desc.sockfd,
455d4afb5ceSopenharmony_ci		   lsp->stdwsi[LWS_STDOUT]->desc.sockfd,
456d4afb5ceSopenharmony_ci		   lsp->stdwsi[LWS_STDERR]->desc.sockfd);
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_ci	/*
459d4afb5ceSopenharmony_ci	 * Windows nonblocking pipe handling is a mess that is unable
460d4afb5ceSopenharmony_ci	 * to interoperate with WSA-based wait as far as I can tell.
461d4afb5ceSopenharmony_ci	 *
462d4afb5ceSopenharmony_ci	 * Let's set up a sul to poll the pipes and synthesize the
463d4afb5ceSopenharmony_ci	 * protocol callbacks if anything coming.
464d4afb5ceSopenharmony_ci	 */
465d4afb5ceSopenharmony_ci	lws_sul_schedule(context, 0, &lsp->sul_poll, windows_pipe_poll_hack,
466d4afb5ceSopenharmony_ci			 50 * LWS_US_PER_MS);
467d4afb5ceSopenharmony_ci
468d4afb5ceSopenharmony_ci
469d4afb5ceSopenharmony_ci	/*
470d4afb5ceSopenharmony_ci	 * Windows wants a single string commandline
471d4afb5ceSopenharmony_ci	 */
472d4afb5ceSopenharmony_ci	p = cli;
473d4afb5ceSopenharmony_ci	n = 0;
474d4afb5ceSopenharmony_ci	while (i->exec_array[n]) {
475d4afb5ceSopenharmony_ci		lws_strncpy(p, i->exec_array[n],
476d4afb5ceSopenharmony_ci			    sizeof(cli) - lws_ptr_diff(p, cli));
477d4afb5ceSopenharmony_ci		if (sizeof(cli) - lws_ptr_diff(p, cli) < 4)
478d4afb5ceSopenharmony_ci			break;
479d4afb5ceSopenharmony_ci		p += strlen(p);
480d4afb5ceSopenharmony_ci		*p++ = ' ';
481d4afb5ceSopenharmony_ci		*p = '\0';
482d4afb5ceSopenharmony_ci		n++;
483d4afb5ceSopenharmony_ci	}
484d4afb5ceSopenharmony_ci
485d4afb5ceSopenharmony_ci	puts(cli);
486d4afb5ceSopenharmony_ci
487d4afb5ceSopenharmony_ci	memset(&pi, 0, sizeof(pi));
488d4afb5ceSopenharmony_ci	memset(&si, 0, sizeof(si));
489d4afb5ceSopenharmony_ci
490d4afb5ceSopenharmony_ci	si.cb		= sizeof(STARTUPINFO);
491d4afb5ceSopenharmony_ci	si.hStdInput	= lsp->pipe_fds[LWS_STDIN][0];
492d4afb5ceSopenharmony_ci	si.hStdOutput	= lsp->pipe_fds[LWS_STDOUT][1];
493d4afb5ceSopenharmony_ci	si.hStdError	= lsp->pipe_fds[LWS_STDERR][1];
494d4afb5ceSopenharmony_ci	si.dwFlags	= STARTF_USESTDHANDLES | CREATE_NO_WINDOW;
495d4afb5ceSopenharmony_ci	si.wShowWindow	= TRUE;
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci	if (!CreateProcess(NULL, cli, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
498d4afb5ceSopenharmony_ci		lwsl_err("%s: CreateProcess failed 0x%x\n", __func__,
499d4afb5ceSopenharmony_ci				(unsigned long)GetLastError());
500d4afb5ceSopenharmony_ci		goto bail3;
501d4afb5ceSopenharmony_ci	}
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ci	lsp->child_pid = pi.hProcess;
504d4afb5ceSopenharmony_ci
505d4afb5ceSopenharmony_ci	lwsl_notice("%s: lsp %p spawned PID %d\n", __func__, lsp, lsp->child_pid);
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	lws_sul_schedule(context, i->tsi, &lsp->sul, lws_spawn_timeout,
508d4afb5ceSopenharmony_ci			 i->timeout_us ? i->timeout_us : 300 * LWS_US_PER_SEC);
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_ci	/*
511d4afb5ceSopenharmony_ci	 *  close:                stdin:r, stdout:w, stderr:w
512d4afb5ceSopenharmony_ci	 */
513d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++)
514d4afb5ceSopenharmony_ci		CloseHandle(lsp->pipe_fds[n][n != 0]);
515d4afb5ceSopenharmony_ci
516d4afb5ceSopenharmony_ci	lsp->pipes_alive = 3;
517d4afb5ceSopenharmony_ci	lsp->created = lws_now_usecs();
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci	if (i->owner)
520d4afb5ceSopenharmony_ci		lws_dll2_add_head(&lsp->dll, i->owner);
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci	if (i->timeout_us)
523d4afb5ceSopenharmony_ci		lws_sul_schedule(context, i->tsi, &lsp->sul,
524d4afb5ceSopenharmony_ci				 lws_spawn_timeout, i->timeout_us);
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci	return lsp;
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_cibail3:
529d4afb5ceSopenharmony_ci
530d4afb5ceSopenharmony_ci	lws_sul_cancel(&lsp->sul_poll);
531d4afb5ceSopenharmony_ci
532d4afb5ceSopenharmony_ci	while (--n >= 0)
533d4afb5ceSopenharmony_ci		__remove_wsi_socket_from_fds(lsp->stdwsi[n]);
534d4afb5ceSopenharmony_cibail2:
535d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++)
536d4afb5ceSopenharmony_ci		if (lsp->stdwsi[n])
537d4afb5ceSopenharmony_ci			__lws_free_wsi(lsp->stdwsi[n]);
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_cibail1:
540d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++) {
541d4afb5ceSopenharmony_ci		if (lsp->pipe_fds[n][0] >= 0)
542d4afb5ceSopenharmony_ci			CloseHandle(lsp->pipe_fds[n][0]);
543d4afb5ceSopenharmony_ci		if (lsp->pipe_fds[n][1] >= 0)
544d4afb5ceSopenharmony_ci			CloseHandle(lsp->pipe_fds[n][1]);
545d4afb5ceSopenharmony_ci	}
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci	lws_free(lsp);
548d4afb5ceSopenharmony_ci
549d4afb5ceSopenharmony_ci	lwsl_err("%s: failed\n", __func__);
550d4afb5ceSopenharmony_ci
551d4afb5ceSopenharmony_ci	return NULL;
552d4afb5ceSopenharmony_ci}
553d4afb5ceSopenharmony_ci
554d4afb5ceSopenharmony_civoid
555d4afb5ceSopenharmony_cilws_spawn_stdwsi_closed(struct lws_spawn_piped *lsp, struct lws *wsi)
556d4afb5ceSopenharmony_ci{
557d4afb5ceSopenharmony_ci	int n;
558d4afb5ceSopenharmony_ci
559d4afb5ceSopenharmony_ci	assert(lsp);
560d4afb5ceSopenharmony_ci	lsp->pipes_alive--;
561d4afb5ceSopenharmony_ci	lwsl_debug("%s: pipes alive %d\n", __func__, lsp->pipes_alive);
562d4afb5ceSopenharmony_ci	if (!lsp->pipes_alive)
563d4afb5ceSopenharmony_ci		lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
564d4afb5ceSopenharmony_ci				&lsp->sul_reap, lws_spawn_sul_reap, 1);
565d4afb5ceSopenharmony_ci
566d4afb5ceSopenharmony_ci	for (n = 0; n < 3; n++)
567d4afb5ceSopenharmony_ci		if (lsp->stdwsi[n] == wsi)
568d4afb5ceSopenharmony_ci			lsp->stdwsi[n] = NULL;
569d4afb5ceSopenharmony_ci}
570d4afb5ceSopenharmony_ci
571d4afb5ceSopenharmony_ciint
572d4afb5ceSopenharmony_cilws_spawn_get_stdfd(struct lws *wsi)
573d4afb5ceSopenharmony_ci{
574d4afb5ceSopenharmony_ci	return wsi->lsp_channel;
575d4afb5ceSopenharmony_ci}
576