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
13 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
14 #include "wsutil/ws_pipe.h"
23 #include <fcntl.h> /* for _O_BINARY */
24 #include <wsutil/win32-utils.h>
27 #ifdef HAVE_SYS_SELECT_H
28 #include <sys/select.h>
32 #if !GLIB_CHECK_VERSION(2, 58, 2)
34 #define HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
36 #include <sys/syscall.h> /* for syscall and SYS_getdents64 */
37 #include <wsutil/file_util.h> /* for ws_open -> open to pacify checkAPIs.pl */
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. */
55 filename_to_fd(const char *p
)
59 const int cutoff
= INT_MAX
/ 10;
60 const int cutlim
= INT_MAX
% 10;
65 while ((c
= *p
++) != '\0') {
66 if (!g_ascii_isdigit(c
))
70 /* Check for overflow. */
71 if (fd
> cutoff
|| (fd
== cutoff
&& c
> cutlim
))
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
);
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
);
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
);
120 static ULONG pipe_serial_number
;
122 /* Alternative for CreatePipe() where read handle is opened with FILE_FLAG_OVERLAPPED */
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
);
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
,
139 if (INVALID_HANDLE_VALUE
== read_pipe
)
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
);
155 *read_pipe_handle
= read_pipe
;
156 *write_pipe_handle
= write_pipe
;
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.
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.
179 ws_warning("Empty argument %d in arguments list", i
);
181 argv
[1 + i
] = g_strdup(args
[i
]);
183 argv
[args_count
+ 1] = NULL
;
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.
193 convert_to_command_line(char **argv
)
195 GString
*command_line
= g_string_sized_new(200);
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
, '"');
206 g_string_append(command_line
, 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
);
217 for (int i
= 0; argv
[i
]; i
++) {
218 char *quoted_arg
= g_shell_quote(argv
[i
]);
220 g_string_append_c(command_line
, ' ');
222 g_string_append(command_line
, quoted_arg
);
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
)
233 char *local_output
= NULL
;
236 #define BUFFER_SIZE 16384
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
;
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();
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
);
270 ws_debug("Could not create stdout overlapped event");
273 stderr_overlapped
.hEvent
= CreateEvent(NULL
, true, false, NULL
);
274 if (!stderr_overlapped
.hEvent
)
276 CloseHandle(stdout_overlapped
.hEvent
);
277 g_free(command_line
);
279 ws_debug("Could not create stderr overlapped event");
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
);
294 ws_debug("Could not create stdout handle");
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
);
306 ws_debug("Could not create stderr handle");
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
);
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;
357 if (!process_finished
)
359 handles
[n_handles
++] = processInfo
.hProcess
;
363 handles
[n_handles
++] = stdout_overlapped
.hEvent
;
367 handles
[n_handles
++] = stderr_overlapped
.hEvent
;
372 /* No more things to wait */
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
)
392 if (!GetOverlappedResult(child_stdout_rd
, &stdout_overlapped
, &bytes_read
, true))
394 if (GetLastError() == ERROR_BROKEN_PIPE
)
396 pending_stdout
= false;
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;
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. */
421 if (!GetOverlappedResult(child_stderr_rd
, &stderr_overlapped
, &bytes_read
, true))
423 if (GetLastError() == ERROR_BROKEN_PIPE
)
425 pending_stderr
= false;
428 ws_debug("GetOverlappedResult on stderr failed. Error %ld", GetLastError());
430 if (process_finished
&& (bytes_read
== 0))
432 pending_stderr
= false;
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;
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)
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
);
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
);
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
;
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)
495 ws_debug("%s finished in %.3fms", argv
[0], (g_get_monotonic_time() - start_time
) / 1000.0);
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
);
507 g_free(local_output
);
508 g_free(command_line
);
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
;
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];
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
);
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
);
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
);
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
);
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
);
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
);
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
;
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
);
633 ws_debug("Error creating async pipe: %s", error
->message
);
634 g_free(error
->message
);
638 g_free(command_line
);
643 if (pid
!= WS_INVALID_PID
) {
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
);
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
);
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);
677 ws_pipe_wait_for_pipe(HANDLE
* pipe_handles
, int num_pipe_handles
, HANDLE pid
)
679 PIPEINTS pipeinsts
[3];
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.");
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
);
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();
715 case ERROR_IO_PENDING
:
716 pipeinsts
[i
].pendingIO
= true;
719 case ERROR_PIPE_CONNECTED
:
720 SetEvent(pipeinsts
[i
].ol
.hEvent
);
724 ws_debug("ConnectNamedPipe failed with %ld\n.", error
);
734 for (int i
= 0; i
< num_pipe_handles
; ++i
)
736 if (pipeinsts
[i
].pendingIO
)
738 handles
[num_handles
] = pipeinsts
[i
].ol
.hEvent
;
742 if (num_handles
== 0)
744 /* All pipes have been successfully connected */
747 /* Wait for process in case it exits before the pipes have connected */
748 handles
[num_handles
] = pid
;
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.");
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.");
767 for (int i
= 0; i
< num_pipe_handles
; ++i
)
769 if (handles
[handle_idx
] == pipeinsts
[i
].ol
.hEvent
)
772 BOOL success
= GetOverlappedResult(
773 pipeinsts
[i
].pipeHandle
, // handle to pipe
774 &pipeinsts
[i
].ol
, // OVERLAPPED structure
775 &cbRet
, // bytes transferred
779 ws_debug("Error %ld \n.", GetLastError());
782 pipeinsts
[i
].pendingIO
= false;
788 ws_debug("WaitForMultipleObjects returned 0x%08lX. Error %ld", dw
, GetLastError());
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
);
808 ws_pipe_data_available(int pipe_fd
)
810 #ifdef _WIN32 /* PeekNamedPipe */
811 HANDLE hPipe
= (HANDLE
) _get_osfhandle(pipe_fd
);
814 if (hPipe
== INVALID_HANDLE_VALUE
)
819 if (! PeekNamedPipe(hPipe
, NULL
, 0, NULL
, &bytes_avail
, NULL
))
831 struct timeval timeout
;
834 FD_SET(pipe_fd
, &rfds
);
838 if (select(pipe_fd
+ 1, &rfds
, NULL
, NULL
, &timeout
) > 0)
848 * Editor modelines - https://www.wireshark.org/tools/modelines.html
853 * indent-tabs-mode: nil
856 * vi: set shiftwidth=4 tabstop=8 expandtab:
857 * :indentSize=4:tabSize=8:noTabs=true: