### Bug Summary

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