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