### Bug Summary

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

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
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-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D CARES_NO_DEPRECATED -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-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../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-nonliteral -std=gnu17 -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 -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-08-13-100404-3660-1 -x c /builds/wireshark/wireshark/capture/capture_sync.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

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