dcerpc-nt: add UNION_ALIGN_TO... helpers
[wireshark-sm.git] / wsutil / ws_pipe.c
blob2add60a9ef72b3011d89cfa44eabeb74c875e9b6
1 /* ws_pipe.c
3 * Routines for handling pipes.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <config.h>
13 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
14 #include "wsutil/ws_pipe.h"
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #ifdef _WIN32
21 #include <windows.h>
22 #include <io.h>
23 #include <fcntl.h> /* for _O_BINARY */
24 #include <wsutil/win32-utils.h>
25 #else
26 #include <unistd.h>
27 #ifdef HAVE_SYS_SELECT_H
28 #include <sys/select.h>
29 #endif
30 #endif
32 #if !GLIB_CHECK_VERSION(2, 58, 2)
33 #ifdef __linux__
34 #define HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
35 #include <fcntl.h>
36 #include <sys/syscall.h> /* for syscall and SYS_getdents64 */
37 #include <wsutil/file_util.h> /* for ws_open -> open to pacify checkAPIs.pl */
38 #endif
39 #endif
41 #include "wsutil/filesystem.h"
42 #include "wsutil/wslog.h"
44 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
45 struct linux_dirent64 {
46 uint64_t d_ino; /* 64-bit inode number */
47 uint64_t d_off; /* 64-bit offset to next structure */
48 unsigned short d_reclen; /* Size of this dirent */
49 unsigned char d_type; /* File type */
50 char d_name[]; /* Filename (null-terminated) */
53 /* Async-signal-safe string to integer conversion. */
54 static int
55 filename_to_fd(const char *p)
57 char c;
58 int fd = 0;
59 const int cutoff = INT_MAX / 10;
60 const int cutlim = INT_MAX % 10;
62 if (*p == '\0')
63 return -1;
65 while ((c = *p++) != '\0') {
66 if (!g_ascii_isdigit(c))
67 return -1;
68 c -= '0';
70 /* Check for overflow. */
71 if (fd > cutoff || (fd == cutoff && c > cutlim))
72 return -1;
74 fd = fd * 10 + c;
77 return fd;
80 static void
81 close_non_standard_fds_linux(void * user_data _U_)
84 * GLib 2.14.2 and newer (up to at least GLib 2.58.1) on Linux with multiple
85 * threads can deadlock in the child process due to use of opendir (which
86 * is not async-signal-safe). To avoid this, disable the broken code path
87 * and manually close file descriptors using async-signal-safe code only.
88 * Use CLOEXEC to allow reporting of execve errors to the parent via a pipe.
89 * https://gitlab.gnome.org/GNOME/glib/issues/1014
90 * https://gitlab.gnome.org/GNOME/glib/merge_requests/490
92 int dir_fd = ws_open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
93 if (dir_fd >= 0) {
94 char buf[4096];
95 int nread, fd;
96 struct linux_dirent64 *de;
98 while ((nread = (int) syscall(SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0) {
99 for (int pos = 0; pos < nread; pos += de->d_reclen) {
100 de = (struct linux_dirent64 *)(buf + pos);
101 fd = filename_to_fd(de->d_name);
102 if (fd > STDERR_FILENO && fd != dir_fd) {
103 /* Close all other (valid) file descriptors above stderr. */
104 fcntl(fd, F_SETFD, FD_CLOEXEC);
109 close(dir_fd);
110 } else {
111 /* Slow fallback in case /proc is not mounted */
112 for (int fd = STDERR_FILENO + 1; fd < getdtablesize(); fd++) {
113 fcntl(fd, F_SETFD, FD_CLOEXEC);
117 #endif
119 #ifdef _WIN32
120 static ULONG pipe_serial_number;
122 /* Alternative for CreatePipe() where read handle is opened with FILE_FLAG_OVERLAPPED */
123 static bool
124 ws_pipe_create_overlapped_read(HANDLE *read_pipe_handle, HANDLE *write_pipe_handle,
125 SECURITY_ATTRIBUTES *sa, DWORD suggested_buffer_size)
127 HANDLE read_pipe, write_pipe;
128 unsigned char *name = ws_strdup_printf("\\\\.\\Pipe\\WiresharkWsPipe.%08lx.%08lx",
129 GetCurrentProcessId(),
130 InterlockedIncrement(&pipe_serial_number));
131 gunichar2 *wname = g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
133 g_free(name);
135 read_pipe = CreateNamedPipe(wname, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
136 PIPE_TYPE_BYTE | PIPE_WAIT, 1,
137 suggested_buffer_size, suggested_buffer_size,
138 0, sa);
139 if (INVALID_HANDLE_VALUE == read_pipe)
141 g_free(wname);
142 return false;
145 write_pipe = CreateFile(wname, GENERIC_WRITE, 0, sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
146 if (INVALID_HANDLE_VALUE == write_pipe)
148 DWORD error = GetLastError();
149 CloseHandle(read_pipe);
150 SetLastError(error);
151 g_free(wname);
152 return false;
155 *read_pipe_handle = read_pipe;
156 *write_pipe_handle = write_pipe;
157 g_free(wname);
158 return true;
160 #endif
163 * Helper to convert a command and argument list to an NULL-terminated 'argv'
164 * array, suitable for g_spawn_sync and friends. Free with g_strfreev.
166 static char **
167 convert_to_argv(const char *command, int args_count, char *const *args)
169 char **argv = g_new(char *, args_count + 2);
170 // The caller does not seem to modify this, but g_spawn_sync uses 'char **'
171 // as opposed to 'const char **', so just to be sure clone it.
172 argv[0] = g_strdup(command);
173 for (int i = 0; i < args_count; i++) {
174 // Empty arguments may indicate a bug in Wireshark. Extcap for example
175 // omits arguments when their string value is empty. On Windows, empty
176 // arguments would silently be ignored because protect_arg returns an
177 // empty string, therefore we print a warning here.
178 if (!*args[i]) {
179 ws_warning("Empty argument %d in arguments list", i);
181 argv[1 + i] = g_strdup(args[i]);
183 argv[args_count + 1] = NULL;
184 return argv;
188 * Convert a non-empty NULL-terminated array of command and arguments to a
189 * string for displaying purposes. On Windows, the returned string is properly
190 * escaped and can be executed directly.
192 static char *
193 convert_to_command_line(char **argv)
195 GString *command_line = g_string_sized_new(200);
196 #ifdef _WIN32
197 // The first argument must always be quoted even if it does not contain
198 // special characters or else CreateProcess might consider arguments as part
199 // of the executable.
200 char *quoted_arg = protect_arg(argv[0]);
201 if (quoted_arg[0] != '"') {
202 g_string_append_c(command_line, '"');
203 g_string_append(command_line, quoted_arg);
204 g_string_append_c(command_line, '"');
205 } else {
206 g_string_append(command_line, quoted_arg);
208 g_free(quoted_arg);
210 for (int i = 1; argv[i]; i++) {
211 quoted_arg = protect_arg(argv[i]);
212 g_string_append_c(command_line, ' ');
213 g_string_append(command_line, quoted_arg);
214 g_free(quoted_arg);
216 #else
217 for (int i = 0; argv[i]; i++) {
218 char *quoted_arg = g_shell_quote(argv[i]);
219 if (i != 0) {
220 g_string_append_c(command_line, ' ');
222 g_string_append(command_line, quoted_arg);
223 g_free(quoted_arg);
225 #endif
226 return g_string_free(command_line, FALSE);
229 bool ws_pipe_spawn_sync(const char *working_directory, const char *command, int argc, char **args, char **command_output)
231 bool status = false;
232 bool result = false;
233 char *local_output = NULL;
234 #ifdef _WIN32
236 #define BUFFER_SIZE 16384
238 STARTUPINFO info;
239 PROCESS_INFORMATION processInfo;
241 SECURITY_ATTRIBUTES sa;
242 HANDLE child_stdout_rd = NULL;
243 HANDLE child_stdout_wr = NULL;
244 HANDLE child_stderr_rd = NULL;
245 HANDLE child_stderr_wr = NULL;
246 HANDLE inherit_handles[2];
248 OVERLAPPED stdout_overlapped;
249 OVERLAPPED stderr_overlapped;
250 #else
251 int exit_status = 0;
252 #endif
254 char **argv = convert_to_argv(command, argc, args);
255 char *command_line = convert_to_command_line(argv);
257 ws_debug("command line: %s", command_line);
259 uint64_t start_time = g_get_monotonic_time();
261 #ifdef _WIN32
262 /* Setup overlapped structures. Create Manual Reset events, initially not signalled */
263 memset(&stdout_overlapped, 0, sizeof(OVERLAPPED));
264 memset(&stderr_overlapped, 0, sizeof(OVERLAPPED));
265 stdout_overlapped.hEvent = CreateEvent(NULL, true, false, NULL);
266 if (!stdout_overlapped.hEvent)
268 g_free(command_line);
269 g_strfreev(argv);
270 ws_debug("Could not create stdout overlapped event");
271 return false;
273 stderr_overlapped.hEvent = CreateEvent(NULL, true, false, NULL);
274 if (!stderr_overlapped.hEvent)
276 CloseHandle(stdout_overlapped.hEvent);
277 g_free(command_line);
278 g_strfreev(argv);
279 ws_debug("Could not create stderr overlapped event");
280 return false;
283 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
284 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
285 sa.bInheritHandle = false;
286 sa.lpSecurityDescriptor = NULL;
288 if (!ws_pipe_create_overlapped_read(&child_stdout_rd, &child_stdout_wr, &sa, 0))
290 CloseHandle(stdout_overlapped.hEvent);
291 CloseHandle(stderr_overlapped.hEvent);
292 g_free(command_line);
293 g_strfreev(argv);
294 ws_debug("Could not create stdout handle");
295 return false;
298 if (!ws_pipe_create_overlapped_read(&child_stderr_rd, &child_stderr_wr, &sa, 0))
300 CloseHandle(stdout_overlapped.hEvent);
301 CloseHandle(stderr_overlapped.hEvent);
302 CloseHandle(child_stdout_rd);
303 CloseHandle(child_stdout_wr);
304 g_free(command_line);
305 g_strfreev(argv);
306 ws_debug("Could not create stderr handle");
307 return false;
310 inherit_handles[0] = child_stderr_wr;
311 inherit_handles[1] = child_stdout_wr;
313 memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
314 memset(&info, 0, sizeof(STARTUPINFO));
316 info.cb = sizeof(STARTUPINFO);
317 info.hStdError = child_stderr_wr;
318 info.hStdOutput = child_stdout_wr;
319 info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
320 info.wShowWindow = SW_HIDE;
322 if (win32_create_process(NULL, command_line, NULL, NULL, G_N_ELEMENTS(inherit_handles), inherit_handles,
323 CREATE_NEW_CONSOLE, NULL, working_directory, &info, &processInfo))
325 char* stdout_buffer = (char*)g_malloc(BUFFER_SIZE);
326 char* stderr_buffer = (char*)g_malloc(BUFFER_SIZE);
327 DWORD dw;
328 DWORD bytes_read;
329 GString *output_string = g_string_new(NULL);
330 bool process_finished = false;
331 bool pending_stdout = true;
332 bool pending_stderr = true;
334 /* Start asynchronous reads from child process stdout and stderr */
335 if (!ReadFile(child_stdout_rd, stdout_buffer, BUFFER_SIZE, NULL, &stdout_overlapped))
337 if (GetLastError() != ERROR_IO_PENDING)
339 ws_debug("ReadFile on child stdout pipe failed. Error %ld", GetLastError());
340 pending_stdout = false;
344 if (!ReadFile(child_stderr_rd, stderr_buffer, BUFFER_SIZE, NULL, &stderr_overlapped))
346 if (GetLastError() != ERROR_IO_PENDING)
348 ws_debug("ReadFile on child stderr pipe failed. Error %ld", GetLastError());
349 pending_stderr = false;
353 for (;;)
355 HANDLE handles[3];
356 DWORD n_handles = 0;
357 if (!process_finished)
359 handles[n_handles++] = processInfo.hProcess;
361 if (pending_stdout)
363 handles[n_handles++] = stdout_overlapped.hEvent;
365 if (pending_stderr)
367 handles[n_handles++] = stderr_overlapped.hEvent;
370 if (!n_handles)
372 /* No more things to wait */
373 break;
376 dw = WaitForMultipleObjects(n_handles, handles, false, INFINITE);
377 if (dw < (WAIT_OBJECT_0 + n_handles))
379 int i = dw - WAIT_OBJECT_0;
380 if (handles[i] == processInfo.hProcess)
382 /* Process finished but there might still be unread data in the pipe.
383 * Close the write pipes, so ReadFile does not wait indefinitely.
385 CloseHandle(child_stdout_wr);
386 CloseHandle(child_stderr_wr);
387 process_finished = true;
389 else if (handles[i] == stdout_overlapped.hEvent)
391 bytes_read = 0;
392 if (!GetOverlappedResult(child_stdout_rd, &stdout_overlapped, &bytes_read, true))
394 if (GetLastError() == ERROR_BROKEN_PIPE)
396 pending_stdout = false;
397 continue;
399 ws_debug("GetOverlappedResult on stdout failed. Error %ld", GetLastError());
401 if (process_finished && (bytes_read == 0))
403 /* We have drained the pipe and there isn't any process that holds active write handle to the pipe. */
404 pending_stdout = false;
405 continue;
407 g_string_append_len(output_string, stdout_buffer, bytes_read);
408 if (!ReadFile(child_stdout_rd, stdout_buffer, BUFFER_SIZE, NULL, &stdout_overlapped))
410 if (GetLastError() != ERROR_IO_PENDING)
412 ws_debug("ReadFile on child stdout pipe failed. Error %ld", GetLastError());
413 pending_stdout = false;
417 else if (handles[i] == stderr_overlapped.hEvent)
419 /* Discard the stderr data just like non-windows version of this function does. */
420 bytes_read = 0;
421 if (!GetOverlappedResult(child_stderr_rd, &stderr_overlapped, &bytes_read, true))
423 if (GetLastError() == ERROR_BROKEN_PIPE)
425 pending_stderr = false;
426 continue;
428 ws_debug("GetOverlappedResult on stderr failed. Error %ld", GetLastError());
430 if (process_finished && (bytes_read == 0))
432 pending_stderr = false;
433 continue;
435 if (!ReadFile(child_stderr_rd, stderr_buffer, BUFFER_SIZE, NULL, &stderr_overlapped))
437 if (GetLastError() != ERROR_IO_PENDING)
439 ws_debug("ReadFile on child stderr pipe failed. Error %ld", GetLastError());
440 pending_stderr = false;
445 else
447 ws_debug("WaitForMultipleObjects returned 0x%08lX. Error %ld", dw, GetLastError());
451 g_free(stdout_buffer);
452 g_free(stderr_buffer);
454 status = GetExitCodeProcess(processInfo.hProcess, &dw);
455 if (status && dw != 0)
457 status = false;
460 local_output = g_string_free(output_string, FALSE);
462 CloseHandle(child_stdout_rd);
463 CloseHandle(child_stderr_rd);
465 CloseHandle(processInfo.hProcess);
466 CloseHandle(processInfo.hThread);
468 else
470 status = false;
472 CloseHandle(child_stdout_rd);
473 CloseHandle(child_stdout_wr);
474 CloseHandle(child_stderr_rd);
475 CloseHandle(child_stderr_wr);
478 CloseHandle(stdout_overlapped.hEvent);
479 CloseHandle(stderr_overlapped.hEvent);
480 #else
482 GSpawnFlags flags = (GSpawnFlags)0;
483 GSpawnChildSetupFunc child_setup = NULL;
484 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
485 flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
486 child_setup = close_non_standard_fds_linux;
487 #endif
488 status = g_spawn_sync(working_directory, argv, NULL,
489 flags, child_setup, NULL, &local_output, NULL, &exit_status, NULL);
491 if (status && exit_status != 0)
492 status = false;
493 #endif
495 ws_debug("%s finished in %.3fms", argv[0], (g_get_monotonic_time() - start_time) / 1000.0);
497 if (status)
499 if (local_output != NULL) {
500 ws_noisy("spawn output: %s", local_output);
501 if (command_output != NULL)
502 *command_output = g_strdup(local_output);
504 result = true;
507 g_free(local_output);
508 g_free(command_line);
509 g_strfreev(argv);
511 return result;
514 void ws_pipe_init(ws_pipe_t *ws_pipe)
516 if (!ws_pipe) return;
517 memset(ws_pipe, 0, sizeof(ws_pipe_t));
518 ws_pipe->pid = WS_INVALID_PID;
521 GPid ws_pipe_spawn_async(ws_pipe_t *ws_pipe, GPtrArray *args)
523 GPid pid = WS_INVALID_PID;
524 int stdin_fd, stdout_fd, stderr_fd;
525 #ifdef _WIN32
526 STARTUPINFO info;
527 PROCESS_INFORMATION processInfo;
529 SECURITY_ATTRIBUTES sa;
530 HANDLE child_stdin_rd = NULL;
531 HANDLE child_stdin_wr = NULL;
532 HANDLE child_stdout_rd = NULL;
533 HANDLE child_stdout_wr = NULL;
534 HANDLE child_stderr_rd = NULL;
535 HANDLE child_stderr_wr = NULL;
536 HANDLE inherit_handles[3];
537 #endif
539 // XXX harmonize handling of command arguments for the sync/async functions
540 // and make them const? This array ends with a trailing NULL by the way.
541 char **args_array = (char **)args->pdata;
542 char **argv = convert_to_argv(args_array[0], args->len - 2, args_array + 1);
543 char *command_line = convert_to_command_line(argv);
545 ws_debug("command line: %s", command_line);
547 #ifdef _WIN32
548 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
549 sa.bInheritHandle = false;
550 sa.lpSecurityDescriptor = NULL;
552 if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &sa, 0))
554 g_free(command_line);
555 g_strfreev(argv);
556 ws_debug("Could not create stdin handle");
557 return WS_INVALID_PID;
560 if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
562 CloseHandle(child_stdin_rd);
563 CloseHandle(child_stdin_wr);
564 g_free(command_line);
565 g_strfreev(argv);
566 ws_debug("Could not create stdout handle");
567 return WS_INVALID_PID;
570 if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
572 CloseHandle(child_stdin_rd);
573 CloseHandle(child_stdin_wr);
574 CloseHandle(child_stdout_rd);
575 CloseHandle(child_stdout_wr);
576 g_free(command_line);
577 g_strfreev(argv);
578 ws_debug("Could not create stderr handle");
579 return WS_INVALID_PID;
582 inherit_handles[0] = child_stdin_rd;
583 inherit_handles[1] = child_stderr_wr;
584 inherit_handles[2] = child_stdout_wr;
586 memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
587 memset(&info, 0, sizeof(STARTUPINFO));
589 info.cb = sizeof(STARTUPINFO);
590 info.hStdInput = child_stdin_rd;
591 info.hStdError = child_stderr_wr;
592 info.hStdOutput = child_stdout_wr;
593 info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
594 info.wShowWindow = SW_HIDE;
596 if (win32_create_process(NULL, command_line, NULL, NULL, G_N_ELEMENTS(inherit_handles), inherit_handles,
597 CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
599 stdin_fd = _open_osfhandle((intptr_t)(child_stdin_wr), _O_BINARY);
600 stdout_fd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
601 stderr_fd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
602 pid = processInfo.hProcess;
603 CloseHandle(processInfo.hThread);
605 else
607 CloseHandle(child_stdin_wr);
608 CloseHandle(child_stdout_rd);
609 CloseHandle(child_stderr_rd);
612 /* We no longer need other (child) end of pipes. The child process holds
613 * its own handles that will be closed on process exit. However, we have
614 * to close *our* handles as otherwise read() on stdout_fd and stderr_fd
615 * will block indefinitely after the process exits.
617 CloseHandle(child_stdin_rd);
618 CloseHandle(child_stdout_wr);
619 CloseHandle(child_stderr_wr);
620 #else
622 GError *error = NULL;
623 GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD;
624 GSpawnChildSetupFunc child_setup = NULL;
625 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
626 flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
627 child_setup = close_non_standard_fds_linux;
628 #endif
629 bool spawned = g_spawn_async_with_pipes(NULL, argv, NULL,
630 flags, child_setup, NULL,
631 &pid, &stdin_fd, &stdout_fd, &stderr_fd, &error);
632 if (!spawned) {
633 ws_debug("Error creating async pipe: %s", error->message);
634 g_free(error->message);
636 #endif
638 g_free(command_line);
639 g_strfreev(argv);
641 ws_pipe->pid = pid;
643 if (pid != WS_INVALID_PID) {
644 #ifdef _WIN32
645 ws_pipe->stdin_io = g_io_channel_win32_new_fd(stdin_fd);
646 ws_pipe->stdout_io = g_io_channel_win32_new_fd(stdout_fd);
647 ws_pipe->stderr_io = g_io_channel_win32_new_fd(stderr_fd);
648 #else
649 ws_pipe->stdin_io = g_io_channel_unix_new(stdin_fd);
650 ws_pipe->stdout_io = g_io_channel_unix_new(stdout_fd);
651 ws_pipe->stderr_io = g_io_channel_unix_new(stderr_fd);
652 #endif
653 g_io_channel_set_encoding(ws_pipe->stdin_io, NULL, NULL);
654 g_io_channel_set_encoding(ws_pipe->stdout_io, NULL, NULL);
655 g_io_channel_set_encoding(ws_pipe->stderr_io, NULL, NULL);
656 g_io_channel_set_buffered(ws_pipe->stdin_io, false);
657 g_io_channel_set_buffered(ws_pipe->stdout_io, false);
658 g_io_channel_set_buffered(ws_pipe->stderr_io, false);
659 g_io_channel_set_close_on_unref(ws_pipe->stdin_io, true);
660 g_io_channel_set_close_on_unref(ws_pipe->stdout_io, true);
661 g_io_channel_set_close_on_unref(ws_pipe->stderr_io, true);
664 return pid;
667 #ifdef _WIN32
669 typedef struct
671 HANDLE pipeHandle;
672 OVERLAPPED ol;
673 BOOL pendingIO;
674 } PIPEINTS;
676 bool
677 ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
679 PIPEINTS pipeinsts[3];
680 HANDLE handles[4];
681 bool result = true;
683 SecureZeroMemory(pipeinsts, sizeof(pipeinsts));
685 if (num_pipe_handles == 0 || num_pipe_handles > 3)
687 ws_debug("Invalid number of pipes given as argument.");
688 return false;
691 for (int i = 0; i < num_pipe_handles; ++i)
693 pipeinsts[i].ol.hEvent = CreateEvent(NULL, true, false, NULL);
694 if (!pipeinsts[i].ol.hEvent)
696 ws_debug("Could not create overlapped event");
697 for (int j = 0; j < i; j++)
699 CloseHandle(pipeinsts[j].ol.hEvent);
701 return false;
705 for (int i = 0; i < num_pipe_handles; ++i)
707 pipeinsts[i].pipeHandle = pipe_handles[i];
708 pipeinsts[i].ol.Pointer = 0;
709 pipeinsts[i].pendingIO = false;
710 if (!ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol))
712 DWORD error = GetLastError();
713 switch (error)
715 case ERROR_IO_PENDING:
716 pipeinsts[i].pendingIO = true;
717 break;
719 case ERROR_PIPE_CONNECTED:
720 SetEvent(pipeinsts[i].ol.hEvent);
721 break;
723 default:
724 ws_debug("ConnectNamedPipe failed with %ld\n.", error);
725 result = false;
730 while (result)
732 DWORD dw;
733 int num_handles = 0;
734 for (int i = 0; i < num_pipe_handles; ++i)
736 if (pipeinsts[i].pendingIO)
738 handles[num_handles] = pipeinsts[i].ol.hEvent;
739 num_handles++;
742 if (num_handles == 0)
744 /* All pipes have been successfully connected */
745 break;
747 /* Wait for process in case it exits before the pipes have connected */
748 handles[num_handles] = pid;
749 num_handles++;
751 dw = WaitForMultipleObjects(num_handles, handles, false, 30000);
752 int handle_idx = dw - WAIT_OBJECT_0;
753 if (dw == WAIT_TIMEOUT)
755 ws_debug("extcap didn't connect to pipe within 30 seconds.");
756 result = false;
757 break;
759 // If index points to our handles array
760 else if (handle_idx >= 0 && handle_idx < num_handles)
762 if (handles[handle_idx] == pid)
764 ws_debug("extcap terminated without connecting to pipe.");
765 result = false;
767 for (int i = 0; i < num_pipe_handles; ++i)
769 if (handles[handle_idx] == pipeinsts[i].ol.hEvent)
771 DWORD cbRet;
772 BOOL success = GetOverlappedResult(
773 pipeinsts[i].pipeHandle, // handle to pipe
774 &pipeinsts[i].ol, // OVERLAPPED structure
775 &cbRet, // bytes transferred
776 true); // wait
777 if (!success)
779 ws_debug("Error %ld \n.", GetLastError());
780 result = false;
782 pipeinsts[i].pendingIO = false;
786 else
788 ws_debug("WaitForMultipleObjects returned 0x%08lX. Error %ld", dw, GetLastError());
789 result = false;
793 for (int i = 0; i < num_pipe_handles; ++i)
795 if (pipeinsts[i].pendingIO)
797 CancelIoEx(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
798 WaitForSingleObject(pipeinsts[i].ol.hEvent, INFINITE);
800 CloseHandle(pipeinsts[i].ol.hEvent);
803 return result;
805 #endif
807 bool
808 ws_pipe_data_available(int pipe_fd)
810 #ifdef _WIN32 /* PeekNamedPipe */
811 HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
812 DWORD bytes_avail;
814 if (hPipe == INVALID_HANDLE_VALUE)
816 return false;
819 if (! PeekNamedPipe(hPipe, NULL, 0, NULL, &bytes_avail, NULL))
821 return false;
824 if (bytes_avail > 0)
826 return true;
828 return false;
829 #else /* select */
830 fd_set rfds;
831 struct timeval timeout;
833 FD_ZERO(&rfds);
834 FD_SET(pipe_fd, &rfds);
835 timeout.tv_sec = 0;
836 timeout.tv_usec = 0;
838 if (select(pipe_fd + 1, &rfds, NULL, NULL, &timeout) > 0)
840 return true;
843 return false;
844 #endif
848 * Editor modelines - https://www.wireshark.org/tools/modelines.html
850 * Local variables:
851 * c-basic-offset: 4
852 * tab-width: 8
853 * indent-tabs-mode: nil
854 * End:
856 * vi: set shiftwidth=4 tabstop=8 expandtab:
857 * :indentSize=4:tabSize=8:noTabs=true: