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