Bug Summary

File:capture/capture_sync.c
Warning:line 1611, column 9
Potential leak of memory pointed to by 'argv'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name capture_sync.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-20/lib/clang/20 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-08-27-100402-3933-1 -x c /builds/wireshark/wireshark/capture/capture_sync.c
1/* capture_sync.c
2 * Synchronisation between Wireshark capture parent and child instances
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12#define WS_LOG_DOMAIN"Capture" LOG_DOMAIN_CAPTURE"Capture"
13
14#include <wireshark.h>
15
16#ifdef HAVE_LIBPCAP1
17
18#include <glib.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <signal.h>
23
24#include <ws_exit_codes.h>
25
26#include <wsutil/application_flavor.h>
27#include <wsutil/strtoi.h>
28#include <wsutil/ws_assert.h>
29#include <wsutil/pint.h>
30
31#ifdef _WIN32
32#include <wsutil/unicode-utils.h>
33#include <wsutil/win32-utils.h>
34#include <wsutil/ws_pipe.h>
35#else
36#include <glib-unix1.h>
37#endif
38
39#ifdef HAVE_SYS_WAIT_H1
40# include <sys/wait.h>
41#endif
42
43#include "capture/capture-pcap-util.h"
44
45#ifndef _WIN32
46/*
47 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
48 * macros) on UNIX systems that don't have them.
49 */
50#ifndef WIFEXITED
51# define WIFEXITED(status)(((status) & 0x7f) == 0) (((status) & 0177) == 0)
52#endif
53#ifndef WIFSTOPPED
54# define WIFSTOPPED(status)(((status) & 0xff) == 0x7f) (((status) & 0177) == 0177)
55#endif
56#ifndef WIFSIGNALED
57# define WIFSIGNALED(status)(((signed char) (((status) & 0x7f) + 1) >> 1) > 0
)
(!WIFSTOPPED(status)(((status) & 0xff) == 0x7f) && !WIFEXITED(status)(((status) & 0x7f) == 0))
58#endif
59#ifndef WEXITSTATUS
60# define WEXITSTATUS(status)(((status) & 0xff00) >> 8) ((status) >> 8)
61#endif
62#ifndef WTERMSIG
63# define WTERMSIG(status)((status) & 0x7f) ((status) & 0177)
64#endif
65#ifndef WCOREDUMP
66# define WCOREDUMP(status)((status) & 0x80) ((status) & 0200)
67#endif
68#ifndef WSTOPSIG
69# define WSTOPSIG(status)(((status) & 0xff00) >> 8) ((status) >> 8)
70#endif
71#endif /* _WIN32 */
72
73#include <epan/packet.h>
74#include <epan/prefs.h>
75
76#include "file.h"
77
78#include "ui/capture.h"
79#include <capture/capture_sync.h>
80
81#include "sync_pipe.h"
82
83#ifdef _WIN32
84#include "capture/capture-wpcap.h"
85#endif
86
87#include "ui/ws_ui_util.h"
88
89#include <wsutil/filesystem.h>
90#include <wsutil/file_util.h>
91#include <wsutil/report_message.h>
92#include "extcap.h"
93
94#ifdef _WIN32
95#include <process.h> /* For spawning child process */
96#endif
97
98#include <wsutil/ws_pipe.h>
99
100#ifdef _WIN32
101static int create_dummy_signal_pipe(char **msg);
102static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
103static char *dummy_control_id;
104#else
105static const char *sync_pipe_signame(int);
106#endif
107
108/* We use this pipe buffer size for both the sync message pipe and the
109 * data pipe. Ensure that it's large enough for the indicator and header
110 * plus maximum message size.
111 */
112#define PIPE_BUF_SIZE((512 * 1000)+4) (SP_MAX_MSG_LEN(512 * 1000)+4)
113
114static gboolean sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session);
115static int sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp);
116static void pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len);
117static ssize_t pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
118 char **err_msg);
119
120static void (*fetch_dumpcap_pid)(ws_process_id);
121
122void
123capture_session_init(capture_session *cap_session, capture_file *cf,
124 new_file_fn new_file, new_packets_fn new_packets,
125 drops_fn drops, error_fn error,
126 cfilter_error_fn cfilter_error, closed_fn closed)
127{
128 cap_session->cf = cf;
129 cap_session->fork_child = WS_INVALID_PID-1; /* invalid process handle */
130 cap_session->pipe_input_id = 0;
131#ifdef _WIN32
132 cap_session->signal_pipe_write_fd = -1;
133#endif
134 cap_session->state = CAPTURE_STOPPED;
135#ifndef _WIN32
136 cap_session->owner = getuid();
137 cap_session->group = getgid();
138#endif
139 cap_session->count = 0;
140 cap_session->count_pending = 0;
141 cap_session->session_will_restart = false0;
142
143 cap_session->new_file = new_file;
144 cap_session->new_packets = new_packets;
145 cap_session->drops = drops;
146 cap_session->error = error;
147 cap_session->cfilter_error = cfilter_error;
148 cap_session->closed = closed;
149 cap_session->frame_cksum = NULL((void*)0);
150}
151
152void capture_process_finished(capture_session *cap_session)
153{
154 capture_options *capture_opts = cap_session->capture_opts;
155 interface_options *interface_opts;
156 GString *message;
157 unsigned i;
158
159 if (!extcap_session_stop(cap_session)) {
160 /* At least one extcap process did not fully finish yet, wait for it */
161 return;
162 }
163
164 if (cap_session->fork_child != WS_INVALID_PID-1) {
165 if (capture_opts->stop_after_extcaps) {
166 /* User has requested capture stop and all extcaps are gone now */
167 capture_opts->stop_after_extcaps = false0;
168 sync_pipe_stop(cap_session);
169 }
170 /* Wait for child process to end, session is not closed yet */
171 return;
172 }
173
174 /* Construct message and close session */
175 message = g_string_new(capture_opts->closed_msg);
176 for (i = 0; i < capture_opts->ifaces->len; i++) {
177 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i)(((interface_options*) (void *) (capture_opts->ifaces)->
data) [(i)])
;
178 if (interface_opts->if_type != IF_EXTCAP) {
179 continue;
180 }
181
182 if ((interface_opts->extcap_stderr != NULL((void*)0)) &&
183 (interface_opts->extcap_stderr->len > 0)) {
184 if (message->len > 0) {
185 g_string_append(message, "\n")(__builtin_constant_p ("\n") ? __extension__ ({ const char * const
__val = ("\n"); g_string_append_len_inline (message, __val, (
__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)))
: (gssize) -1); }) : g_string_append_len_inline (message, "\n"
, (gssize) -1))
;
186 }
187 g_string_append(message, "Error from extcap pipe: ")(__builtin_constant_p ("Error from extcap pipe: ") ? __extension__
({ const char * const __val = ("Error from extcap pipe: "); g_string_append_len_inline
(message, __val, (__val != ((void*)0)) ? (gssize) strlen (((
__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(message, "Error from extcap pipe: ", (gssize) -1))
;
188 g_string_append(message, interface_opts->extcap_stderr->str)(__builtin_constant_p (interface_opts->extcap_stderr->str
) ? __extension__ ({ const char * const __val = (interface_opts
->extcap_stderr->str); g_string_append_len_inline (message
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (message
, interface_opts->extcap_stderr->str, (gssize) -1))
;
189 }
190 }
191
192 cap_session->closed(cap_session, message->str);
193 g_string_free(message, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(message), ((!(0)))) : g_string_free_and_steal (message)) : (
g_string_free) ((message), ((!(0)))))
;
194 g_free(capture_opts->closed_msg);
195 capture_opts->closed_msg = NULL((void*)0);
196 capture_opts->stop_after_extcaps = false0;
197}
198
199/* Append an arg (realloc) to an argc/argv array */
200/* (add a string pointer to a NULL-terminated array of string pointers) */
201/* XXX: For glib >= 2.68 we could use a GStrvBuilder.
202 */
203static char **
204sync_pipe_add_arg(char **args, int *argc, const char *arg)
205{
206 /* Grow the array; "*argc" currently contains the number of string
207 pointers, *not* counting the NULL pointer at the end, so we have
208 to add 2 in order to get the new size of the array, including the
209 new pointer and the terminating NULL pointer. */
210 args = (char **)g_realloc( (void *) args, (*argc + 2) * sizeof (char *));
8
Memory is allocated
211
212 /* Stuff the pointer into the penultimate element of the array, which
213 is the one at the index specified by "*argc". */
214 args[*argc] = g_strdup(arg)g_strdup_inline (arg);
215 /* Now bump the count. */
216 (*argc)++;
217
218 /* We overwrite the NULL pointer; put it back right after the
219 element we added. */
220 args[*argc] = NULL((void*)0);
221
222 return args;
223}
224
225/* Take a buffer from an SP_LOG_MSG from dumpcap and send it to our
226 * current logger. Keep this in sync with the format used in
227 * dumpcap_log_writer. (We might want to do more proper serialization
228 * of more than just the log level.)
229 */
230static void
231sync_pipe_handle_log_msg(const char *buffer) {
232 const char *log_msg = NULL((void*)0);
233 const char* end;
234 uint32_t level = 0;
235
236 if (ws_strtou32(buffer, &end, &level) && end[0] == ':') {
237 log_msg = end + 1;
238 }
239 ws_log(LOG_DOMAIN_CAPCHILD"Capchild", level, "%s", log_msg);
240}
241
242/* Initialize an argument list and add dumpcap to it. */
243static char **
244init_pipe_args(int *argc) {
245 char *exename;
246 char **argv;
247
248 /* Find the absolute path of the dumpcap executable. */
249 exename = get_executable_path("dumpcap");
250 if (exename == NULL((void*)0)) {
251 return NULL((void*)0);
252 }
253
254 /* Allocate the string pointer array with enough space for the
255 terminating NULL pointer. */
256 *argc = 0;
257 argv = (char **)g_malloc(sizeof (char *));
258 *argv = NULL((void*)0);
259
260 /* Make that the first argument in the argument list (argv[0]). */
261 argv = sync_pipe_add_arg(argv, argc, exename);
262
263 /* Tell dumpcap to log at the lowest level its domain (Capchild) is
264 * set to log in the main program. (It might be in the special noisy
265 * or debug filter, so we can't just check the overall level.)
266 */
267 for (enum ws_log_level level = LOG_LEVEL_NOISY; level != _LOG_LEVEL_LAST; level++) {
268 if (ws_log_msg_is_active(LOG_DOMAIN_CAPCHILD"Capchild", level)) {
269 argv = sync_pipe_add_arg(argv, argc, "--log-level");
270 argv = sync_pipe_add_arg(argv, argc, ws_log_level_to_string(level));
271 break;
272 }
273 }
274
275 argv = sync_pipe_add_arg(argv, argc, "--application-flavor");
276 argv = sync_pipe_add_arg(argv, argc, application_flavor_name_lower());
277
278 /* sync_pipe_add_arg strdupes exename, so we should free our copy */
279 g_free(exename);
280
281 return argv;
282}
283
284static gboolean
285pipe_io_cb(GIOChannel *pipe_io, GIOCondition condition _U___attribute__((unused)), void * user_data)
286{
287 capture_session *cap_session = (capture_session *)user_data;
288 if (!sync_pipe_input_cb(pipe_io, cap_session)) {
289 cap_session->pipe_input_id = 0;
290 return G_SOURCE_REMOVE(0);
291 }
292 return G_SOURCE_CONTINUE(!(0));
293}
294
295/*
296 * Open two pipes to dumpcap with the supplied arguments, one for its
297 * standard output and one for its standard error.
298 *
299 * On success, *msg is unchanged and 0 is returned; data_read_fd,
300 * message_read_fd, and fork_child point to the standard output pipe's
301 * file descriptor, the standard error pipe's file descriptor, and
302 * the child's PID/handle, respectively.
303 *
304 * On failure, *msg points to an error message for the failure, and -1 is
305 * returned, in which case *msg must be freed with g_free().
306 */
307#define ARGV_NUMBER_LEN24 24
308static int
309#ifdef _WIN32
310sync_pipe_open_command(char **argv, int *data_read_fd,
311 GIOChannel **message_read_io, int *signal_write_fd,
312 ws_process_id *fork_child, GArray *ifaces,
313 char **msg, void(*update_cb)(void))
314#else
315sync_pipe_open_command(char **argv, int *data_read_fd,
316 GIOChannel **message_read_io, int *signal_write_fd _U___attribute__((unused)),
317 ws_process_id *fork_child, GArray *ifaces _U___attribute__((unused)),
318 char **msg, void(*update_cb)(void))
319#endif
320{
321 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
322 int message_read_fd = -1;
323 char sync_id[ARGV_NUMBER_LEN24];
324#ifdef _WIN32
325 HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
326 HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
327 int signal_pipe_write_fd = -1;
328 HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */
329 char control_id[ARGV_NUMBER_LEN24];
330 char *signal_pipe_name;
331 size_t i_handles = 0;
332 HANDLE *handles;
333 GString *args = g_string_sized_new(200);
334 char *quoted_arg;
335 SECURITY_ATTRIBUTES sa;
336 STARTUPINFO si;
337 PROCESS_INFORMATION pi;
338 int i;
339 unsigned j;
340 interface_options *interface_opts;
341#else
342 int sync_pipe[2]; /* pipe used to send messages from child to parent */
343 int data_pipe[2]; /* pipe used to send data from child to parent */
344#endif
345 *fork_child = WS_INVALID_PID-1;
346 if (data_read_fd != NULL((void*)0)) {
347 *data_read_fd = -1;
348 }
349 *message_read_io = NULL((void*)0);
350 ws_debug("sync_pipe_open_command")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 350, __func__, "sync_pipe_open_command"); } } while (0)
;
351
352 if (!msg) {
353 /* We can't return anything */
354 g_strfreev(argv);
355#ifdef _WIN32
356 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
357#endif
358 return -1;
359 }
360
361#ifdef _WIN32
362 /* init SECURITY_ATTRIBUTES */
363 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
364 sa.bInheritHandle = false0;
365 sa.lpSecurityDescriptor = NULL((void*)0);
366
367 /* Create a pipe for the child process to send us messages */
368 /* (increase this value if you have trouble while fast capture file switches) */
369 if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
370 /* Couldn't create the message pipe between parent and child. */
371 *msg = ws_strdup_printf("Couldn't create sync pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, win32strerror(GetLastError()))
372 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, win32strerror(GetLastError()))
;
373 g_strfreev(argv);
374 return -1;
375 }
376
377 /*
378 * Associate a C run-time file handle with the Windows HANDLE for the
379 * read side of the message pipe.
380 *
381 * (See http://www.flounder.com/handles.htm for information on various
382 * types of file handle in C/C++ on Windows.)
383 */
384 message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
385 if (message_read_fd == -1) {
386 *msg = ws_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for message read pipe: %s"
, g_strerror((*__errno_location ())))
;
387 g_strfreev(argv);
388 CloseHandle(sync_pipe[PIPE_READ]);
389 CloseHandle(sync_pipe[PIPE_WRITE]);
390 return -1;
391 }
392
393 if (data_read_fd != NULL((void*)0)) {
394 /* Create a pipe for the child process to send us data */
395 /* (increase this value if you have trouble while fast capture file switches) */
396 if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, PIPE_BUF_SIZE((512 * 1000)+4))) {
397 /* Couldn't create the message pipe between parent and child. */
398 *msg = ws_strdup_printf("Couldn't create data pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, win32strerror(GetLastError()))
399 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, win32strerror(GetLastError()))
;
400 g_strfreev(argv);
401 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
402 CloseHandle(sync_pipe[PIPE_WRITE]);
403 return -1;
404 }
405
406 /*
407 * Associate a C run-time file handle with the Windows HANDLE for the
408 * read side of the data pipe.
409 *
410 * (See http://www.flounder.com/handles.htm for information on various
411 * types of file handle in C/C++ on Windows.)
412 */
413 *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
414 if (*data_read_fd == -1) {
415 *msg = ws_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for data read pipe: %s"
, g_strerror((*__errno_location ())))
;
416 g_strfreev(argv);
417 CloseHandle(data_pipe[PIPE_READ]);
418 CloseHandle(data_pipe[PIPE_WRITE]);
419 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
420 CloseHandle(sync_pipe[PIPE_WRITE]);
421 return -1;
422 }
423 }
424
425 if (signal_write_fd != NULL((void*)0)) {
426 /* Create the signal pipe */
427 snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
428 signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, control_id
)
;
429 signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
430 PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
431 g_free(signal_pipe_name);
432
433 if (signal_pipe == INVALID_HANDLE_VALUE) {
434 /* Couldn't create the signal pipe between parent and child. */
435 *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
436 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
;
437 g_strfreev(argv);
438 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
439 CloseHandle(sync_pipe[PIPE_WRITE]);
440 return -1;
441 }
442
443 /*
444 * Associate a C run-time file handle with the Windows HANDLE for the
445 * read side of the message pipe.
446 *
447 * (See http://www.flounder.com/handles.htm for information on various
448 * types of file handle in C/C++ on Windows.)
449 */
450 signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
451 if (signal_pipe_write_fd == -1) {
452 /* Couldn't create the pipe between parent and child. */
453 *msg = ws_strdup_printf("Couldn't get C file handle for sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't get C file handle for sync pipe: %s"
, g_strerror((*__errno_location ())))
;
454 g_strfreev(argv);
455 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
456 CloseHandle(sync_pipe[PIPE_WRITE]);
457 CloseHandle(signal_pipe);
458 return -1;
459 }
460 }
461
462 /* init STARTUPINFO & PROCESS_INFORMATION */
463 memset(&si, 0, sizeof(si));
464 si.cb = sizeof(si);
465 memset(&pi, 0, sizeof(pi));
466#ifdef DEBUG_CHILD
467 si.dwFlags = STARTF_USESHOWWINDOW;
468 si.wShowWindow = SW_SHOW;
469#else
470 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
471 si.wShowWindow = SW_HIDE; /* this hides the console window */
472
473 if (data_read_fd == NULL((void*)0)) {
474 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
475 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
476 } else {
477 si.hStdInput = NULL((void*)0); /* handle for named pipe*/
478 si.hStdOutput = data_pipe[PIPE_WRITE];
479 }
480 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
481
482 /* On Windows, "[a]n inherited handle refers to the same object in the child
483 * process as it does in the parent process. It also has the same value."
484 * https://learn.microsoft.com/en-us/windows/win32/procthread/inheritance
485 * When converted to a file descriptor (via _open_osfhandle), the fd
486 * value is not necessarily the same in the two processes, but the handle
487 * value can be shared.
488 * A HANDLE is a void* though "64-bit versions of Windows use 32-bit handles
489 * for interoperability... only the lower 32 bits are significant, so it is
490 * safe to truncate the handle... or sign-extend the handle"
491 * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
492 * So it should be fine to call PtrToLong instead of casting to intptr_t.
493 * https://learn.microsoft.com/en-us/windows/win32/WinProg64/rules-for-using-pointers
494 */
495 int argc = g_strv_length(argv);
496 argv = sync_pipe_add_arg(argv, &argc, "-Z");
497 snprintf(sync_id, ARGV_NUMBER_LEN24, "%ld", PtrToLong(sync_pipe[PIPE_WRITE]));
498 argv = sync_pipe_add_arg(argv, &argc, sync_id);
499#endif
500
501 if (ifaces) {
502 for (j = 0; j < ifaces->len; j++) {
503 interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
504 if (interface_opts->extcap_fifo != NULL((void*)0)) {
505 i_handles++;
506 }
507 }
508 }
509 handles = g_new(HANDLE, 3 + i_handles)((HANDLE *) g_malloc_n ((3 + i_handles), sizeof (HANDLE)));
510 i_handles = 0;
511 if (si.hStdInput) {
512 handles[i_handles++] = si.hStdInput;
513 }
514 if (si.hStdOutput && (si.hStdOutput != si.hStdInput)) {
515 handles[i_handles++] = si.hStdOutput;
516 }
517 handles[i_handles++] = sync_pipe[PIPE_WRITE];
518 if (ifaces) {
519 for (j = 0; j < ifaces->len; j++) {
520 interface_opts = &g_array_index(ifaces, interface_options, j)(((interface_options*) (void *) (ifaces)->data) [(j)]);
521 if (interface_opts->extcap_fifo != NULL((void*)0)) {
522 handles[i_handles++] = interface_opts->extcap_pipe_h;
523 }
524 }
525 }
526
527 /* convert args array into a single string */
528 /* XXX - could change sync_pipe_add_arg() instead */
529 /* there is a drawback here: the length is internally limited to 1024 bytes */
530 for(i=0; argv[i] != 0; i++) {
531 if(i != 0) g_string_append_c(args, ' ')g_string_append_c_inline (args, ' '); /* don't prepend a space before the path!!! */
532 quoted_arg = protect_arg(argv[i]);
533 g_string_append(args, quoted_arg)(__builtin_constant_p (quoted_arg) ? __extension__ ({ const char
* const __val = (quoted_arg); g_string_append_len_inline (args
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (args
, quoted_arg, (gssize) -1))
;
534 g_free(quoted_arg);
535 }
536
537 /* call dumpcap */
538 if(!win32_create_process(argv[0], args->str, NULL((void*)0), NULL((void*)0), i_handles, handles,
539 CREATE_NEW_CONSOLE, NULL((void*)0), NULL((void*)0), &si, &pi)) {
540 *msg = ws_strdup_printf("Couldn't run %s in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s"
, args->str, win32strerror(GetLastError()))
541 args->str, win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't run %s in child process: %s"
, args->str, win32strerror(GetLastError()))
;
542 if (data_read_fd) {
543 ws_closeclose(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
544 CloseHandle(data_pipe[PIPE_WRITE]);
545 } else {
546 ws_closeclose(signal_pipe_write_fd);
547 }
548 ws_closeclose(message_read_fd); /* Should close sync_pipe[PIPE_READ] */
549 CloseHandle(sync_pipe[PIPE_WRITE]);
550 g_strfreev(argv);
551 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
552 g_free(handles);
553 return -1;
554 }
555 *fork_child = pi.hProcess;
556 /* We may need to store this and close it later */
557 CloseHandle(pi.hThread);
558 g_strfreev(argv);
559 g_string_free(args, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(args), ((!(0)))) : g_string_free_and_steal (args)) : (g_string_free
) ((args), ((!(0)))))
;
560 g_free(handles);
561
562 if (signal_write_fd != NULL((void*)0)) {
563 *signal_write_fd = signal_pipe_write_fd;
564 }
565#else /* _WIN32 */
566 /* Create a pipe for the child process to send us messages */
567 if (pipe(sync_pipe) < 0) {
568 /* Couldn't create the message pipe between parent and child. */
569 *msg = ws_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create sync pipe: %s"
, g_strerror((*__errno_location ())))
;
570 g_strfreev(argv);
571 return -1;
572 }
573
574 if (data_read_fd != NULL((void*)0)) {
575 /* Create a pipe for the child process to send us data */
576 if (pipe(data_pipe) < 0) {
577 /* Couldn't create the data pipe between parent and child. */
578 *msg = ws_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create data pipe: %s"
, g_strerror((*__errno_location ())))
;
579 g_strfreev(argv);
580 ws_closeclose(sync_pipe[PIPE_READ]);
581 ws_closeclose(sync_pipe[PIPE_WRITE]);
582 return -1;
583 }
584 }
585
586 if ((*fork_child = fork()) == 0) {
587 /*
588 * Child process - run dumpcap with the right arguments to make
589 * it just capture with the specified capture parameters
590 */
591 if (data_read_fd != NULL((void*)0)) {
592 dup2(data_pipe[PIPE_WRITE], 1);
593 ws_closeclose(data_pipe[PIPE_READ]);
594 ws_closeclose(data_pipe[PIPE_WRITE]);
595 }
596 ws_closeclose(sync_pipe[PIPE_READ]);
597 /* dumpcap should be running in capture child mode (hidden feature) */
598#ifndef DEBUG_CHILD
599 int argc = g_strv_length(argv);
600 argv = sync_pipe_add_arg(argv, &argc, "-Z");
601 snprintf(sync_id, ARGV_NUMBER_LEN24, "%d", sync_pipe[PIPE_WRITE]);
602 argv = sync_pipe_add_arg(argv, &argc, sync_id);
603#endif
604 execv(argv[0], argv);
605 sync_pipe_write_int_msg(sync_pipe[PIPE_WRITE], SP_EXEC_FAILED'X', errno(*__errno_location ()));
606
607 /* Exit with "_exit()", so that we don't close the connection
608 to the X server (and cause stuff buffered up by our parent but
609 not yet sent to be sent, as that stuff should only be sent by
610 our parent). We've sent an error message to the parent, so
611 we exit with an exit status of 1 (any exit status other than
612 0 or 1 will cause an additional message to report that exit
613 status, over and above the error message we sent to the parent). */
614 _exit(1);
615 }
616
617 g_strfreev(argv);
618
619 if (fetch_dumpcap_pid && *fork_child > 0)
620 fetch_dumpcap_pid(*fork_child);
621
622 if (data_read_fd != NULL((void*)0)) {
623 *data_read_fd = data_pipe[PIPE_READ];
624 }
625 message_read_fd = sync_pipe[PIPE_READ];
626
627#endif
628
629 /* Parent process - read messages from the child process over the
630 sync pipe. */
631
632 /* Close the write sides of the pipes, so that only the child has them
633 open, and thus they completely close, and thus return to us
634 an EOF indication, if the child closes them (either deliberately
635 or by exiting abnormally). */
636#ifdef _WIN32
637 if (data_read_fd != NULL((void*)0)) {
638 CloseHandle(data_pipe[PIPE_WRITE]);
639 }
640 CloseHandle(sync_pipe[PIPE_WRITE]);
641#else
642 if (data_read_fd != NULL((void*)0)) {
643 ws_closeclose(data_pipe[PIPE_WRITE]);
644 }
645 ws_closeclose(sync_pipe[PIPE_WRITE]);
646#endif
647
648 if (*fork_child == WS_INVALID_PID-1) {
649 /* We couldn't even create the child process. */
650 *msg = ws_strdup_printf("Couldn't create child process: %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't create child process: %s"
, g_strerror((*__errno_location ())))
;
651 if (data_read_fd != NULL((void*)0)) {
652 ws_closeclose(*data_read_fd);
653 }
654#ifdef _WIN32
655 if (signal_write_fd != NULL((void*)0)) {
656 ws_closeclose(signal_pipe_write_fd);
657 }
658#endif
659 ws_closeclose(message_read_fd);
660 return -1;
661 }
662
663#ifdef _WIN32
664 *message_read_io = g_io_channel_win32_new_fd(message_read_fd);
665#else
666 *message_read_io = g_io_channel_unix_new(message_read_fd);
667#endif
668 g_io_channel_set_encoding(*message_read_io, NULL((void*)0), NULL((void*)0));
669 g_io_channel_set_buffered(*message_read_io, false0);
670 g_io_channel_set_close_on_unref(*message_read_io, true1);
671
672 /* we might wait for a moment till child is ready, so update screen now */
673 if (update_cb) update_cb();
674 return 0;
675}
676
677/* a new capture run: start a new dumpcap task and hand over parameters through command line */
678bool_Bool
679sync_pipe_start(capture_options *capture_opts, GPtrArray *capture_comments,
680 capture_session *cap_session, info_data_t* cap_data,
681 void (*update_cb)(void))
682{
683#ifdef _WIN32
684 char control_id[ARGV_NUMBER_LEN24];
685#endif
686 GIOChannel *sync_pipe_read_io;
687 int argc;
688 char **argv;
689 int i;
690 unsigned j;
691 interface_options *interface_opts;
692
693 if (capture_opts->ifaces->len > 1)
694 capture_opts->use_pcapng = true1;
695 ws_debug("sync_pipe_start")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 695, __func__, "sync_pipe_start"); } } while (0)
;
696 capture_opts_log(LOG_DOMAIN_CAPTURE"Capture", LOG_LEVEL_DEBUG, capture_opts);
697
698 cap_session->fork_child = WS_INVALID_PID-1;
699 cap_session->capture_opts = capture_opts;
700
701 if (!extcap_init_interfaces(cap_session)) {
702 report_failure("Unable to init extcaps. (tmp fifo already exists?)");
703 return false0;
704 }
705
706 argv = init_pipe_args(&argc);
707 if (!argv) {
708 /* We don't know where to find dumpcap. */
709 report_failure("We don't know where to find dumpcap.");
710 return false0;
711 }
712
713 if (capture_opts->ifaces->len > 1)
714 argv = sync_pipe_add_arg(argv, &argc, "-t");
715
716 argv = sync_pipe_add_arg(argv, &argc, "-F");
717 if (capture_opts->use_pcapng)
718 argv = sync_pipe_add_arg(argv, &argc, "pcapng");
719 else
720 argv = sync_pipe_add_arg(argv, &argc, "pcap");
721
722 if (capture_comments != NULL((void*)0)) {
723 for (j = 0; j < capture_comments->len; j++) {
724 argv = sync_pipe_add_arg(argv, &argc, "--capture-comment");
725 argv = sync_pipe_add_arg(argv, &argc, (char*)g_ptr_array_index(capture_comments, j)((capture_comments)->pdata)[j]);
726 }
727 }
728
729 if (capture_opts->temp_dir) {
730 argv = sync_pipe_add_arg(argv, &argc, "--temp-dir");
731 argv = sync_pipe_add_arg(argv, &argc, capture_opts->temp_dir);
732 }
733
734 if (capture_opts->multi_files_on) {
735 if (capture_opts->has_autostop_filesize) {
736 char sfilesize[ARGV_NUMBER_LEN24];
737 argv = sync_pipe_add_arg(argv, &argc, "-b");
738 snprintf(sfilesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
739 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
740 }
741
742 if (capture_opts->has_file_duration) {
743 char sfile_duration[ARGV_NUMBER_LEN24];
744 argv = sync_pipe_add_arg(argv, &argc, "-b");
745 snprintf(sfile_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->file_duration);
746 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
747 }
748
749 if (capture_opts->has_file_interval) {
750 char sfile_interval[ARGV_NUMBER_LEN24];
751 argv = sync_pipe_add_arg(argv, &argc, "-b");
752 snprintf(sfile_interval, ARGV_NUMBER_LEN24, "interval:%d",capture_opts->file_interval);
753 argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
754 }
755
756 if (capture_opts->has_file_packets) {
757 char sfile_packets[ARGV_NUMBER_LEN24];
758 argv = sync_pipe_add_arg(argv, &argc, "-b");
759 snprintf(sfile_packets, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->file_packets);
760 argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
761 }
762
763 if (capture_opts->has_ring_num_files) {
764 char sring_num_files[ARGV_NUMBER_LEN24];
765 argv = sync_pipe_add_arg(argv, &argc, "-b");
766 snprintf(sring_num_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->ring_num_files);
767 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
768 }
769
770 if (capture_opts->print_file_names) {
771 char *print_name = g_strdup_printf("printname:%s", capture_opts->print_name_to);
772 argv = sync_pipe_add_arg(argv, &argc, "-b");
773 argv = sync_pipe_add_arg(argv, &argc, print_name);
774 g_free(print_name);
775 }
776
777 if (capture_opts->has_nametimenum) {
778 char nametimenum[ARGV_NUMBER_LEN24];
779 argv = sync_pipe_add_arg(argv, &argc, "-b");
780 snprintf(nametimenum, ARGV_NUMBER_LEN24, "nametimenum:2");
781 argv = sync_pipe_add_arg(argv, &argc, nametimenum);
782 }
783
784 if (capture_opts->has_autostop_files) {
785 char sautostop_files[ARGV_NUMBER_LEN24];
786 argv = sync_pipe_add_arg(argv, &argc, "-a");
787 snprintf(sautostop_files, ARGV_NUMBER_LEN24, "files:%d",capture_opts->autostop_files);
788 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
789 }
790 } else {
791 if (capture_opts->has_autostop_filesize) {
792 char sautostop_filesize[ARGV_NUMBER_LEN24];
793 argv = sync_pipe_add_arg(argv, &argc, "-a");
794 snprintf(sautostop_filesize, ARGV_NUMBER_LEN24, "filesize:%u",capture_opts->autostop_filesize);
795 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
796 }
797 }
798
799 if (capture_opts->has_autostop_packets) {
800 char scount[ARGV_NUMBER_LEN24];
801 argv = sync_pipe_add_arg(argv, &argc, "-c");
802 snprintf(scount, ARGV_NUMBER_LEN24, "%d",capture_opts->autostop_packets);
803 argv = sync_pipe_add_arg(argv, &argc, scount);
804 }
805
806 if (capture_opts->has_autostop_duration) {
807 char sautostop_duration[ARGV_NUMBER_LEN24];
808 argv = sync_pipe_add_arg(argv, &argc, "-a");
809 snprintf(sautostop_duration, ARGV_NUMBER_LEN24, "duration:%f",capture_opts->autostop_duration);
810 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
811 }
812
813 if (capture_opts->has_autostop_written_packets) {
814 char scount[ARGV_NUMBER_LEN24];
815 argv = sync_pipe_add_arg(argv, &argc, "-a");
816 snprintf(scount, ARGV_NUMBER_LEN24, "packets:%d",capture_opts->autostop_written_packets);
817 argv = sync_pipe_add_arg(argv, &argc, scount);
818 }
819
820 if (capture_opts->group_read_access) {
821 argv = sync_pipe_add_arg(argv, &argc, "-g");
822 }
823
824 if (capture_opts->update_interval != DEFAULT_UPDATE_INTERVAL100) {
825 char scount[ARGV_NUMBER_LEN24];
826 argv = sync_pipe_add_arg(argv, &argc, "--update-interval");
827 snprintf(scount, ARGV_NUMBER_LEN24, "%d", capture_opts->update_interval);
828 argv = sync_pipe_add_arg(argv, &argc, scount);
829 }
830
831 for (j = 0; j < capture_opts->ifaces->len; j++) {
832 interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j)(((interface_options*) (void *) (capture_opts->ifaces)->
data) [(j)])
;
833
834 argv = sync_pipe_add_arg(argv, &argc, "-i");
835 if (interface_opts->extcap_fifo != NULL((void*)0))
836 {
837#ifdef _WIN32
838 char *pipe = ws_strdup_printf("%s%" PRIuMAX, EXTCAP_PIPE_PREFIX, (uintmax_t)interface_opts->extcap_pipe_h)wmem_strdup_printf(((void*)0), "%s%" "l" "u", "wireshark_extcap"
, (uintmax_t)interface_opts->extcap_pipe_h)
;
839 argv = sync_pipe_add_arg(argv, &argc, pipe);
840 g_free(pipe);
841#else
842 argv = sync_pipe_add_arg(argv, &argc, interface_opts->extcap_fifo);
843#endif
844 /* Add a name for the interface, to put into an IDB. */
845 argv = sync_pipe_add_arg(argv, &argc, "--ifname");
846 argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
847 }
848 else
849 argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
850
851 if (interface_opts->descr != NULL((void*)0))
852 {
853 /* Add a description for the interface to put into an IDB and
854 * use for the temporary filename. */
855 argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
856 argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
857 }
858
859 if (interface_opts->cfilter != NULL((void*)0) && strlen(interface_opts->cfilter) != 0) {
860 argv = sync_pipe_add_arg(argv, &argc, "-f");
861 argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
862 }
863 if (interface_opts->has_snaplen) {
864 char ssnap[ARGV_NUMBER_LEN24];
865 argv = sync_pipe_add_arg(argv, &argc, "-s");
866 snprintf(ssnap, ARGV_NUMBER_LEN24, "%d", interface_opts->snaplen);
867 argv = sync_pipe_add_arg(argv, &argc, ssnap);
868 }
869
870 if (interface_opts->linktype != -1) {
871 const char *linktype = linktype_val_to_name(interface_opts->linktype);
872 if ( linktype != NULL((void*)0) )
873 {
874 argv = sync_pipe_add_arg(argv, &argc, "-y");
875 argv = sync_pipe_add_arg(argv, &argc, linktype);
876 }
877 }
878
879 if (!interface_opts->promisc_mode) {
880 argv = sync_pipe_add_arg(argv, &argc, "-p");
881 }
882
883 if (interface_opts->buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE2) {
884 char buffer_size[ARGV_NUMBER_LEN24];
885 argv = sync_pipe_add_arg(argv, &argc, "-B");
886 if(interface_opts->buffer_size == 0x00)
887 interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE2;
888 snprintf(buffer_size, ARGV_NUMBER_LEN24, "%d", interface_opts->buffer_size);
889 argv = sync_pipe_add_arg(argv, &argc, buffer_size);
890 }
891
892 if (interface_opts->monitor_mode) {
893 argv = sync_pipe_add_arg(argv, &argc, "-I");
894 }
895
896#ifdef HAVE_PCAP_REMOTE
897 if (interface_opts->datatx_udp)
898 argv = sync_pipe_add_arg(argv, &argc, "-u");
899
900 if (!interface_opts->nocap_rpcap)
901 argv = sync_pipe_add_arg(argv, &argc, "-r");
902
903 if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
904 char sauth[256];
905 argv = sync_pipe_add_arg(argv, &argc, "-A");
906 snprintf(sauth, sizeof(sauth), "%s:%s",
907 interface_opts->auth_username,
908 interface_opts->auth_password);
909 argv = sync_pipe_add_arg(argv, &argc, sauth);
910 }
911#endif
912
913#ifdef HAVE_PCAP_SETSAMPLING
914 if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
915 char ssampling[ARGV_NUMBER_LEN24];
916 argv = sync_pipe_add_arg(argv, &argc, "-m");
917 snprintf(ssampling, ARGV_NUMBER_LEN24, "%s:%d",
918 interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :
919 interface_opts->sampling_method == CAPTURE_SAMP_BY_TIMER ? "timer" :
920 "undef",
921 interface_opts->sampling_param);
922 argv = sync_pipe_add_arg(argv, &argc, ssampling);
923 }
924#endif
925 if (interface_opts->timestamp_type) {
926 argv = sync_pipe_add_arg(argv, &argc, "--time-stamp-type");
927 argv = sync_pipe_add_arg(argv, &argc, interface_opts->timestamp_type);
928 }
929 }
930
931#ifndef DEBUG_CHILD
932#ifdef _WIN32
933 /* pass process id to dumpcap for named signal pipe */
934 argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
935 snprintf(control_id, ARGV_NUMBER_LEN24, "%ld", GetCurrentProcessId());
936 argv = sync_pipe_add_arg(argv, &argc, control_id);
937#endif
938#endif
939
940 if (capture_opts->save_file) {
941 argv = sync_pipe_add_arg(argv, &argc, "-w");
942 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
943 }
944 for (i = 0; i < argc; i++) {
945 ws_debug("argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 945, __func__, "argv[%d]: %s", i, argv[i]); } } while (0)
;
946 }
947 if (capture_opts->compress_type) {
948 argv = sync_pipe_add_arg(argv, &argc, "--compress-type");
949 argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
950 }
951
952 int ret;
953 char* msg;
954#ifdef _WIN32
955 ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, &cap_session->signal_pipe_write_fd,
956 &cap_session->fork_child, capture_opts->ifaces, &msg, update_cb);
957#else
958 ret = sync_pipe_open_command(argv, NULL((void*)0), &sync_pipe_read_io, NULL((void*)0),
959 &cap_session->fork_child, NULL((void*)0), &msg, update_cb);
960#endif
961
962 if (ret == -1) {
963 report_failure("%s", msg);
964 g_free(msg);
965 return false0;
966 }
967
968 /* Parent process - read messages from the child process over the
969 sync pipe. */
970
971 cap_session->fork_child_status = 0;
972 cap_session->cap_data_info = cap_data;
973
974 /* We were able to set up to read the capture file;
975 arrange that our callback be called whenever it's possible
976 to read from the sync pipe, so that it's called when
977 the child process wants to tell us something. */
978
979 /* we have a running capture, now wait for the real capture filename */
980 if (cap_session->pipe_input_id) {
981 g_source_remove(cap_session->pipe_input_id);
982 cap_session->pipe_input_id = 0;
983 }
984 cap_session->pipe_input_id = g_io_add_watch(sync_pipe_read_io, G_IO_IN | G_IO_HUP, pipe_io_cb, cap_session);
985 /* Pipe will be closed when watch is removed */
986 g_io_channel_unref(sync_pipe_read_io);
987
988 return true1;
989}
990
991/*
992 * Close the pipes we're using to read from dumpcap, and wait for it
993 * to exit. On success, *msgp is unchanged, and the exit status of
994 * dumpcap is returned. On failure (which includes "dumpcap exited
995 * due to being killed by a signal or an exception"), *msgp points
996 * to an error message for the failure, and -1 is returned. In the
997 * latter case, *msgp must be freed with g_free().
998 */
999static int
1000sync_pipe_close_command(int *data_read_fd, GIOChannel *message_read_io,
1001 ws_process_id *fork_child, char **msgp)
1002{
1003 ws_closeclose(*data_read_fd);
1004 if (message_read_io != NULL((void*)0))
1005 g_io_channel_unref(message_read_io);
1006
1007#ifdef _WIN32
1008 /* XXX - Should we signal the child somehow? */
1009 sync_pipe_kill(*fork_child);
1010#endif
1011
1012 return sync_pipe_wait_for_child(*fork_child, msgp);
1013}
1014
1015/*
1016 * Run dumpcap with the supplied arguments.
1017 *
1018 * On success, *data points to a buffer containing the dumpcap output,
1019 * *primary_msg and *secondary_message are NULL, and 0 is returned; *data
1020 * must be freed with g_free().
1021 *
1022 * On failure, *data is NULL, *primary_msg points to an error message,
1023 * *secondary_msg either points to an additional error message or is
1024 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1025 * must be freed with g_free().
1026 */
1027static int
1028sync_pipe_run_command_actual(char **argv, char **data, char **primary_msg,
1029 char **secondary_msg, void(*update_cb)(void))
1030{
1031 char *msg;
1032 int data_pipe_read_fd, ret;
1033 GIOChannel *sync_pipe_read_io;
1034 ws_process_id fork_child;
1035 char *wait_msg;
1036 char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1037 ssize_t nread;
1038 char indicator;
1039 int32_t exec_errno = 0;
1040 unsigned primary_msg_len;
1041 const char *primary_msg_text;
1042 unsigned secondary_msg_len;
1043 const char *secondary_msg_text;
1044 char *combined_msg;
1045 GString *data_buf = NULL((void*)0);
1046 ssize_t count;
1047
1048 if (buffer == NULL((void*)0)) {
1049 /* g_malloc is supposed to terminate the program if this fails, but,
1050 * at least on a RELEASE build, some versions of gcc don't think that
1051 * happens.
1052 */
1053 *primary_msg = ws_strdup_printf("Couldn't allocate memory for dumpcap output buffer: %s",wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s"
, g_strerror((*__errno_location ())))
1054 g_strerror(errno))wmem_strdup_printf(((void*)0), "Couldn't allocate memory for dumpcap output buffer: %s"
, g_strerror((*__errno_location ())))
;
1055 *secondary_msg = NULL((void*)0);
1056 *data = NULL((void*)0);
1057 return -1;
1058 }
1059
1060 ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_io, NULL((void*)0),
1061 &fork_child, NULL((void*)0), &msg, update_cb);
1062 if (ret == -1) {
1063 *primary_msg = msg;
1064 *secondary_msg = NULL((void*)0);
1065 *data = NULL((void*)0);
1066 g_free(buffer);
1067 return -1;
1068 }
1069
1070 /*
1071 * We were able to set up to read dumpcap's output. Do so.
1072 *
1073 * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
1074 */
1075 do {
1076 nread = pipe_read_block(sync_pipe_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1077 buffer, primary_msg);
1078 if(nread <= 0) {
1079 /* We got a read error from the sync pipe, or we got no data at
1080 all from the sync pipe, so we're not going to be getting any
1081 data or error message from the child process. Pick up its
1082 exit status, and complain.
1083
1084 We don't have to worry about killing the child, if the sync pipe
1085 returned an error. Usually this error is caused as the child killed
1086 itself while going down. Even in the rare cases that this isn't the
1087 case, the child will get an error when writing to the broken pipe
1088 the next time, cleaning itself up then. */
1089 g_io_channel_unref(sync_pipe_read_io);
1090 ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
1091 if(nread == 0) {
1092 /* We got an EOF from the sync pipe. That means that it exited
1093 before giving us any data to read. If ret is -1, we report
1094 that as a bad exit (e.g., exiting due to a signal); otherwise,
1095 we report it as a premature exit. */
1096 if (ret == -1)
1097 *primary_msg = wait_msg;
1098 else
1099 *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely"
)
;
1100 } else {
1101 /* We got an error from the sync pipe. If ret is -1, report
1102 both the sync pipe I/O error and the wait error. */
1103 if (ret == -1) {
1104 combined_msg = ws_strdup_printf("%s\n\n%s", *primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *primary_msg, wait_msg
)
;
1105 g_free(*primary_msg);
1106 g_free(wait_msg);
1107 *primary_msg = combined_msg;
1108 }
1109 }
1110 *secondary_msg = NULL((void*)0);
1111 *data = NULL((void*)0);
1112 g_free(buffer);
1113
1114 return -1;
1115 }
1116
1117 /* we got a valid message block from the child, process it */
1118 switch(indicator) {
1119
1120 case SP_EXEC_FAILED'X':
1121 /*
1122 * Exec of dumpcap failed. Get the errno for the failure.
1123 */
1124 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1125 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 1125, __func__, "Invalid errno: %s", buffer); } } while (0)
;
1126 }
1127
1128 /*
1129 * Pick up the child status.
1130 */
1131 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1132 &fork_child, &msg);
1133 if (ret == -1) {
1134 /*
1135 * Child process failed unexpectedly, or wait failed; msg is the
1136 * error message.
1137 */
1138 *primary_msg = msg;
1139 *secondary_msg = NULL((void*)0);
1140 } else {
1141 /*
1142 * Child process failed, but returned the expected exit status.
1143 * Return the messages it gave us, and indicate failure.
1144 */
1145 *primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
1146 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
1147 *secondary_msg = NULL((void*)0);
1148 ret = -1;
1149 }
1150 *data = NULL((void*)0);
1151 break;
1152
1153 case SP_ERROR_MSG'E':
1154 /*
1155 * Error from dumpcap; there will be a primary message and a
1156 * secondary message.
1157 */
1158
1159 /* convert primary message */
1160 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1161 primary_msg_text = buffer+4;
1162 /* convert secondary message */
1163 pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1164 &secondary_msg_len);
1165 secondary_msg_text = primary_msg_text + primary_msg_len + 4;
1166 /* the capture child will close the sync_pipe, nothing to do */
1167
1168 /*
1169 * Pick up the child status.
1170 */
1171 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1172 &fork_child, &msg);
1173 if (ret == -1) {
1174 /*
1175 * Child process failed unexpectedly, or wait failed; msg is the
1176 * error message.
1177 */
1178 *primary_msg = msg;
1179 *secondary_msg = NULL((void*)0);
1180 } else {
1181 /*
1182 * Child process failed, but returned the expected exit status.
1183 * Return the messages it gave us, and indicate failure.
1184 */
1185 *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1186 *secondary_msg = g_strdup(secondary_msg_text)g_strdup_inline (secondary_msg_text);
1187 ret = -1;
1188 }
1189 *data = NULL((void*)0);
1190 break;
1191
1192 case SP_BAD_FILTER'B': {
1193 uint32_t indx = 0;
1194 const char* end;
1195
1196 if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
1197 primary_msg_text = end + 1;
1198 } else {
1199 primary_msg_text = "dumpcap process returned a SP_BAD_FILTER without an error message";
1200 }
1201 /*
1202 * Pick up the child status.
1203 */
1204 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1205 &fork_child, &msg);
1206 if (ret == -1) {
1207 /*
1208 * Child process failed unexpectedly, or wait failed; msg is the
1209 * error message.
1210 */
1211 *primary_msg = msg;
1212 *secondary_msg = NULL((void*)0);
1213 } else {
1214 /*
1215 * Child process failed, but returned the expected exit status.
1216 * Return the messages it gave us, and indicate failure.
1217 */
1218 *primary_msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1219 *secondary_msg = NULL((void*)0);
1220 ret = -1;
1221 }
1222 *data = NULL((void*)0);
1223 break;
1224 }
1225 case SP_LOG_MSG'L':
1226 /*
1227 * Log from dumpcap; pass to our log
1228 */
1229 sync_pipe_handle_log_msg(buffer);
1230 break;
1231
1232 case SP_SUCCESS'S':
1233 /* read the output from the command */
1234 data_buf = g_string_new("");
1235 while ((count = ws_readread(data_pipe_read_fd, buffer, PIPE_BUF_SIZE((512 * 1000)+4))) > 0) {
1236 buffer[count] = '\0';
1237 g_string_append(data_buf, buffer)(__builtin_constant_p (buffer) ? __extension__ ({ const char *
const __val = (buffer); g_string_append_len_inline (data_buf
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (data_buf
, buffer, (gssize) -1))
;
1238 }
1239
1240 /*
1241 * Pick up the child status.
1242 */
1243 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1244 &fork_child, &msg);
1245 if (ret == -1) {
1246 /*
1247 * Child process failed unexpectedly, or wait failed; msg is the
1248 * error message.
1249 */
1250 *primary_msg = msg;
1251 *secondary_msg = NULL((void*)0);
1252 g_string_free(data_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(data_buf), ((!(0)))) : g_string_free_and_steal (data_buf)) :
(g_string_free) ((data_buf), ((!(0)))))
;
1253 *data = NULL((void*)0);
1254 } else {
1255 /*
1256 * Child process succeeded.
1257 */
1258 *primary_msg = NULL((void*)0);
1259 *secondary_msg = NULL((void*)0);
1260 *data = g_string_free(data_buf, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((data_buf
), ((0))) : g_string_free_and_steal (data_buf)) : (g_string_free
) ((data_buf), ((0))))
;
1261 }
1262 break;
1263
1264 default:
1265 /*
1266 * Pick up the child status.
1267 */
1268 ret = sync_pipe_close_command(&data_pipe_read_fd, sync_pipe_read_io,
1269 &fork_child, &msg);
1270 if (ret == -1) {
1271 /*
1272 * Child process failed unexpectedly, or wait failed; msg is the
1273 * error message.
1274 */
1275 *primary_msg = msg;
1276 *secondary_msg = NULL((void*)0);
1277 } else {
1278 /*
1279 * Child process returned an unknown status.
1280 */
1281 *primary_msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
1282 indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
;
1283 *secondary_msg = NULL((void*)0);
1284 ret = -1;
1285 }
1286 *data = NULL((void*)0);
1287 break;
1288 }
1289 } while (indicator != SP_SUCCESS'S' && ret != -1);
1290
1291 g_free(buffer);
1292 return ret;
1293}
1294
1295/* centralised logging and timing for sync_pipe_run_command_actual(),
1296* redirects to sync_pipe_run_command_actual()
1297*/
1298static int
1299sync_pipe_run_command(char **argv, char **data, char **primary_msg,
1300 char **secondary_msg, void (*update_cb)(void))
1301{
1302 int ret, i;
1303 int64_t start_time;
1304 double elapsed;
1305 int logging_enabled;
1306
1307 /* check if logging is actually enabled, otherwise don't expend the CPU generating logging */
1308 logging_enabled = ws_log_msg_is_active(WS_LOG_DOMAIN"Capture", LOG_LEVEL_INFO);
1309 if (logging_enabled) {
1310 start_time = g_get_monotonic_time();
1311 ws_debug("sync_pipe_run_command() starts")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1311, __func__, "sync_pipe_run_command() starts"); } } while
(0)
;
1312 for (i=0; argv[i] != 0; i++) {
1313 ws_noisy(" argv[%d]: %s", i, argv[i])do { if (1) { ws_log_full("Capture", LOG_LEVEL_NOISY, "capture/capture_sync.c"
, 1313, __func__, " argv[%d]: %s", i, argv[i]); } } while (0
)
;
1314 }
1315 }
1316 /* do the actual sync pipe run command */
1317 ret = sync_pipe_run_command_actual(argv, data, primary_msg, secondary_msg, update_cb);
1318
1319 if (logging_enabled) {
1320 elapsed = (g_get_monotonic_time() - start_time) / 1e6;
1321
1322 ws_debug("sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1322, __func__, "sync_pipe_run_command() ends, taking %.3fs, result=%d"
, elapsed, ret); } } while (0)
;
1323
1324 }
1325 return ret;
1326}
1327
1328
1329int
1330sync_interface_set_80211_chan(const char *iface, const char *freq, const char *type,
1331 const char *center_freq1, const char *center_freq2,
1332 char **data, char **primary_msg,
1333 char **secondary_msg, void (*update_cb)(void))
1334{
1335 int argc, ret;
1336 char **argv;
1337 char *opt;
1338
1339 argv = init_pipe_args(&argc);
1340
1341 if (!argv) {
1342 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1343 *secondary_msg = NULL((void*)0);
1344 *data = NULL((void*)0);
1345 return -1;
1346 }
1347
1348 argv = sync_pipe_add_arg(argv, &argc, "-i");
1349 argv = sync_pipe_add_arg(argv, &argc, iface);
1350
1351 if (center_freq2)
1352 opt = ws_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2)wmem_strdup_printf(((void*)0), "%s,%s,%s,%s", freq, type, center_freq1
, center_freq2)
;
1353 else if (center_freq1)
1354 opt = ws_strdup_printf("%s,%s,%s", freq, type, center_freq1)wmem_strdup_printf(((void*)0), "%s,%s,%s", freq, type, center_freq1
)
;
1355 else if (type)
1356 opt = ws_strdup_printf("%s,%s", freq, type)wmem_strdup_printf(((void*)0), "%s,%s", freq, type);
1357 else
1358 opt = g_strdup(freq)g_strdup_inline (freq);
1359
1360 argv = sync_pipe_add_arg(argv, &argc, "-k");
1361 argv = sync_pipe_add_arg(argv, &argc, opt);
1362
1363 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1364 g_free(opt);
1365 return ret;
1366}
1367
1368/*
1369 * Get the results of compiling a capture filter for an interface using dumpcap.
1370 *
1371 * On success, *data points to a buffer containing the dumpcap output,
1372 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1373 * must be freed with g_free().
1374 *
1375 * On failure, *data is NULL, *primary_msg points to an error message,
1376 * *secondary_msg either points to an additional error message or is
1377 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1378 * must be freed with g_free().
1379 */
1380int
1381sync_if_bpf_filter_open(const char *ifname, const char* filter,
1382 int linktype, char **data, char **primary_msg,
1383 char **secondary_msg, void (*update_cb)(void))
1384{
1385 int argc;
1386 char **argv;
1387 int ret;
1388
1389 ws_debug("sync_if_bpf_filter_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1389, __func__, "sync_if_bpf_filter_open"); } } while (0)
;
1390
1391 argv = init_pipe_args(&argc);
1392
1393 if (!argv) {
1394 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1395 *secondary_msg = NULL((void*)0);
1396 *data = NULL((void*)0);
1397 return -1;
1398 }
1399
1400 const char* linktype_name = linktype_val_to_name(linktype);
1401 if (linktype != -1) { // Allow -1 for device default
1402 if (!linktype_name) {
1403 *primary_msg = g_strdup_printf("Unknown link-layer type %d.", linktype);
1404 *secondary_msg = NULL((void*)0);
1405 *data = NULL((void*)0);
1406 return -1;
1407 }
1408 }
1409
1410 /* Ask for the human-readable BPF code for the capture filter */
1411 argv = sync_pipe_add_arg(argv, &argc, "-d");
1412 argv = sync_pipe_add_arg(argv, &argc, "-i");
1413 argv = sync_pipe_add_arg(argv, &argc, ifname);
1414 if (linktype_name) {
1415 argv = sync_pipe_add_arg(argv, &argc, "-y");
1416 argv = sync_pipe_add_arg(argv, &argc, linktype_name);
1417 }
1418 argv = sync_pipe_add_arg(argv, &argc, "-f");
1419 argv = sync_pipe_add_arg(argv, &argc, filter);
1420
1421 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1422 return ret;
1423}
1424
1425/*
1426 * Get the list of interfaces using dumpcap.
1427 *
1428 * On success, *data points to a buffer containing the dumpcap output,
1429 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1430 * must be freed with g_free().
1431 *
1432 * On failure, *data is NULL, *primary_msg points to an error message,
1433 * *secondary_msg either points to an additional error message or is
1434 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1435 * must be freed with g_free().
1436 */
1437int
1438sync_interface_list_open(char **data, char **primary_msg,
1439 char **secondary_msg, void (*update_cb)(void))
1440{
1441 int argc;
1442 char **argv;
1443 int ret;
1444
1445 ws_debug("sync_interface_list_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1445, __func__, "sync_interface_list_open"); } } while (0)
;
1446
1447 argv = init_pipe_args(&argc);
1448
1449 if (!argv) {
1450 *primary_msg = g_strdup("We don't know where to find dumpcap..")g_strdup_inline ("We don't know where to find dumpcap..");
1451 *secondary_msg = NULL((void*)0);
1452 *data = NULL((void*)0);
1453 return -1;
1454 }
1455
1456 /* Ask for the interface list */
1457 argv = sync_pipe_add_arg(argv, &argc, "-D");
1458
1459 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1460 return ret;
1461}
1462
1463/*
1464 * Get the capabilities of an interface using dumpcap.
1465 *
1466 * On success, *data points to a buffer containing the dumpcap output,
1467 * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
1468 * must be freed with g_free().
1469 *
1470 * On failure, *data is NULL, *primary_msg points to an error message,
1471 * *secondary_msg either points to an additional error message or is
1472 * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
1473 * must be freed with g_free().
1474 */
1475int
1476sync_if_capabilities_open(const char *ifname, bool_Bool monitor_mode, const char* auth,
1477 char **data, char **primary_msg,
1478 char **secondary_msg, void (*update_cb)(void))
1479{
1480 int argc;
1481 char **argv;
1482 int ret;
1483
1484 ws_debug("sync_if_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1484, __func__, "sync_if_capabilities_open"); } } while (0)
;
1485
1486 argv = init_pipe_args(&argc);
1487
1488 if (!argv) {
1489 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1490 *secondary_msg = NULL((void*)0);
1491 *data = NULL((void*)0);
1492 return -1;
1493 }
1494
1495 /* Ask for the interface capabilities */
1496 argv = sync_pipe_add_arg(argv, &argc, "-i");
1497 argv = sync_pipe_add_arg(argv, &argc, ifname);
1498 argv = sync_pipe_add_arg(argv, &argc, "-L");
1499 argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1500 if (monitor_mode)
1501 argv = sync_pipe_add_arg(argv, &argc, "-I");
1502 if (auth) {
1503 argv = sync_pipe_add_arg(argv, &argc, "-A");
1504 argv = sync_pipe_add_arg(argv, &argc, auth);
1505 }
1506
1507 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1508 return ret;
1509}
1510
1511int
1512sync_if_list_capabilities_open(GList *if_queries,
1513 char **data, char **primary_msg,
1514 char **secondary_msg, void (*update_cb)(void))
1515{
1516 int argc;
1517 char **argv;
1518 int ret;
1519 if_cap_query_t *if_cap_query;
1520
1521 ws_debug("sync_if_list_capabilities_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1521, __func__, "sync_if_list_capabilities_open"); } } while
(0)
;
1522
1523 argv = init_pipe_args(&argc);
1524
1525 if (!argv) {
1526 *primary_msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1527 *secondary_msg = NULL((void*)0);
1528 *data = NULL((void*)0);
1529 return -1;
1530 }
1531
1532 for (GList *li = if_queries; li != NULL((void*)0); li = g_list_next(li)((li) ? (((GList *)(li))->next) : ((void*)0))) {
1533 if_cap_query = (if_cap_query_t*)li->data;
1534 /* Ask for the interface capabilities */
1535 argv = sync_pipe_add_arg(argv, &argc, "-i");
1536 argv = sync_pipe_add_arg(argv, &argc, if_cap_query->name);
1537 if (if_cap_query->monitor_mode)
1538 argv = sync_pipe_add_arg(argv, &argc, "-I");
1539 if (if_cap_query->auth_username && if_cap_query->auth_password) {
1540 char sauth[256];
1541 argv = sync_pipe_add_arg(argv, &argc, "-A");
1542 snprintf(sauth, sizeof(sauth), "%s:%s",
1543 if_cap_query->auth_username,
1544 if_cap_query->auth_password);
1545 argv = sync_pipe_add_arg(argv, &argc, sauth);
1546 }
1547 }
1548 argv = sync_pipe_add_arg(argv, &argc, "-L");
1549 argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
1550
1551 ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
1552 return ret;
1553}
1554
1555/*
1556 * Start getting interface statistics using dumpcap. On success, read_fd
1557 * contains the file descriptor for the pipe's stdout, *msg is unchanged,
1558 * and zero is returned. On failure, *msg will point to an error message
1559 * that must be g_free()d, and -1 will be returned.
1560 * If data is not NULL, then it will also be set to point to a JSON
1561 * serialization of the list of local interfaces and their capabilities.
1562 */
1563int
1564sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, char **data, char **msg, void (*update_cb)(void))
1565{
1566 int argc;
1567 char **argv;
1568 int ret;
1569 GIOChannel *message_read_io;
1570 char *wait_msg;
1571 char *buffer = g_malloc(PIPE_BUF_SIZE((512 * 1000)+4) + 1);
1572 ssize_t nread;
1573 char indicator;
1574 int32_t exec_errno = 0;
1575 unsigned primary_msg_len;
1576 char *primary_msg_text;
1577 unsigned secondary_msg_len;
1578 /*char *secondary_msg_text;*/
1579 char *combined_msg;
1580
1581 ws_debug("sync_interface_stats_open")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1581, __func__, "sync_interface_stats_open"); } } while (0)
;
1
Taking true branch
2
Loop condition is false. Exiting loop
1582
1583 argv = init_pipe_args(&argc);
1584
1585 if (!argv) {
3
Assuming 'argv' is non-null
4
Taking false branch
1586 *msg = g_strdup("We don't know where to find dumpcap.")g_strdup_inline ("We don't know where to find dumpcap.");
1587 g_free(buffer);
1588 return -1;
1589 }
1590
1591 /* Ask for the interface statistics */
1592 argv = sync_pipe_add_arg(argv, &argc, "-S");
1593
1594 /* If requested, ask for the interface list and capabilities. */
1595 if (data) {
5
Assuming 'data' is non-null
6
Taking true branch
1596 argv = sync_pipe_add_arg(argv, &argc, "-D");
1597 argv = sync_pipe_add_arg(argv, &argc, "-L");
7
Calling 'sync_pipe_add_arg'
9
Returned allocated memory
1598 }
1599
1600#ifndef DEBUG_CHILD
1601#ifdef _WIN32
1602 argv = sync_pipe_add_arg(argv, &argc, "--signal-pipe");
1603 ret = create_dummy_signal_pipe(msg);
1604 if (ret == -1) {
1605 g_free(buffer);
1606 return -1;
1607 }
1608 argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
1609#endif
1610#endif
1611 ret = sync_pipe_open_command(argv, data_read_fd, &message_read_io, NULL((void*)0),
10
Potential leak of memory pointed to by 'argv'
1612 fork_child, NULL((void*)0), msg, update_cb);
1613 if (ret == -1) {
1614 g_free(buffer);
1615 return -1;
1616 }
1617
1618 /*
1619 * We were able to set up to read dumpcap's output. Do so.
1620 *
1621 * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
1622 */
1623 do {
1624 nread = pipe_read_block(message_read_io, &indicator, SP_MAX_MSG_LEN(512 * 1000),
1625 buffer, msg);
1626 if(nread <= 0) {
1627 /* We got a read error from the sync pipe, or we got no data at
1628 all from the sync pipe, so we're not going to be getting any
1629 data or error message from the child process. Pick up its
1630 exit status, and complain.
1631
1632 We don't have to worry about killing the child, if the sync pipe
1633 returned an error. Usually this error is caused as the child killed
1634 itself while going down. Even in the rare cases that this isn't the
1635 case, the child will get an error when writing to the broken pipe
1636 the next time, cleaning itself up then. */
1637 g_io_channel_unref(message_read_io);
1638 ws_closeclose(*data_read_fd);
1639 ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
1640 if(nread == 0) {
1641 /* We got an EOF from the sync pipe. That means that it exited
1642 before giving us any data to read. If ret is -1, we report
1643 that as a bad exit (e.g., exiting due to a signal); otherwise,
1644 we report it as a premature exit. */
1645 if (ret == -1)
1646 *msg = wait_msg;
1647 else
1648 *msg = g_strdup("Child dumpcap closed sync pipe prematurely")g_strdup_inline ("Child dumpcap closed sync pipe prematurely"
)
;
1649 } else {
1650 /* We got an error from the sync pipe. If ret is -1, report
1651 both the sync pipe I/O error and the wait error. */
1652 if (ret == -1) {
1653 combined_msg = ws_strdup_printf("%s\n\n%s", *msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", *msg, wait_msg);
1654 g_free(*msg);
1655 g_free(wait_msg);
1656 *msg = combined_msg;
1657 }
1658 }
1659 g_free(buffer);
1660 return -1;
1661 }
1662
1663 /* we got a valid message block from the child, process it */
1664 switch(indicator) {
1665
1666 case SP_EXEC_FAILED'X':
1667 /*
1668 * Exec of dumpcap failed. Get the errno for the failure.
1669 */
1670 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
1671 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 1671, __func__, "Invalid errno: %s", buffer); } } while (0)
;
1672 }
1673 *msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
1674 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
1675
1676 /*
1677 * Pick up the child status.
1678 */
1679 char *close_msg = NULL((void*)0);
1680 sync_pipe_close_command(data_read_fd, message_read_io,
1681 fork_child, &close_msg);
1682 /*
1683 * Ignore the error from sync_pipe_close_command, presumably the one
1684 * returned by the child is more pertinent to what went wrong.
1685 */
1686 g_free(close_msg);
1687 ret = -1;
1688 break;
1689
1690 case SP_ERROR_MSG'E':
1691 /*
1692 * Error from dumpcap; there will be a primary message and a
1693 * secondary message.
1694 */
1695
1696 /* convert primary message */
1697 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_msg_len);
1698 primary_msg_text = buffer+4;
1699 /* convert secondary message */
1700 pipe_convert_header((unsigned char*)primary_msg_text + primary_msg_len, &indicator,
1701 &secondary_msg_len);
1702 /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
1703 /* the capture child will close the sync_pipe, nothing to do */
1704
1705 /*
1706 * Pick up the child status.
1707 */
1708 ret = sync_pipe_close_command(data_read_fd, message_read_io,
1709 fork_child, msg);
1710 if (ret == -1) {
1711 /*
1712 * Child process failed unexpectedly, or wait failed; msg is the
1713 * error message.
1714 */
1715 } else if (ret == WS_EXIT_NO_INTERFACES12) {
1716 /*
1717 * No interfaces were found. If that's not the
1718 * result of an error when fetching the local
1719 * interfaces, let the user know.
1720 */
1721 *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1722 } else {
1723 /*
1724 * Child process failed, but returned the expected exit status.
1725 * Return the messages it gave us, and indicate failure.
1726 */
1727 *msg = g_strdup(primary_msg_text)g_strdup_inline (primary_msg_text);
1728 ret = -1;
1729 }
1730 g_free(buffer);
1731 return ret;
1732
1733 case SP_LOG_MSG'L':
1734 /*
1735 * Log from dumpcap; pass to our log
1736 */
1737 sync_pipe_handle_log_msg(buffer);
1738 break;
1739
1740 case SP_IFACE_LIST'I':
1741 /*
1742 * Dumpcap giving us the interface list
1743 */
1744
1745 /* convert primary message */
1746 if (data) {
1747 *data = g_strdup(buffer)g_strdup_inline (buffer);
1748 }
1749 break;
1750
1751 case SP_SUCCESS'S':
1752 /* Close the message pipe. */
1753 g_io_channel_unref(message_read_io);
1754 break;
1755
1756 default:
1757 /*
1758 * Pick up the child status.
1759 */
1760 ret = sync_pipe_close_command(data_read_fd, message_read_io,
1761 fork_child, msg);
1762 if (ret == -1) {
1763 /*
1764 * Child process failed unexpectedly, or wait failed; msg is the
1765 * error message.
1766 */
1767 } else {
1768 /*
1769 * Child process returned an unknown status.
1770 */
1771 *msg = ws_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
1772 indicator)wmem_strdup_printf(((void*)0), "dumpcap process gave an unexpected message type: 0x%02x"
, indicator)
;
1773 ret = -1;
1774 }
1775 break;
1776 }
1777 } while (indicator != SP_SUCCESS'S' && ret != -1);
1778
1779 g_free(buffer);
1780 return ret;
1781}
1782
1783/* Close down the stats process */
1784int
1785sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, char **msg)
1786{
1787#ifdef _WIN32
1788 CloseHandle(dummy_signal_pipe);
1789 dummy_signal_pipe = NULL((void*)0);
1790#else
1791 /*
1792 * Don't bother waiting for the child. sync_pipe_close_command
1793 * does this for us on Windows.
1794 */
1795 sync_pipe_kill(*fork_child);
1796#endif
1797 return sync_pipe_close_command(read_fd, NULL((void*)0), fork_child, msg);
1798}
1799
1800/* read a number of bytes from a pipe */
1801/* (blocks until enough bytes read or an error occurs) */
1802static ssize_t
1803pipe_read_bytes(GIOChannel *pipe_io, char *bytes, size_t required, char **msg)
1804{
1805 GError *err = NULL((void*)0);
1806 size_t newly;
1807 size_t offset = 0;
1808
1809 /* This should never happen, as "required" should be no greater than 2^24. */
1810 if (required > SSIZE_MAX9223372036854775807L) {
1811 ws_debug("read from pipe %p: bytes to read %zu > %zu", pipe_io, required, SSIZE_MAX)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1811, __func__, "read from pipe %p: bytes to read %zu > %zu"
, pipe_io, required, 9223372036854775807L); } } while (0)
;
1812 *msg = ws_strdup_printf("Error reading from sync pipe: bytes to read %zu > %zu", required, SSIZE_MAX)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: bytes to read %zu > %zu"
, required, 9223372036854775807L)
;
1813 return -1;
1814 }
1815 while(required) {
1816 if (g_io_channel_read_chars(pipe_io, &bytes[offset], required, &newly, &err) == G_IO_STATUS_ERROR) {
1817 if (err != NULL((void*)0)) {
1818 ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1818, __func__, "read from pipe %p: error(%u): %s", pipe_io
, err->code, err->message); } } while (0)
;
1819 *msg = ws_strdup_printf("Error reading from sync pipe: %s", err->message)wmem_strdup_printf(((void*)0), "Error reading from sync pipe: %s"
, err->message)
;
1820 g_clear_error(&err);
1821 } else {
1822 ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1822, __func__, "read from pipe %p: unknown error", pipe_io
); } } while (0)
;
1823 *msg = ws_strdup_printf("Error reading from sync pipe: unknown error")wmem_strdup_printf(((void*)0), "Error reading from sync pipe: unknown error"
)
;
1824 }
1825 return -1;
1826 }
1827 if (newly == 0) {
1828 /* EOF */
1829 ws_debug("read from pipe %p: EOF (capture closed?)", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1829, __func__, "read from pipe %p: EOF (capture closed?)",
pipe_io); } } while (0)
;
1830 *msg = NULL((void*)0);
1831 /*
1832 * offset is, at this point, known to be less than the value of
1833 * required passed to us, which is guaranteed to fit in an ssize_t.
1834 */
1835 return (ssize_t)offset;
1836 }
1837
1838 required -= newly;
1839 offset += newly;
1840 }
1841
1842 /*
1843 * offset is, at this point, known to be equal to the value of
1844 * required passed to us, which is guaranteed to fit in an ssize_t.
1845 */
1846 *msg = NULL((void*)0);
1847 return (ssize_t)offset;
1848}
1849
1850/*
1851 * Read a line from a pipe; similar to fgets, but doesn't block.
1852 *
1853 * XXX - just stops reading if there's nothing to be read right now;
1854 * that could conceivably mean that you don't get a complete line.
1855 */
1856int
1857sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
1858 ssize_t newly;
1859 int offset = -1;
1860
1861 while(offset < max - 1) {
1862 offset++;
1863 if (! ws_pipe_data_available(pipe_fd))
1864 break;
1865 newly = ws_readread(pipe_fd, &bytes[offset], 1);
1866 if (newly == 0) {
1867 /* EOF - not necessarily an error */
1868 break;
1869 } else if (newly == -1) {
1870 /* error */
1871 ws_debug("read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1871, __func__, "read from pipe %d: error(%u): %s", pipe_fd
, (*__errno_location ()), g_strerror((*__errno_location ())))
; } } while (0)
;
1872 return -1;
1873 } else if (bytes[offset] == '\n') {
1874 break;
1875 }
1876 }
1877
1878 if (offset >= 0)
1879 bytes[offset] = '\0';
1880
1881 return offset;
1882}
1883
1884
1885/* convert header values (indicator and 3-byte length) */
1886static void
1887pipe_convert_header(const unsigned char *header, char *indicator, unsigned *block_len) {
1888
1889 /* convert header values */
1890 *indicator = pntohu8(&header[0]);
1891 *block_len = pntohu24(&header[1]);
1892}
1893
1894/* read a message from the sending pipe in the standard format
1895 (1-byte message indicator, 3-byte message length (excluding length
1896 and indicator field), and the rest is the message) */
1897static ssize_t
1898pipe_read_block(GIOChannel *pipe_io, char *indicator, unsigned len, char *msg,
1899 char **err_msg)
1900{
1901 unsigned required;
1902 ssize_t newly;
1903 char header[4];
1904
1905 /* read header (indicator and 3-byte length) */
1906 newly = pipe_read_bytes(pipe_io, header, 4, err_msg);
1907 if(newly != 4) {
1908 if(newly != -1) {
1909 /*
1910 * Error; *err_msg has been set.
1911 */
1912 ws_debug("read %p got an error reading header: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1912, __func__, "read %p got an error reading header: %s", pipe_io
, *err_msg); } } while (0)
;
1913 return -1;
1914 }
1915 if(newly == 0) {
1916 /*
1917 * Immediate EOF; if the capture child exits normally, this
1918 * is an "I'm done" indication, so don't report it as an
1919 * error.
1920 */
1921 ws_debug("read %p got an EOF reading header", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1921, __func__, "read %p got an EOF reading header", pipe_io
); } } while (0)
;
1922 return 0;
1923 }
1924 /*
1925 * Short read, but not an immediate EOF.
1926 */
1927 ws_debug("read %p got premature EOF reading header: %zd", pipe_io, newly)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1927, __func__, "read %p got premature EOF reading header: %zd"
, pipe_io, newly); } } while (0)
;
1928 *err_msg = ws_strdup_printf("Premature EOF reading from sync pipe: got only %zd bytes",wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes"
, newly)
1929 newly)wmem_strdup_printf(((void*)0), "Premature EOF reading from sync pipe: got only %zd bytes"
, newly)
;
1930 return -1;
1931 }
1932
1933 /* convert header values */
1934 pipe_convert_header((unsigned char*)header, indicator, &required);
1935
1936 /* only indicator with no value? */
1937 if(required == 0) {
1938 ws_debug("read %p indicator: %c empty value", pipe_io, *indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1938, __func__, "read %p indicator: %c empty value", pipe_io
, *indicator); } } while (0)
;
1939 return 4;
1940 }
1941
1942 /* does the data fit into the given buffer? */
1943 if(required > len) {
1944 size_t bytes_read;
1945 GError *err = NULL((void*)0);
1946 ws_debug("read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1948, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
1947 pipe_io, required, len,do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1948, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
1948 header[0], header[1], header[2], header[3])do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1948, __func__, "read %p length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x"
, pipe_io, required, len, header[0], header[1], header[2], header
[3]); } } while (0)
;
1949
1950 /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
1951 if (g_io_channel_read_chars(pipe_io, msg, len, &bytes_read, &err) == G_IO_STATUS_ERROR) {
1952 if (err != NULL((void*)0)) { /* error */
1953 ws_debug("read from pipe %p: error(%u): %s", pipe_io, err->code, err->message)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1953, __func__, "read from pipe %p: error(%u): %s", pipe_io
, err->code, err->message); } } while (0)
;
1954 g_clear_error(&err);
1955 } else {
1956 ws_debug("read from pipe %p: unknown error", pipe_io)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1956, __func__, "read from pipe %p: unknown error", pipe_io
); } } while (0)
;
1957 }
1958 }
1959 *err_msg = ws_strdup_printf("Message %c from dumpcap with length %d > buffer size %d! Partial message: %s",wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s"
, *indicator, required, len, msg)
1960 *indicator, required, len, msg)wmem_strdup_printf(((void*)0), "Message %c from dumpcap with length %d > buffer size %d! Partial message: %s"
, *indicator, required, len, msg)
;
1961 return -1;
1962 }
1963 len = required;
1964
1965 /* read the actual block data */
1966 newly = pipe_read_bytes(pipe_io, msg, required, err_msg);
1967 if(newly == -1) {
1968 /*
1969 * Error; *err_msg has been set.
1970 */
1971 ws_debug("read %p got an error reading block data: %s", pipe_io, *err_msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1971, __func__, "read %p got an error reading block data: %s"
, pipe_io, *err_msg); } } while (0)
;
1972 return -1;
1973 }
1974
1975 /*
1976 * newly is guaranteed to be >= 0 at this point, as pipe_read_bytes()
1977 * either returns -1 on an error, a positive value <= required on
1978 * a short read, or required on a non-short read.
1979 */
1980 if((size_t)newly != required) {
1981 *err_msg = ws_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s"
, msg)
1982 msg)wmem_strdup_printf(((void*)0), "Unknown message from dumpcap reading data, try to show it as a string: %s"
, msg)
;
1983 return -1;
1984 }
1985
1986 /* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
1987 ws_debug("read %p ok indicator: %c len: %u msg: %s", pipe_io, *indicator, len, msg)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 1987, __func__, "read %p ok indicator: %c len: %u msg: %s",
pipe_io, *indicator, len, msg); } } while (0)
;
1988 *err_msg = NULL((void*)0);
1989 return newly + 4;
1990}
1991
1992
1993/* There's stuff to read from the sync pipe, meaning the child has sent
1994 us a message, or the sync pipe has closed, meaning the child has
1995 closed it (perhaps because it exited). */
1996static gboolean
1997sync_pipe_input_cb(GIOChannel *pipe_io, capture_session *cap_session)
1998{
1999 int ret;
2000 char *buffer = g_malloc(SP_MAX_MSG_LEN(512 * 1000) + 1);
2001 ssize_t nread;
2002 char indicator;
2003 int32_t exec_errno = 0;
2004 int primary_len;
2005 char *primary_msg;
2006 int secondary_len;
2007 char *secondary_msg;
2008 char *wait_msg, *combined_msg;
2009 uint32_t npackets = 0;
2010
2011 nread = pipe_read_block(pipe_io, &indicator, SP_MAX_MSG_LEN(512 * 1000), buffer,
2012 &primary_msg);
2013 if(nread <= 0) {
2014 /* We got a read error, or a bad message, or an EOF, from the sync pipe.
2015
2016 If we got a read error or a bad message, nread is -1 and
2017 primary_msg is set to point to an error message. We don't
2018 have to worry about killing the child; usually this error
2019 is caused as the child killed itself while going down.
2020 Even in the rare cases that this isn't the case, the child
2021 will get an error when writing to the broken pipe the next time,
2022 cleaning itself up then.
2023
2024 If we got an EOF, nread is 0 and primary_msg isn't set. This
2025 is an indication that the capture is finished. */
2026 ret = sync_pipe_wait_for_child(cap_session->fork_child, &wait_msg);
2027 if(nread == 0) {
2028 /* We got an EOF from the sync pipe. That means that the capture
2029 child exited, and not in the middle of a message; we treat
2030 that as an indication that it's done, and only report an
2031 error if ret is -1, in which case wait_msg is the error
2032 message. */
2033 if (ret == -1)
2034 primary_msg = wait_msg;
2035 } else {
2036 /* We got an error from the sync pipe. If ret is -1, report
2037 both the sync pipe I/O error and the wait error. */
2038 if (ret == -1) {
2039 combined_msg = ws_strdup_printf("%s\n\n%s", primary_msg, wait_msg)wmem_strdup_printf(((void*)0), "%s\n\n%s", primary_msg, wait_msg
)
;
2040 g_free(primary_msg);
2041 g_free(wait_msg);
2042 primary_msg = combined_msg;
2043 }
2044 }
2045
2046 /* No more child process. */
2047 cap_session->fork_child = WS_INVALID_PID-1;
2048 cap_session->fork_child_status = ret;
2049
2050#ifdef _WIN32
2051 ws_closeclose(cap_session->signal_pipe_write_fd);
2052#endif
2053 cap_session->capture_opts->closed_msg = primary_msg;
2054 if (extcap_session_stop(cap_session)) {
2055 capture_process_finished(cap_session);
2056 } else {
2057 extcap_request_stop(cap_session);
2058 }
2059 g_free(buffer);
2060 return false0;
2061 }
2062
2063 /* we got a valid message block from the child, process it */
2064 switch(indicator) {
2065 case SP_FILE'F':
2066 if(!cap_session->new_file(cap_session, buffer)) {
2067 ws_debug("file failed, closing capture")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2067, __func__, "file failed, closing capture"); } } while (
0)
;
2068
2069 /* We weren't able to open the new capture file; user has been
2070 alerted. The sync pipe will close after we return false. */
2071
2072 /* The child has sent us a filename which we couldn't open.
2073
2074 This could mean that the child is creating and deleting files
2075 (ring buffer mode) faster than we can handle it.
2076
2077 That should only be the case for very fast file switches;
2078 We can't do much more than telling the child to stop.
2079 (This is the "emergency brake" if the user e.g. wants to
2080 switch files every second).
2081
2082 This can also happen if the user specified "-", meaning
2083 "standard output", as the capture file. */
2084 sync_pipe_stop(cap_session);
2085 cap_session->closed(cap_session, NULL((void*)0));
2086 g_free(buffer);
2087 return false0;
2088 }
2089 break;
2090 case SP_PACKET_COUNT'P':
2091 if (!ws_strtou32(buffer, NULL((void*)0), &npackets)) {
2092 ws_warning("Invalid packets number: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2092, __func__, "Invalid packets number: %s", buffer); } } while
(0)
;
2093 }
2094 ws_debug("new packets %u", npackets)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2094, __func__, "new packets %u", npackets); } } while (0)
;
2095 cap_session->count += npackets;
2096 cap_session->new_packets(cap_session, npackets);
2097 break;
2098 case SP_EXEC_FAILED'X':
2099 /*
2100 * Exec of dumpcap failed. Get the errno for the failure.
2101 */
2102 if (!ws_strtoi32(buffer, NULL((void*)0), &exec_errno)) {
2103 ws_warning("Invalid errno: %s", buffer)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2103, __func__, "Invalid errno: %s", buffer); } } while (0)
;
2104 }
2105 primary_msg = ws_strdup_printf("Couldn't run dumpcap in child process: %s",wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
2106 g_strerror(exec_errno))wmem_strdup_printf(((void*)0), "Couldn't run dumpcap in child process: %s"
, g_strerror(exec_errno))
;
2107 cap_session->error(cap_session, primary_msg, NULL((void*)0));
2108 /* the capture child will close the sync_pipe, nothing to do for now */
2109 /* (an error message doesn't mean we have to stop capturing) */
2110 break;
2111 case SP_ERROR_MSG'E':
2112 /* convert primary message */
2113 pipe_convert_header((unsigned char*)buffer, &indicator, &primary_len);
2114 primary_msg = buffer+4;
2115 /* convert secondary message */
2116 pipe_convert_header((unsigned char*)primary_msg + primary_len, &indicator, &secondary_len);
2117 secondary_msg = primary_msg + primary_len + 4;
2118 /* message output */
2119 cap_session->error(cap_session, primary_msg, secondary_msg);
2120 /* the capture child will close the sync_pipe, nothing to do for now */
2121 /* (an error message doesn't mean we have to stop capturing) */
2122 break;
2123 case SP_LOG_MSG'L':
2124 /*
2125 * Log from dumpcap; pass to our log
2126 */
2127 sync_pipe_handle_log_msg(buffer);
2128 break;
2129 case SP_BAD_FILTER'B': {
2130 const char *message=NULL((void*)0);
2131 uint32_t indx = 0;
2132 const char* end;
2133
2134 if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
2135 message = end + 1;
2136 }
2137
2138 cap_session->cfilter_error(cap_session, indx, message);
2139 /* the capture child will close the sync_pipe, nothing to do for now */
2140 break;
2141 }
2142 case SP_DROPS'D': {
2143 const char *name = NULL((void*)0);
2144 const char* end;
2145 uint32_t num = 0;
2146
2147 if (ws_strtou32(buffer, &end, &num) && end[0] == ':') {
2148 name = end + 1;
2149 }
2150
2151 cap_session->drops(cap_session, num, name);
2152 break;
2153 }
2154 default:
2155 if (g_ascii_isprint(indicator)((g_ascii_table[(guchar) (indicator)] & G_ASCII_PRINT) !=
0)
)
2156 ws_warning("Unknown indicator '%c'", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2156, __func__, "Unknown indicator '%c'", indicator); } } while
(0)
;
2157 else
2158 ws_warning("Unknown indicator '\\x%02x", indicator)do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2158, __func__, "Unknown indicator '\\x%02x", indicator); }
} while (0)
;
2159 break;
2160 }
2161
2162 g_free(buffer);
2163 return true1;
2164}
2165
2166
2167
2168/*
2169 * dumpcap is exiting; wait for it to exit. On success, *msgp is
2170 * unchanged, and the exit status of dumpcap is returned. On
2171 * failure (which includes "dumpcap exited due to being killed by
2172 * a signal or an exception"), *msgp points to an error message
2173 * for the failure, and -1 is returned. In the latter case, *msgp
2174 * must be freed with g_free().
2175 */
2176static int
2177sync_pipe_wait_for_child(ws_process_id fork_child, char **msgp)
2178{
2179 int fork_child_status;
2180#ifndef _WIN32
2181 int retry_waitpid = 3;
2182#endif
2183 int ret = -1;
2184 int64_t start_time;
2185 double elapsed;
2186
2187 start_time = g_get_monotonic_time();
2188
2189 ws_debug("wait till child closed")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2189, __func__, "wait till child closed"); } } while (0)
;
2190 ws_assert(fork_child != WS_INVALID_PID)do { if ((1) && !(fork_child != -1)) ws_log_fatal_full
("Capture", LOG_LEVEL_ERROR, "capture/capture_sync.c", 2190, __func__
, "assertion failed: %s", "fork_child != -1"); } while (0)
;
2191
2192 *msgp = NULL((void*)0); /* assume no error */
2193#ifdef _WIN32
2194 if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
2195 *msgp = ws_strdup_printf("Error from cwait(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from cwait(): %s", g_strerror
((*__errno_location ())))
;
2196 ret = -1;
2197 } else {
2198 /*
2199 * The child exited; return its exit status. Do not treat this as
2200 * an error.
2201 */
2202 ret = fork_child_status;
2203 if ((fork_child_status & 0xC0000000) == ERROR_SEVERITY_ERROR) {
2204 /* Probably an exception code */
2205 *msgp = ws_strdup_printf("Child dumpcap process died: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s"
, win32strexception(fork_child_status))
2206 win32strexception(fork_child_status))wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s"
, win32strexception(fork_child_status))
;
2207 ret = -1;
2208 }
2209 }
2210#else
2211 while (--retry_waitpid >= 0) {
2212 if (waitpid(fork_child, &fork_child_status, 0) != -1) {
2213 /* waitpid() succeeded */
2214 if (WIFEXITED(fork_child_status)(((fork_child_status) & 0x7f) == 0)) {
2215 /*
2216 * The child exited; return its exit status. Do not treat this as
2217 * an error.
2218 */
2219 ret = WEXITSTATUS(fork_child_status)(((fork_child_status) & 0xff00) >> 8);
2220 } else if (WIFSTOPPED(fork_child_status)(((fork_child_status) & 0xff) == 0x7f)) {
2221 /* It stopped, rather than exiting. "Should not happen." */
2222 *msgp = ws_strdup_printf("Child dumpcap process stopped: %s",wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s"
, sync_pipe_signame((((fork_child_status) & 0xff00) >>
8)))
2223 sync_pipe_signame(WSTOPSIG(fork_child_status)))wmem_strdup_printf(((void*)0), "Child dumpcap process stopped: %s"
, sync_pipe_signame((((fork_child_status) & 0xff00) >>
8)))
;
2224 ret = -1;
2225 } else if (WIFSIGNALED(fork_child_status)(((signed char) (((fork_child_status) & 0x7f) + 1) >>
1) > 0)
) {
2226 /* It died with a signal. */
2227 *msgp = ws_strdup_printf("Child dumpcap process died: %s%s",wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
2228 sync_pipe_signame(WTERMSIG(fork_child_status)),wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
2229 WCOREDUMP(fork_child_status) ? " - core dumped" : "")wmem_strdup_printf(((void*)0), "Child dumpcap process died: %s%s"
, sync_pipe_signame(((fork_child_status) & 0x7f)), ((fork_child_status
) & 0x80) ? " - core dumped" : "")
;
2230 ret = -1;
2231 } else {
2232 /* What? It had to either have exited, or stopped, or died with
2233 a signal; what happened here? */
2234 *msgp = ws_strdup_printf("Bad status from waitpid(): %#o",wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o"
, fork_child_status)
2235 fork_child_status)wmem_strdup_printf(((void*)0), "Bad status from waitpid(): %#o"
, fork_child_status)
;
2236 ret = -1;
2237 }
2238 } else {
2239 /* waitpid() failed */
2240 if (errno(*__errno_location ()) == EINTR4) {
2241 /*
2242 * Signal interrupted waitpid().
2243 *
2244 * If it's SIGALRM, we just want to keep waiting, in case
2245 * there's some timer using it (e.g., in a GUI toolkit).
2246 *
2247 * If you ^C TShark (or Wireshark), that should deliver
2248 * SIGINT to dumpcap as well. dumpcap catches SIGINT,
2249 * and should clean up and exit, so we should eventually
2250 * see that and clean up and terminate.
2251 *
2252 * If we're sent a SIGTERM, we should (and do) catch it,
2253 * and TShark, at least, calls sync_pipe_stop(). which
2254 * kills dumpcap, so we should eventually see that and
2255 * clean up and terminate.
2256 */
2257 ws_warning("waitpid returned EINTR. retrying.")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2257, __func__, "waitpid returned EINTR. retrying."); } } while
(0)
;
2258 continue;
2259 } else if (errno(*__errno_location ()) == ECHILD10) {
2260 /*
2261 * The process identified by fork_child either doesn't
2262 * exist any more or isn't our child process (anymore?).
2263 *
2264 * echld might have already reaped the child.
2265 */
2266 ret = fetch_dumpcap_pid ? 0 : -1;
2267 } else {
2268 /* Unknown error. */
2269 *msgp = ws_strdup_printf("Error from waitpid(): %s", g_strerror(errno))wmem_strdup_printf(((void*)0), "Error from waitpid(): %s", g_strerror
((*__errno_location ())))
;
2270 ret = -1;
2271 }
2272 }
2273 break;
2274 }
2275#endif
2276
2277 elapsed = (g_get_monotonic_time() - start_time) / 1e6;
2278 ws_debug("capture child closed after %.3fs", elapsed)do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2278, __func__, "capture child closed after %.3fs", elapsed
); } } while (0)
;
2279 return ret;
2280}
2281
2282
2283#ifndef _WIN32
2284/* convert signal to corresponding name */
2285static const char *
2286sync_pipe_signame(int sig)
2287{
2288 const char *sigmsg;
2289 static char sigmsg_buf[6+1+3+1];
2290
2291 switch (sig) {
2292
2293 case SIGHUP1:
2294 sigmsg = "Hangup";
2295 break;
2296
2297 case SIGINT2:
2298 sigmsg = "Interrupted";
2299 break;
2300
2301 case SIGQUIT3:
2302 sigmsg = "Quit";
2303 break;
2304
2305 case SIGILL4:
2306 sigmsg = "Illegal instruction";
2307 break;
2308
2309 case SIGTRAP5:
2310 sigmsg = "Trace trap";
2311 break;
2312
2313 case SIGABRT6:
2314 sigmsg = "Abort";
2315 break;
2316
2317 case SIGFPE8:
2318 sigmsg = "Arithmetic exception";
2319 break;
2320
2321 case SIGKILL9:
2322 sigmsg = "Killed";
2323 break;
2324
2325 case SIGBUS7:
2326 sigmsg = "Bus error";
2327 break;
2328
2329 case SIGSEGV11:
2330 sigmsg = "Segmentation violation";
2331 break;
2332
2333 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
2334 Linux is POSIX compliant. These are not POSIX-defined signals ---
2335 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
2336
2337 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
2338 were omitted from POSIX.1 because their behavior is
2339 implementation dependent and could not be adequately catego-
2340 rized. Conforming implementations may deliver these sig-
2341 nals, but must document the circumstances under which they
2342 are delivered and note any restrictions concerning their
2343 delivery.''
2344
2345 So we only check for SIGSYS on those systems that happen to
2346 implement them (a system can be POSIX-compliant and implement
2347 them, it's just that POSIX doesn't *require* a POSIX-compliant
2348 system to implement them).
2349 */
2350
2351#ifdef SIGSYS31
2352 case SIGSYS31:
2353 sigmsg = "Bad system call";
2354 break;
2355#endif
2356
2357 case SIGPIPE13:
2358 sigmsg = "Broken pipe";
2359 break;
2360
2361 case SIGALRM14:
2362 sigmsg = "Alarm clock";
2363 break;
2364
2365 case SIGTERM15:
2366 sigmsg = "Terminated";
2367 break;
2368
2369 default:
2370 /* Returning a static buffer is ok in the context we use it here */
2371 snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
2372 sigmsg = sigmsg_buf;
2373 break;
2374 }
2375 return sigmsg;
2376}
2377#endif
2378
2379
2380#ifdef _WIN32
2381
2382static int create_dummy_signal_pipe(char **msg) {
2383 char *dummy_signal_pipe_name;
2384
2385 if (dummy_signal_pipe != NULL((void*)0)) return 0;
2386
2387 if (!dummy_control_id) {
2388 dummy_control_id = ws_strdup_printf("%ld.dummy", GetCurrentProcessId())wmem_strdup_printf(((void*)0), "%ld.dummy", GetCurrentProcessId
())
;
2389 }
2390
2391 /* Create the signal pipe */
2392 dummy_signal_pipe_name = ws_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id)wmem_strdup_printf(((void*)0), SIGNAL_PIPE_FORMAT, dummy_control_id
)
;
2393 dummy_signal_pipe = CreateNamedPipe(utf_8to16(dummy_signal_pipe_name),
2394 PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL((void*)0));
2395 g_free(dummy_signal_pipe_name);
2396 if (dummy_signal_pipe == INVALID_HANDLE_VALUE) {
2397 *msg = ws_strdup_printf("Couldn't create signal pipe: %s",wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
2398 win32strerror(GetLastError()))wmem_strdup_printf(((void*)0), "Couldn't create signal pipe: %s"
, win32strerror(GetLastError()))
;
2399 return -1;
2400 }
2401 return 0;
2402}
2403
2404/* tell the child through the signal pipe that we want to quit the capture */
2405static void
2406signal_pipe_capquit_to_child(capture_session *cap_session)
2407{
2408 const char quit_msg[] = "QUIT";
2409 int ret;
2410
2411 ws_debug("signal_pipe_capquit_to_child")do { if (1) { ws_log_full("Capture", LOG_LEVEL_DEBUG, "capture/capture_sync.c"
, 2411, __func__, "signal_pipe_capquit_to_child"); } } while (
0)
;
2412
2413 /* it doesn't matter *what* we send here, the first byte will stop the capture */
2414 /* simply sending a "QUIT" string */
2415 /*sync_pipe_write_string_msg(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
2416 ret = ws_writewrite(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
2417 if(ret == -1) {
2418 ws_warning("%d header: error %s", cap_session->signal_pipe_write_fd, win32strerror(GetLastError()))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2418, __func__, "%d header: error %s", cap_session->signal_pipe_write_fd
, win32strerror(GetLastError())); } } while (0)
;
2419 }
2420}
2421#endif
2422
2423
2424/* user wants to stop the capture run */
2425void
2426sync_pipe_stop(capture_session *cap_session)
2427{
2428 if (cap_session->fork_child != WS_INVALID_PID-1) {
2429#ifndef _WIN32
2430 /* send the SIGINT signal to close the capture child gracefully. */
2431 int sts = kill(cap_session->fork_child, SIGINT2);
2432 if (sts != 0) {
2433 ws_warning("Sending SIGINT to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2433, __func__, "Sending SIGINT to child failed: %s\n", g_strerror
((*__errno_location ()))); } } while (0)
;
2434 }
2435#else
2436#define STOP_SLEEP_TIME 500 /* ms */
2437 DWORD status;
2438
2439 /* First, use the special signal pipe to try to close the capture child
2440 * gracefully.
2441 */
2442 signal_pipe_capquit_to_child(cap_session);
2443
2444 /* Next, wait for the process to exit on its own */
2445 status = WaitForSingleObject((HANDLE) cap_session->fork_child, STOP_SLEEP_TIME);
2446
2447 /* Force the issue. */
2448 if (status != WAIT_OBJECT_0) {
2449 ws_warning("sync_pipe_stop: forcing child to exit")do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2449, __func__, "sync_pipe_stop: forcing child to exit"); }
} while (0)
;
2450 sync_pipe_kill(cap_session->fork_child);
2451 }
2452#endif
2453 }
2454}
2455
2456
2457/* Wireshark has to exit, force the capture child to close */
2458void
2459sync_pipe_kill(ws_process_id fork_child)
2460{
2461 if (fork_child != WS_INVALID_PID-1) {
2462#ifndef _WIN32
2463 int sts = kill(fork_child, SIGTERM15); /* SIGTERM so it can clean up if necessary */
2464 if (sts != 0) {
2465 ws_warning("Sending SIGTERM to child failed: %s\n", g_strerror(errno))do { if (1) { ws_log_full("Capture", LOG_LEVEL_WARNING, "capture/capture_sync.c"
, 2465, __func__, "Sending SIGTERM to child failed: %s\n", g_strerror
((*__errno_location ()))); } } while (0)
;
2466 }
2467#else
2468 /* Remark: This is not the preferred method of closing a process!
2469 * the clean way would be getting the process id of the child process,
2470 * then getting window handle hWnd of that process (using EnumChildWindows),
2471 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
2472 *
2473 * Unfortunately, I don't know how to get the process id from the
2474 * handle. OpenProcess will get an handle (not a window handle)
2475 * from the process ID; it will not get a window handle from the
2476 * process ID. (How could it? A process can have more than one
2477 * window. For that matter, a process might have *no* windows,
2478 * as a process running dumpcap, the normal child process program,
2479 * probably does.)
2480 *
2481 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
2482 * running in the same console; that's not necessarily the case for
2483 * us, as we might not be running in a console.
2484 * And this also will require to have the process id.
2485 */
2486 TerminateProcess((HANDLE) (fork_child), 0);
2487
2488#endif
2489 }
2490}
2491
2492void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid)) {
2493 fetch_dumpcap_pid = cb;
2494}
2495
2496#endif /* HAVE_LIBPCAP */