windows-spawn.c 14 KB

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