### Bug Summary

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