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.
25 /* With MSVC and a libethereal.dll this file needs to import some variables
26 in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
27 #define _NEED_VAR_IMPORT_
48 #ifdef HAVE_SYS_WAIT_H
49 # include <sys/wait.h>
54 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
55 * macros) on UNIX systems that don't have them.
58 # define WIFEXITED(status) (((status) & 0177) == 0)
61 # define WIFSTOPPED(status) (((status) & 0177) == 0177)
64 # define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
67 # define WEXITSTATUS(status) ((status) >> 8)
70 # define WTERMSIG(status) ((status) & 0177)
73 # define WCOREDUMP(status) ((status) & 0200)
76 # define WSTOPSIG(status) ((status) >> 8)
80 #include <epan/packet.h>
81 #include <epan/prefs.h>
87 #include "capture_sync.h"
88 #include "simple_dialog.h"
91 #include "capture-wpcap.h"
100 #include <process.h> /* For spawning child process */
103 /* Win32 needs the O_BINARY flag for open() */
110 static char *sync_pipe_signame(int);
114 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
115 static void sync_pipe_wait_for_child(int fork_child, gboolean always_report);
117 /* Size of buffer to hold decimal representation of
118 signed/unsigned 64-bit int */
119 #define SP_DECISIZE 20
122 * Indications sent out on the sync pipe.
124 #define SP_CAPSTART ';' /* capture start message */
125 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
126 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
127 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
132 sync_pipe_capstart_to_parent(void)
134 static const char capstart_msg = SP_CAPSTART;
136 write(1, &capstart_msg, 1);
140 sync_pipe_packet_count_to_parent(int packet_count)
142 char tmp[SP_DECISIZE+1+1];
143 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
144 write(1, tmp, strlen(tmp));
148 sync_pipe_errmsg_to_parent(const char *errmsg)
150 int msglen = strlen(errmsg);
151 char lenbuf[SP_DECISIZE+1+1];
153 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
154 write(1, lenbuf, strlen(lenbuf));
155 write(1, errmsg, msglen);
159 sync_pipe_drops_to_parent(int drops)
161 char tmp[SP_DECISIZE+1+1];
162 sprintf(tmp, "%d%c", drops, SP_DROPS);
163 write(1, tmp, strlen(tmp));
167 /* Add a string pointer to a NULL-terminated array of string pointers. */
169 sync_pipe_add_arg(char **args, int *argc, char *arg)
171 /* Grow the array; "*argc" currently contains the number of string
172 pointers, *not* counting the NULL pointer at the end, so we have
173 to add 2 in order to get the new size of the array, including the
174 new pointer and the terminating NULL pointer. */
175 args = g_realloc(args, (*argc + 2) * sizeof (char *));
177 /* Stuff the pointer into the penultimate element of the array, which
178 is the one at the index specified by "*argc". */
181 /* Now bump the count. */
184 /* We overwrite the NULL pointer; put it back right after the
192 /* Given a string, return a pointer to a quote-encapsulated version of
193 the string, so we can pass it as an argument with "spawnvp" even
194 if it contains blanks. */
196 sync_pipe_quote_encapsulate(const char *string)
198 char *encapsulated_string;
200 encapsulated_string = g_new(char, strlen(string) + 3);
201 sprintf(encapsulated_string, "\"%s\"", string);
202 return encapsulated_string;
209 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
216 char scount[24]; /* need a constant for len of numbers */
217 char sautostop_filesize[24]; /* need a constant for len of numbers */
218 char sautostop_duration[24]; /* need a constant for len of numbers */
219 char save_file_fd_str[24];
227 char sync_pipe_fd[24];
231 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
232 int sync_pipe[2]; /* pipes used to sync between instances */
234 capture_opts->fork_child = -1;
236 /* Allocate the string pointer array with enough space for the
237 terminating NULL pointer. */
239 argv = g_malloc(sizeof (char *));
242 /* Now add those arguments used on all platforms. */
243 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
245 argv = sync_pipe_add_arg(argv, &argc, "-i");
246 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
248 argv = sync_pipe_add_arg(argv, &argc, "-w");
249 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
251 argv = sync_pipe_add_arg(argv, &argc, "-W");
252 sprintf(save_file_fd_str,"%d",capture_opts->save_file_fd); /* in lieu of itoa */
253 argv = sync_pipe_add_arg(argv, &argc, save_file_fd_str);
255 if (capture_opts->has_autostop_packets) {
256 argv = sync_pipe_add_arg(argv, &argc, "-c");
257 sprintf(scount,"%d",capture_opts->autostop_packets);
258 argv = sync_pipe_add_arg(argv, &argc, scount);
261 if (capture_opts->has_snaplen) {
262 argv = sync_pipe_add_arg(argv, &argc, "-s");
263 sprintf(ssnap,"%d",capture_opts->snaplen);
264 argv = sync_pipe_add_arg(argv, &argc, ssnap);
267 if (capture_opts->linktype != -1) {
268 argv = sync_pipe_add_arg(argv, &argc, "-y");
269 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
270 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
272 /* XXX - just treat it as a number */
273 sprintf(ssnap,"%d",capture_opts->linktype);
275 argv = sync_pipe_add_arg(argv, &argc, ssnap);
278 if (capture_opts->has_autostop_filesize) {
279 argv = sync_pipe_add_arg(argv, &argc, "-a");
280 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
281 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
284 if (capture_opts->has_autostop_duration) {
285 argv = sync_pipe_add_arg(argv, &argc, "-a");
286 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
287 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
290 if (!capture_opts->show_info) {
291 argv = sync_pipe_add_arg(argv, &argc, "-H");
294 if (!capture_opts->promisc_mode)
295 argv = sync_pipe_add_arg(argv, &argc, "-p");
298 /* Create a pipe for the child process */
300 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
301 /* Couldn't create the pipe between parent and child. */
303 unlink(capture_opts->save_file);
304 g_free(capture_opts->save_file);
305 capture_opts->save_file = NULL;
306 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
311 /* Convert font name to a quote-encapsulated string and pass to child */
312 argv = sync_pipe_add_arg(argv, &argc, "-m");
313 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
314 argv = sync_pipe_add_arg(argv, &argc, fontstring);
316 /* Convert pipe write handle to a string and pass to child */
317 argv = sync_pipe_add_arg(argv, &argc, "-Z");
318 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
319 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
321 /* Convert filter string to a quote delimited string and pass to child */
323 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
324 argv = sync_pipe_add_arg(argv, &argc, "-f");
325 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
326 argv = sync_pipe_add_arg(argv, &argc, filterstring);
330 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
333 g_free(filterstring);
336 if (pipe(sync_pipe) < 0) {
337 /* Couldn't create the pipe between parent and child. */
339 unlink(capture_opts->save_file);
340 g_free(capture_opts->save_file);
341 capture_opts->save_file = NULL;
342 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
347 argv = sync_pipe_add_arg(argv, &argc, "-m");
348 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
350 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
351 argv = sync_pipe_add_arg(argv, &argc, "-f");
352 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
355 if ((capture_opts->fork_child = fork()) == 0) {
357 * Child process - run Ethereal with the right arguments to make
358 * it just pop up the live capture dialog box and capture with
359 * the specified capture parameters, writing to the specified file.
361 * args: -i interface specification
363 * -W file descriptor to write
364 * -c count to capture
367 * -f "filter expression"
370 dup(sync_pipe[PIPE_WRITE]);
371 close(sync_pipe[PIPE_READ]);
372 execvp(ethereal_path, argv);
373 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
374 ethereal_path, strerror(errno));
375 sync_pipe_errmsg_to_parent(errmsg);
377 /* Exit with "_exit()", so that we don't close the connection
378 to the X server (and cause stuff buffered up by our parent but
379 not yet sent to be sent, as that stuff should only be sent by
385 /* Parent process - read messages from the child process over the
387 g_free(argv); /* free up arg array */
389 /* Close the write side of the pipe, so that only the child has it
390 open, and thus it completely closes, and thus returns to us
391 an EOF indication, if the child closes it (either deliberately
392 or by exiting abnormally). */
393 close(sync_pipe[PIPE_WRITE]);
395 /* Close the save file FD, as we won't be using it - we'll be opening
396 it and reading the save file through Wiretap. */
397 close(capture_opts->save_file_fd);
399 if (capture_opts->fork_child == -1) {
400 /* We couldn't even create the child process. */
402 close(sync_pipe[PIPE_READ]);
403 unlink(capture_opts->save_file);
404 g_free(capture_opts->save_file);
405 capture_opts->save_file = NULL;
406 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
407 "Couldn't create child process: %s", strerror(error));
411 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
412 colon; if the count is 0, the child process created the
413 capture file and we should start reading from it, otherwise
414 the capture couldn't start and the count is a count of bytes
415 of error message, and we should display the message. */
418 i = read(sync_pipe[PIPE_READ], &c, 1);
420 /* EOF - the child process died.
421 Close the read side of the sync pipe, remove the capture file,
422 and report the failure. */
423 close(sync_pipe[PIPE_READ]);
424 unlink(capture_opts->save_file);
425 g_free(capture_opts->save_file);
426 capture_opts->save_file = NULL;
427 sync_pipe_wait_for_child(capture_opts->fork_child, TRUE);
430 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
433 /* Child process handed us crap.
434 Close the read side of the sync pipe, remove the capture file,
435 and report the failure. */
436 close(sync_pipe[PIPE_READ]);
437 unlink(capture_opts->save_file);
438 g_free(capture_opts->save_file);
439 capture_opts->save_file = NULL;
440 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
441 "Capture child process sent us a bad message");
444 byte_count = byte_count*10 + c - '0';
446 if (c != SP_CAPSTART) {
447 /* Failure - the child process sent us a message indicating
448 what the problem was. */
449 if (byte_count == 0) {
450 /* Zero-length message? */
451 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
452 "Capture child process failed, but its error message was empty.");
454 msg = g_malloc(byte_count + 1);
456 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
457 "Capture child process failed, but its error message was too big.");
459 i = read(sync_pipe[PIPE_READ], msg, byte_count);
460 msg[byte_count] = '\0';
462 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
463 "Capture child process failed: Error %s reading its error message.",
466 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
467 "Capture child process failed: EOF reading its error message.");
468 sync_pipe_wait_for_child(capture_opts->fork_child, FALSE);
470 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
474 /* Close the sync pipe. */
475 close(sync_pipe[PIPE_READ]);
477 /* Get rid of the save file - the capture never started. */
478 unlink(capture_opts->save_file);
479 g_free(capture_opts->save_file);
480 capture_opts->save_file = NULL;
485 /* The child process started a capture.
486 Attempt to open the capture file and set up to read it. */
487 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
489 /* We were able to open and set up to read the capture file;
490 arrange that our callback be called whenever it's possible
491 to read from the sync pipe, so that it's called when
492 the child process wants to tell us something. */
493 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
498 /* We weren't able to open the capture file; user has been
499 alerted. Close the sync pipe. */
501 close(sync_pipe[PIPE_READ]);
503 /* Don't unlink the save file - leave it around, for debugging
505 g_free(capture_opts->save_file);
506 capture_opts->save_file = NULL;
511 g_assert_not_reached();
516 /* There's stuff to read from the sync pipe, meaning the child has sent
517 us a message, or the sync pipe has closed, meaning the child has
518 closed it (perhaps because it exited). */
520 sync_pipe_input_cb(gint source, gpointer user_data)
522 capture_options *capture_opts = (capture_options *)user_data;
523 gint fork_child = capture_opts->fork_child;
525 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
526 int nread, msglen, chars_to_copy;
531 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
532 /* The child has closed the sync pipe, meaning it's not going to be
533 capturing any more packets. Pick up its exit status, and
534 complain if it did anything other than exit with status 0. */
535 sync_pipe_wait_for_child(fork_child, FALSE);
537 /* Read what remains of the capture file, and finish the capture.
538 XXX - do something if this fails? */
539 switch (cf_finish_tail(capture_opts->cf, &err)) {
542 if(cf_packet_count(capture_opts->cf) == 0) {
543 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
544 "%sNo packets captured!%s\n\n"
545 "As no data was captured, closing the %scapture file!",
546 simple_dialog_primary_start(), simple_dialog_primary_end(),
547 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
548 cf_close(capture_opts->cf);
552 /* Just because we got an error, that doesn't mean we were unable
553 to read any of the file; we handle what we could get from the
557 case CF_READ_ABORTED:
558 /* Exit by leaving the main loop, so that any quit functions
559 we registered get called. */
564 /* We're not doing a capture any more, so we don't have a save
566 g_free(capture_opts->save_file);
567 capture_opts->save_file = NULL;
572 buffer[nread] = '\0';
575 /* look for (possibly multiple) indications */
577 case SP_PACKET_COUNT :
584 cf_set_drops_known(capture_opts->cf, TRUE);
585 cf_set_drops(capture_opts->cf, atoi(p));
596 /* Read the entire message.
597 XXX - if the child hasn't sent it all yet, this could cause us
598 to hang until they do. */
599 msg = g_malloc(msglen + 1);
601 while (msglen != 0) {
604 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
609 chars_to_copy = MIN(msglen, nread);
610 memcpy(r, q, chars_to_copy);
613 nread -= chars_to_copy;
614 msglen -= chars_to_copy;
617 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
627 /* Read from the capture file the number of records the child told us
629 XXX - do something if this fails? */
630 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
634 /* Just because we got an error, that doesn't mean we were unable
635 to read any of the file; we handle what we could get from the
638 XXX - abort on a read error? */
641 case CF_READ_ABORTED:
642 /* Kill the child capture process; the user wants to exit, and we
643 shouldn't just leave it running. */
644 capture_kill_child(capture_opts);
652 /* the child process is going down, wait until it's completely terminated */
654 sync_pipe_wait_for_child(int fork_child, gboolean always_report)
659 /* XXX - analyze the wait status and display more information
661 XXX - set "fork_child" to -1 if we find it exited? */
662 if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
663 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
664 "Child capture process stopped unexpectedly");
667 if (wait(&wstatus) != -1) {
668 if (WIFEXITED(wstatus)) {
669 /* The child exited; display its exit status, if it's not zero,
670 and even if it's zero if "always_report" is true. */
671 if (always_report || WEXITSTATUS(wstatus) != 0) {
672 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
673 "Child capture process exited: exit status %d",
674 WEXITSTATUS(wstatus));
676 } else if (WIFSTOPPED(wstatus)) {
677 /* It stopped, rather than exiting. "Should not happen." */
678 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
679 "Child capture process stopped: %s",
680 sync_pipe_signame(WSTOPSIG(wstatus)));
681 } else if (WIFSIGNALED(wstatus)) {
682 /* It died with a signal. */
683 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
684 "Child capture process died: %s%s",
685 sync_pipe_signame(WTERMSIG(wstatus)),
686 WCOREDUMP(wstatus) ? " - core dumped" : "");
688 /* What? It had to either have exited, or stopped, or died with
689 a signal; what happened here? */
690 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
691 "Child capture process died: wait status %#o", wstatus);
695 /* No more child process. */
703 sync_pipe_signame(int sig)
706 static char sigmsg_buf[6+1+3+1];
715 sigmsg = "Interrupted";
723 sigmsg = "Illegal instruction";
727 sigmsg = "Trace trap";
735 sigmsg = "Arithmetic exception";
743 sigmsg = "Bus error";
747 sigmsg = "Segmentation violation";
750 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
751 Linux is POSIX compliant. These are not POSIX-defined signals ---
752 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
754 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
755 were omitted from POSIX.1 because their behavior is
756 implementation dependent and could not be adequately catego-
757 rized. Conforming implementations may deliver these sig-
758 nals, but must document the circumstances under which they
759 are delivered and note any restrictions concerning their
762 So we only check for SIGSYS on those systems that happen to
763 implement them (a system can be POSIX-compliant and implement
764 them, it's just that POSIX doesn't *require* a POSIX-compliant
765 system to implement them).
770 sigmsg = "Bad system call";
775 sigmsg = "Broken pipe";
779 sigmsg = "Alarm clock";
783 sigmsg = "Terminated";
787 sprintf(sigmsg_buf, "Signal %d", sig);
797 sync_pipe_stop(capture_options *capture_opts)
799 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
801 kill(capture_opts->fork_child, SIGUSR1);
803 /* XXX: this is not the preferred method of closing a process!
804 * the clean way would be getting the process id of the child process,
805 * then getting window handle hWnd of that process (using EnumChildWindows),
806 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
808 * Unfortunately, I don't know how to get the process id from the
809 * handle. OpenProcess will get an handle (not a window handle)
810 * from the process ID; it will not get a window handle from the
811 * process ID. (How could it? A process can have more than one
814 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
815 * running in the same console; that's not necessarily the case for
816 * us, as we might not be running in a console.
817 * And this also will require to have the process id.
819 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
826 sync_pipe_kill(capture_options *capture_opts)
828 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
830 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
832 /* XXX: this is not the preferred method of closing a process!
833 * the clean way would be getting the process id of the child process,
834 * then getting window handle hWnd of that process (using EnumChildWindows),
835 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
837 * Unfortunately, I don't know how to get the process id from the
838 * handle. OpenProcess will get an handle (not a window handle)
839 * from the process ID; it will not get a window handle from the
840 * process ID. (How could it? A process can have more than one
843 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
844 * running in the same console; that's not necessarily the case for
845 * us, as we might not be running in a console.
846 * And this also will require to have the process id.
848 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
853 #endif /* HAVE_LIBPCAP */