2 * Synchronisation between Ethereal capture parent and child instances
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
50 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
51 * macros) on UNIX systems that don't have them.
54 # define WIFEXITED(status) (((status) & 0177) == 0)
57 # define WIFSTOPPED(status) (((status) & 0177) == 0177)
60 # define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
63 # define WEXITSTATUS(status) ((status) >> 8)
66 # define WTERMSIG(status) ((status) & 0177)
69 # define WCOREDUMP(status) ((status) & 0200)
72 # define WSTOPSIG(status) ((status) >> 8)
76 #include <epan/packet.h>
77 #include <epan/prefs.h>
83 #include "capture_sync.h"
84 #include "simple_dialog.h"
87 #include "capture-wpcap.h"
96 #include <process.h> /* For spawning child process */
99 /* Win32 needs the O_BINARY flag for open() */
106 static char *sync_pipe_signame(int);
110 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
111 static void sync_pipe_wait_for_child(int fork_child, gboolean always_report);
113 /* Size of buffer to hold decimal representation of
114 signed/unsigned 64-bit int */
115 #define SP_DECISIZE 20
118 * Indications sent out on the sync pipe.
120 #define SP_CAPSTART ';' /* capture start message */
121 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
122 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
123 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
128 sync_pipe_capstart_to_parent(void)
130 static const char capstart_msg = SP_CAPSTART;
132 write(1, &capstart_msg, 1);
136 sync_pipe_packet_count_to_parent(int packet_count)
138 char tmp[SP_DECISIZE+1+1];
139 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
140 write(1, tmp, strlen(tmp));
144 sync_pipe_errmsg_to_parent(const char *errmsg)
146 int msglen = strlen(errmsg);
147 char lenbuf[SP_DECISIZE+1+1];
149 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
150 write(1, lenbuf, strlen(lenbuf));
151 write(1, errmsg, msglen);
155 sync_pipe_drops_to_parent(int drops)
157 char tmp[SP_DECISIZE+1+1];
158 sprintf(tmp, "%d%c", drops, SP_DROPS);
159 write(1, tmp, strlen(tmp));
163 /* Add a string pointer to a NULL-terminated array of string pointers. */
165 sync_pipe_add_arg(char **args, int *argc, char *arg)
167 /* Grow the array; "*argc" currently contains the number of string
168 pointers, *not* counting the NULL pointer at the end, so we have
169 to add 2 in order to get the new size of the array, including the
170 new pointer and the terminating NULL pointer. */
171 args = g_realloc(args, (*argc + 2) * sizeof (char *));
173 /* Stuff the pointer into the penultimate element of the array, which
174 is the one at the index specified by "*argc". */
177 /* Now bump the count. */
180 /* We overwrite the NULL pointer; put it back right after the
188 /* Given a string, return a pointer to a quote-encapsulated version of
189 the string, so we can pass it as an argument with "spawnvp" even
190 if it contains blanks. */
192 sync_pipe_quote_encapsulate(const char *string)
194 char *encapsulated_string;
196 encapsulated_string = g_new(char, strlen(string) + 3);
197 sprintf(encapsulated_string, "\"%s\"", string);
198 return encapsulated_string;
205 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
212 char scount[24]; /* need a constant for len of numbers */
213 char sautostop_filesize[24]; /* need a constant for len of numbers */
214 char sautostop_duration[24]; /* need a constant for len of numbers */
215 char save_file_fd_str[24];
223 char sync_pipe_fd[24];
227 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
228 int sync_pipe[2]; /* pipes used to sync between instances */
230 capture_opts->fork_child = -1;
232 /* Allocate the string pointer array with enough space for the
233 terminating NULL pointer. */
235 argv = g_malloc(sizeof (char *));
238 /* Now add those arguments used on all platforms. */
239 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
241 argv = sync_pipe_add_arg(argv, &argc, "-i");
242 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
244 argv = sync_pipe_add_arg(argv, &argc, "-w");
245 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
247 argv = sync_pipe_add_arg(argv, &argc, "-W");
248 sprintf(save_file_fd_str,"%d",capture_opts->save_file_fd); /* in lieu of itoa */
249 argv = sync_pipe_add_arg(argv, &argc, save_file_fd_str);
251 if (capture_opts->has_autostop_packets) {
252 argv = sync_pipe_add_arg(argv, &argc, "-c");
253 sprintf(scount,"%d",capture_opts->autostop_packets);
254 argv = sync_pipe_add_arg(argv, &argc, scount);
257 if (capture_opts->has_snaplen) {
258 argv = sync_pipe_add_arg(argv, &argc, "-s");
259 sprintf(ssnap,"%d",capture_opts->snaplen);
260 argv = sync_pipe_add_arg(argv, &argc, ssnap);
263 if (capture_opts->linktype != -1) {
264 argv = sync_pipe_add_arg(argv, &argc, "-y");
265 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
266 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
268 /* XXX - just treat it as a number */
269 sprintf(ssnap,"%d",capture_opts->linktype);
271 argv = sync_pipe_add_arg(argv, &argc, ssnap);
274 if (capture_opts->has_autostop_filesize) {
275 argv = sync_pipe_add_arg(argv, &argc, "-a");
276 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
277 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
280 if (capture_opts->has_autostop_duration) {
281 argv = sync_pipe_add_arg(argv, &argc, "-a");
282 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
283 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
286 if (!capture_opts->show_info) {
287 argv = sync_pipe_add_arg(argv, &argc, "-H");
290 if (!capture_opts->promisc_mode)
291 argv = sync_pipe_add_arg(argv, &argc, "-p");
294 /* Create a pipe for the child process */
296 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
297 /* Couldn't create the pipe between parent and child. */
299 unlink(capture_opts->save_file);
300 g_free(capture_opts->save_file);
301 capture_opts->save_file = NULL;
302 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
307 /* Convert font name to a quote-encapsulated string and pass to child */
308 argv = sync_pipe_add_arg(argv, &argc, "-m");
309 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
310 argv = sync_pipe_add_arg(argv, &argc, fontstring);
312 /* Convert pipe write handle to a string and pass to child */
313 argv = sync_pipe_add_arg(argv, &argc, "-Z");
314 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
315 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
317 /* Convert filter string to a quote delimited string and pass to child */
319 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
320 argv = sync_pipe_add_arg(argv, &argc, "-f");
321 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
322 argv = sync_pipe_add_arg(argv, &argc, filterstring);
326 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
329 g_free(filterstring);
332 if (pipe(sync_pipe) < 0) {
333 /* Couldn't create the pipe between parent and child. */
335 unlink(capture_opts->save_file);
336 g_free(capture_opts->save_file);
337 capture_opts->save_file = NULL;
338 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
343 argv = sync_pipe_add_arg(argv, &argc, "-m");
344 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
346 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
347 argv = sync_pipe_add_arg(argv, &argc, "-f");
348 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
351 if ((capture_opts->fork_child = fork()) == 0) {
353 * Child process - run Ethereal with the right arguments to make
354 * it just pop up the live capture dialog box and capture with
355 * the specified capture parameters, writing to the specified file.
357 * args: -i interface specification
359 * -W file descriptor to write
360 * -c count to capture
363 * -f "filter expression"
366 dup(sync_pipe[PIPE_WRITE]);
367 close(sync_pipe[PIPE_READ]);
368 execvp(ethereal_path, argv);
369 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
370 ethereal_path, strerror(errno));
371 sync_pipe_errmsg_to_parent(errmsg);
373 /* Exit with "_exit()", so that we don't close the connection
374 to the X server (and cause stuff buffered up by our parent but
375 not yet sent to be sent, as that stuff should only be sent by
381 /* Parent process - read messages from the child process over the
383 g_free(argv); /* free up arg array */
385 /* Close the write side of the pipe, so that only the child has it
386 open, and thus it completely closes, and thus returns to us
387 an EOF indication, if the child closes it (either deliberately
388 or by exiting abnormally). */
389 close(sync_pipe[PIPE_WRITE]);
391 /* Close the save file FD, as we won't be using it - we'll be opening
392 it and reading the save file through Wiretap. */
393 close(capture_opts->save_file_fd);
395 if (capture_opts->fork_child == -1) {
396 /* We couldn't even create the child process. */
398 close(sync_pipe[PIPE_READ]);
399 unlink(capture_opts->save_file);
400 g_free(capture_opts->save_file);
401 capture_opts->save_file = NULL;
402 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
403 "Couldn't create child process: %s", strerror(error));
407 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
408 colon; if the count is 0, the child process created the
409 capture file and we should start reading from it, otherwise
410 the capture couldn't start and the count is a count of bytes
411 of error message, and we should display the message. */
414 i = read(sync_pipe[PIPE_READ], &c, 1);
416 /* EOF - the child process died.
417 Close the read side of the sync pipe, remove the capture file,
418 and report the failure. */
419 close(sync_pipe[PIPE_READ]);
420 unlink(capture_opts->save_file);
421 g_free(capture_opts->save_file);
422 capture_opts->save_file = NULL;
423 sync_pipe_wait_for_child(capture_opts->fork_child, TRUE);
426 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
429 /* Child process handed us crap.
430 Close the read side of the sync pipe, remove the capture file,
431 and report the failure. */
432 close(sync_pipe[PIPE_READ]);
433 unlink(capture_opts->save_file);
434 g_free(capture_opts->save_file);
435 capture_opts->save_file = NULL;
436 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
437 "Capture child process sent us a bad message");
440 byte_count = byte_count*10 + c - '0';
442 if (c != SP_CAPSTART) {
443 /* Failure - the child process sent us a message indicating
444 what the problem was. */
445 if (byte_count == 0) {
446 /* Zero-length message? */
447 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
448 "Capture child process failed, but its error message was empty.");
450 msg = g_malloc(byte_count + 1);
452 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
453 "Capture child process failed, but its error message was too big.");
455 i = read(sync_pipe[PIPE_READ], msg, byte_count);
456 msg[byte_count] = '\0';
458 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
459 "Capture child process failed: Error %s reading its error message.",
462 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
463 "Capture child process failed: EOF reading its error message.");
464 sync_pipe_wait_for_child(capture_opts->fork_child, FALSE);
466 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
470 /* Close the sync pipe. */
471 close(sync_pipe[PIPE_READ]);
473 /* Get rid of the save file - the capture never started. */
474 unlink(capture_opts->save_file);
475 g_free(capture_opts->save_file);
476 capture_opts->save_file = NULL;
481 /* The child process started a capture.
482 Attempt to open the capture file and set up to read it. */
483 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
485 /* We were able to open and set up to read the capture file;
486 arrange that our callback be called whenever it's possible
487 to read from the sync pipe, so that it's called when
488 the child process wants to tell us something. */
489 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
494 /* We weren't able to open the capture file; user has been
495 alerted. Close the sync pipe. */
497 close(sync_pipe[PIPE_READ]);
499 /* Don't unlink the save file - leave it around, for debugging
501 g_free(capture_opts->save_file);
502 capture_opts->save_file = NULL;
507 g_assert_not_reached();
512 /* There's stuff to read from the sync pipe, meaning the child has sent
513 us a message, or the sync pipe has closed, meaning the child has
514 closed it (perhaps because it exited). */
516 sync_pipe_input_cb(gint source, gpointer user_data)
518 capture_options *capture_opts = (capture_options *)user_data;
519 gint fork_child = capture_opts->fork_child;
521 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
522 int nread, msglen, chars_to_copy;
527 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
528 /* The child has closed the sync pipe, meaning it's not going to be
529 capturing any more packets. Pick up its exit status, and
530 complain if it did anything other than exit with status 0. */
531 sync_pipe_wait_for_child(fork_child, FALSE);
533 /* Read what remains of the capture file, and finish the capture.
534 XXX - do something if this fails? */
535 switch (cf_finish_tail(capture_opts->cf, &err)) {
538 if(cf_packet_count(capture_opts->cf) == 0) {
539 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
540 "%sNo packets captured!%s\n\n"
541 "As no data was captured, closing the %scapture file!",
542 simple_dialog_primary_start(), simple_dialog_primary_end(),
543 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
544 cf_close(capture_opts->cf);
548 /* Just because we got an error, that doesn't mean we were unable
549 to read any of the file; we handle what we could get from the
553 case CF_READ_ABORTED:
554 /* Exit by leaving the main loop, so that any quit functions
555 we registered get called. */
560 /* We're not doing a capture any more, so we don't have a save
562 g_free(capture_opts->save_file);
563 capture_opts->save_file = NULL;
568 buffer[nread] = '\0';
571 /* look for (possibly multiple) indications */
573 case SP_PACKET_COUNT :
580 cf_set_drops_known(capture_opts->cf, TRUE);
581 cf_set_drops(capture_opts->cf, atoi(p));
592 /* Read the entire message.
593 XXX - if the child hasn't sent it all yet, this could cause us
594 to hang until they do. */
595 msg = g_malloc(msglen + 1);
597 while (msglen != 0) {
600 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
605 chars_to_copy = MIN(msglen, nread);
606 memcpy(r, q, chars_to_copy);
609 nread -= chars_to_copy;
610 msglen -= chars_to_copy;
613 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
623 /* Read from the capture file the number of records the child told us
625 XXX - do something if this fails? */
626 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
630 /* Just because we got an error, that doesn't mean we were unable
631 to read any of the file; we handle what we could get from the
634 XXX - abort on a read error? */
637 case CF_READ_ABORTED:
638 /* Kill the child capture process; the user wants to exit, and we
639 shouldn't just leave it running. */
640 capture_kill_child(capture_opts);
648 /* the child process is going down, wait until it's completely terminated */
650 sync_pipe_wait_for_child(int fork_child, gboolean always_report)
655 /* XXX - analyze the wait status and display more information
657 XXX - set "fork_child" to -1 if we find it exited? */
658 if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
659 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
660 "Child capture process stopped unexpectedly");
663 if (wait(&wstatus) != -1) {
664 if (WIFEXITED(wstatus)) {
665 /* The child exited; display its exit status, if it's not zero,
666 and even if it's zero if "always_report" is true. */
667 if (always_report || WEXITSTATUS(wstatus) != 0) {
668 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
669 "Child capture process exited: exit status %d",
670 WEXITSTATUS(wstatus));
672 } else if (WIFSTOPPED(wstatus)) {
673 /* It stopped, rather than exiting. "Should not happen." */
674 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
675 "Child capture process stopped: %s",
676 sync_pipe_signame(WSTOPSIG(wstatus)));
677 } else if (WIFSIGNALED(wstatus)) {
678 /* It died with a signal. */
679 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
680 "Child capture process died: %s%s",
681 sync_pipe_signame(WTERMSIG(wstatus)),
682 WCOREDUMP(wstatus) ? " - core dumped" : "");
684 /* What? It had to either have exited, or stopped, or died with
685 a signal; what happened here? */
686 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
687 "Child capture process died: wait status %#o", wstatus);
691 /* No more child process. */
699 sync_pipe_signame(int sig)
702 static char sigmsg_buf[6+1+3+1];
711 sigmsg = "Interrupted";
719 sigmsg = "Illegal instruction";
723 sigmsg = "Trace trap";
731 sigmsg = "Arithmetic exception";
739 sigmsg = "Bus error";
743 sigmsg = "Segmentation violation";
746 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
747 Linux is POSIX compliant. These are not POSIX-defined signals ---
748 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
750 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
751 were omitted from POSIX.1 because their behavior is
752 implementation dependent and could not be adequately catego-
753 rized. Conforming implementations may deliver these sig-
754 nals, but must document the circumstances under which they
755 are delivered and note any restrictions concerning their
758 So we only check for SIGSYS on those systems that happen to
759 implement them (a system can be POSIX-compliant and implement
760 them, it's just that POSIX doesn't *require* a POSIX-compliant
761 system to implement them).
766 sigmsg = "Bad system call";
771 sigmsg = "Broken pipe";
775 sigmsg = "Alarm clock";
779 sigmsg = "Terminated";
783 sprintf(sigmsg_buf, "Signal %d", sig);
793 sync_pipe_stop(capture_options *capture_opts)
795 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
797 kill(capture_opts->fork_child, SIGUSR1);
799 /* XXX: this is not the preferred method of closing a process!
800 * the clean way would be getting the process id of the child process,
801 * then getting window handle hWnd of that process (using EnumChildWindows),
802 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
804 * Unfortunately, I don't know how to get the process id from the
805 * handle. OpenProcess will get an handle (not a window handle)
806 * from the process ID; it will not get a window handle from the
807 * process ID. (How could it? A process can have more than one
810 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
811 * running in the same console; that's not necessarily the case for
812 * us, as we might not be running in a console.
813 * And this also will require to have the process id.
815 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
822 sync_pipe_kill(capture_options *capture_opts)
824 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
826 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
828 /* XXX: this is not the preferred method of closing a process!
829 * the clean way would be getting the process id of the child process,
830 * then getting window handle hWnd of that process (using EnumChildWindows),
831 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
833 * Unfortunately, I don't know how to get the process id from the
834 * handle. OpenProcess will get an handle (not a window handle)
835 * from the process ID; it will not get a window handle from the
836 * process ID. (How could it? A process can have more than one
839 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
840 * running in the same console; that's not necessarily the case for
841 * us, as we might not be running in a console.
842 * And this also will require to have the process id.
844 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
849 #endif /* HAVE_LIBPCAP */