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>
86 #include "capture_sync.h"
87 #include "simple_dialog.h"
90 #include "capture-wpcap.h"
98 int fork_child = -1; /* If not -1, in parent, process ID of child */
101 #include <process.h> /* For spawning child process */
104 /* Win32 needs the O_BINARY flag for open() */
111 static char *sync_pipe_signame(int);
115 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
116 static void sync_pipe_wait_for_child(gboolean always_report);
118 /* Size of buffer to hold decimal representation of
119 signed/unsigned 64-bit int */
120 #define SP_DECISIZE 20
123 * Indications sent out on the sync pipe.
125 #define SP_CAPSTART ';' /* capture start message */
126 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
127 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
128 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
133 sync_pipe_capstart_to_parent(void)
135 static const char capstart_msg = SP_CAPSTART;
137 write(1, &capstart_msg, 1);
141 sync_pipe_packet_count_to_parent(int packet_count)
143 char tmp[SP_DECISIZE+1+1];
144 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
145 write(1, tmp, strlen(tmp));
149 sync_pipe_errmsg_to_parent(const char *errmsg)
151 int msglen = strlen(errmsg);
152 char lenbuf[SP_DECISIZE+1+1];
154 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
155 write(1, lenbuf, strlen(lenbuf));
156 write(1, errmsg, msglen);
160 sync_pipe_drops_to_parent(int drops)
162 char tmp[SP_DECISIZE+1+1];
163 sprintf(tmp, "%d%c", drops, SP_DROPS);
164 write(1, tmp, strlen(tmp));
168 /* Add a string pointer to a NULL-terminated array of string pointers. */
170 sync_pipe_add_arg(char **args, int *argc, char *arg)
172 /* Grow the array; "*argc" currently contains the number of string
173 pointers, *not* counting the NULL pointer at the end, so we have
174 to add 2 in order to get the new size of the array, including the
175 new pointer and the terminating NULL pointer. */
176 args = g_realloc(args, (*argc + 2) * sizeof (char *));
178 /* Stuff the pointer into the penultimate element of the array, which
179 is the one at the index specified by "*argc". */
182 /* Now bump the count. */
185 /* We overwrite the NULL pointer; put it back right after the
193 /* Given a string, return a pointer to a quote-encapsulated version of
194 the string, so we can pass it as an argument with "spawnvp" even
195 if it contains blanks. */
197 sync_pipe_quote_encapsulate(const char *string)
199 char *encapsulated_string;
201 encapsulated_string = g_new(char, strlen(string) + 3);
202 sprintf(encapsulated_string, "\"%s\"", string);
203 return encapsulated_string;
210 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
217 char scount[24]; /* need a constant for len of numbers */
218 char sautostop_filesize[24]; /* need a constant for len of numbers */
219 char sautostop_duration[24]; /* need a constant for len of numbers */
220 char save_file_fd[24];
228 char sync_pipe_fd[24];
232 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
233 int sync_pipe[2]; /* pipes used to sync between instances */
238 /* Allocate the string pointer array with enough space for the
239 terminating NULL pointer. */
241 argv = g_malloc(sizeof (char *));
244 /* Now add those arguments used on all platforms. */
245 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
247 argv = sync_pipe_add_arg(argv, &argc, "-i");
248 argv = sync_pipe_add_arg(argv, &argc, cfile.iface);
250 argv = sync_pipe_add_arg(argv, &argc, "-w");
251 argv = sync_pipe_add_arg(argv, &argc, cfile.save_file);
253 argv = sync_pipe_add_arg(argv, &argc, "-W");
254 sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */
255 argv = sync_pipe_add_arg(argv, &argc, save_file_fd);
257 if (capture_opts->has_autostop_packets) {
258 argv = sync_pipe_add_arg(argv, &argc, "-c");
259 sprintf(scount,"%d",capture_opts->autostop_packets);
260 argv = sync_pipe_add_arg(argv, &argc, scount);
263 if (capture_opts->has_snaplen) {
264 argv = sync_pipe_add_arg(argv, &argc, "-s");
265 sprintf(ssnap,"%d",capture_opts->snaplen);
266 argv = sync_pipe_add_arg(argv, &argc, ssnap);
269 if (capture_opts->linktype != -1) {
270 argv = sync_pipe_add_arg(argv, &argc, "-y");
271 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
272 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
274 /* XXX - just treat it as a number */
275 sprintf(ssnap,"%d",capture_opts.linktype);
277 argv = sync_pipe_add_arg(argv, &argc, ssnap);
280 if (capture_opts->has_autostop_filesize) {
281 argv = sync_pipe_add_arg(argv, &argc, "-a");
282 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
283 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
286 if (capture_opts->has_autostop_duration) {
287 argv = sync_pipe_add_arg(argv, &argc, "-a");
288 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
289 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
292 if (!capture_opts->show_info) {
293 argv = sync_pipe_add_arg(argv, &argc, "-H");
296 if (!capture_opts->promisc_mode)
297 argv = sync_pipe_add_arg(argv, &argc, "-p");
300 /* Create a pipe for the child process */
302 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
303 /* Couldn't create the pipe between parent and child. */
305 unlink(cfile.save_file);
306 g_free(cfile.save_file);
307 cfile.save_file = NULL;
308 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
313 /* Convert font name to a quote-encapsulated string and pass to child */
314 argv = sync_pipe_add_arg(argv, &argc, "-m");
315 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
316 argv = sync_pipe_add_arg(argv, &argc, fontstring);
318 /* Convert pipe write handle to a string and pass to child */
319 argv = sync_pipe_add_arg(argv, &argc, "-Z");
320 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
321 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
323 /* Convert filter string to a quote delimited string and pass to child */
325 if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
326 argv = sync_pipe_add_arg(argv, &argc, "-f");
327 filterstring = sync_pipe_quote_encapsulate(cfile.cfilter);
328 argv = sync_pipe_add_arg(argv, &argc, filterstring);
332 fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
335 g_free(filterstring);
338 if (pipe(sync_pipe) < 0) {
339 /* Couldn't create the pipe between parent and child. */
341 unlink(cfile.save_file);
342 g_free(cfile.save_file);
343 cfile.save_file = NULL;
344 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
349 argv = sync_pipe_add_arg(argv, &argc, "-m");
350 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
352 if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
353 argv = sync_pipe_add_arg(argv, &argc, "-f");
354 argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter);
357 if ((fork_child = fork()) == 0) {
359 * Child process - run Ethereal with the right arguments to make
360 * it just pop up the live capture dialog box and capture with
361 * the specified capture parameters, writing to the specified file.
363 * args: -i interface specification
365 * -W file descriptor to write
366 * -c count to capture
369 * -f "filter expression"
372 dup(sync_pipe[PIPE_WRITE]);
373 close(sync_pipe[PIPE_READ]);
374 execvp(ethereal_path, argv);
375 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
376 ethereal_path, strerror(errno));
377 sync_pipe_errmsg_to_parent(errmsg);
379 /* Exit with "_exit()", so that we don't close the connection
380 to the X server (and cause stuff buffered up by our parent but
381 not yet sent to be sent, as that stuff should only be sent by
387 /* Parent process - read messages from the child process over the
389 g_free(argv); /* free up arg array */
391 /* Close the write side of the pipe, so that only the child has it
392 open, and thus it completely closes, and thus returns to us
393 an EOF indication, if the child closes it (either deliberately
394 or by exiting abnormally). */
395 close(sync_pipe[PIPE_WRITE]);
397 /* Close the save file FD, as we won't be using it - we'll be opening
398 it and reading the save file through Wiretap. */
399 close(cfile.save_file_fd);
401 if (fork_child == -1) {
402 /* We couldn't even create the child process. */
404 close(sync_pipe[PIPE_READ]);
405 unlink(cfile.save_file);
406 g_free(cfile.save_file);
407 cfile.save_file = NULL;
408 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
409 "Couldn't create child process: %s", strerror(error));
413 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
414 colon; if the count is 0, the child process created the
415 capture file and we should start reading from it, otherwise
416 the capture couldn't start and the count is a count of bytes
417 of error message, and we should display the message. */
420 i = read(sync_pipe[PIPE_READ], &c, 1);
422 /* EOF - the child process died.
423 Close the read side of the sync pipe, remove the capture file,
424 and report the failure. */
425 close(sync_pipe[PIPE_READ]);
426 unlink(cfile.save_file);
427 g_free(cfile.save_file);
428 cfile.save_file = NULL;
429 sync_pipe_wait_for_child(TRUE);
432 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
435 /* Child process handed us crap.
436 Close the read side of the sync pipe, remove the capture file,
437 and report the failure. */
438 close(sync_pipe[PIPE_READ]);
439 unlink(cfile.save_file);
440 g_free(cfile.save_file);
441 cfile.save_file = NULL;
442 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
443 "Capture child process sent us a bad message");
446 byte_count = byte_count*10 + c - '0';
448 if (c != SP_CAPSTART) {
449 /* Failure - the child process sent us a message indicating
450 what the problem was. */
451 if (byte_count == 0) {
452 /* Zero-length message? */
453 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
454 "Capture child process failed, but its error message was empty.");
456 msg = g_malloc(byte_count + 1);
458 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
459 "Capture child process failed, but its error message was too big.");
461 i = read(sync_pipe[PIPE_READ], msg, byte_count);
462 msg[byte_count] = '\0';
464 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
465 "Capture child process failed: Error %s reading its error message.",
468 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
469 "Capture child process failed: EOF reading its error message.");
470 sync_pipe_wait_for_child(FALSE);
472 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
476 /* Close the sync pipe. */
477 close(sync_pipe[PIPE_READ]);
479 /* Get rid of the save file - the capture never started. */
480 unlink(cfile.save_file);
481 g_free(cfile.save_file);
482 cfile.save_file = NULL;
487 /* The child process started a capture.
488 Attempt to open the capture file and set up to read it. */
489 err = cf_start_tail(cfile.save_file, is_tempfile, &cfile);
491 /* We weren't able to open the capture file; user has been
492 alerted. Close the sync pipe. */
494 close(sync_pipe[PIPE_READ]);
496 /* Don't unlink the save file - leave it around, for debugging
498 g_free(cfile.save_file);
499 cfile.save_file = NULL;
502 /* We were able to open and set up to read the capture file;
503 arrange that our callback be called whenever it's possible
504 to read from the sync pipe, so that it's called when
505 the child process wants to tell us something. */
506 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb);
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_file *cf = (capture_file *)user_data;
520 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
521 int nread, msglen, chars_to_copy;
526 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
527 /* The child has closed the sync pipe, meaning it's not going to be
528 capturing any more packets. Pick up its exit status, and
529 complain if it did anything other than exit with status 0. */
530 sync_pipe_wait_for_child(FALSE);
532 /* Read what remains of the capture file, and finish the capture.
533 XXX - do something if this fails? */
534 switch (cf_finish_tail(cf, &err)) {
538 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
539 "%sNo packets captured!%s\n\n"
540 "As no data was captured, closing the %scapture file!",
541 simple_dialog_primary_start(), simple_dialog_primary_end(),
542 (cf->is_tempfile) ? "temporary " : "");
547 /* Just because we got an error, that doesn't mean we were unable
548 to read any of the file; we handle what we could get from the
553 /* Exit by leaving the main loop, so that any quit functions
554 we registered get called. */
559 /* We're not doing a capture any more, so we don't have a save
561 g_free(cf->save_file);
562 cf->save_file = NULL;
567 buffer[nread] = '\0';
570 /* look for (possibly multiple) indications */
572 case SP_PACKET_COUNT :
579 cf->drops_known = TRUE;
591 /* Read the entire message.
592 XXX - if the child hasn't sent it all yet, this could cause us
593 to hang until they do. */
594 msg = g_malloc(msglen + 1);
596 while (msglen != 0) {
599 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
604 chars_to_copy = MIN(msglen, nread);
605 memcpy(r, q, chars_to_copy);
608 nread -= chars_to_copy;
609 msglen -= chars_to_copy;
612 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
622 /* Read from the capture file the number of records the child told us
624 XXX - do something if this fails? */
625 switch (cf_continue_tail(cf, to_read, &err)) {
629 /* Just because we got an error, that doesn't mean we were unable
630 to read any of the file; we handle what we could get from the
633 XXX - abort on a read error? */
637 /* Kill the child capture process; the user wants to exit, and we
638 shouldn't just leave it running. */
639 kill_capture_child(TRUE /* sync_mode */);
647 /* the child process is going down, wait until it's completely terminated */
649 sync_pipe_wait_for_child(gboolean always_report)
654 /* XXX - analyze the wait status and display more information
656 XXX - set "fork_child" to -1 if we find it exited? */
657 if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
658 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
659 "Child capture process stopped unexpectedly");
662 if (wait(&wstatus) != -1) {
663 if (WIFEXITED(wstatus)) {
664 /* The child exited; display its exit status, if it's not zero,
665 and even if it's zero if "always_report" is true. */
666 if (always_report || WEXITSTATUS(wstatus) != 0) {
667 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
668 "Child capture process exited: exit status %d",
669 WEXITSTATUS(wstatus));
671 } else if (WIFSTOPPED(wstatus)) {
672 /* It stopped, rather than exiting. "Should not happen." */
673 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
674 "Child capture process stopped: %s",
675 sync_pipe_signame(WSTOPSIG(wstatus)));
676 } else if (WIFSIGNALED(wstatus)) {
677 /* It died with a signal. */
678 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
679 "Child capture process died: %s%s",
680 sync_pipe_signame(WTERMSIG(wstatus)),
681 WCOREDUMP(wstatus) ? " - core dumped" : "");
683 /* What? It had to either have exited, or stopped, or died with
684 a signal; what happened here? */
685 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
686 "Child capture process died: wait status %#o", wstatus);
690 /* No more child process. */
698 sync_pipe_signame(int sig)
701 static char sigmsg_buf[6+1+3+1];
710 sigmsg = "Interrupted";
718 sigmsg = "Illegal instruction";
722 sigmsg = "Trace trap";
730 sigmsg = "Arithmetic exception";
738 sigmsg = "Bus error";
742 sigmsg = "Segmentation violation";
745 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
746 Linux is POSIX compliant. These are not POSIX-defined signals ---
747 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
749 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
750 were omitted from POSIX.1 because their behavior is
751 implementation dependent and could not be adequately catego-
752 rized. Conforming implementations may deliver these sig-
753 nals, but must document the circumstances under which they
754 are delivered and note any restrictions concerning their
757 So we only check for SIGSYS on those systems that happen to
758 implement them (a system can be POSIX-compliant and implement
759 them, it's just that POSIX doesn't *require* a POSIX-compliant
760 system to implement them).
765 sigmsg = "Bad system call";
770 sigmsg = "Broken pipe";
774 sigmsg = "Alarm clock";
778 sigmsg = "Terminated";
782 sprintf(sigmsg_buf, "Signal %d", sig);
794 if (fork_child != -1) {
796 kill(fork_child, SIGUSR1);
798 /* XXX: this is not the preferred method of closing a process!
799 * the clean way would be getting the process id of the child process,
800 * then getting window handle hWnd of that process (using EnumChildWindows),
801 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
803 * Unfortunately, I don't know how to get the process id from the handle */
804 /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
806 * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
807 * running in the same console, I don't know if that is true for our case.
808 * And this also will require to have the process id
810 TerminateProcess((HANDLE) fork_child, 0);
819 if (fork_child != -1)
821 kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
823 /* XXX: this is not the preferred method of closing a process!
824 * the clean way would be getting the process id of the child process,
825 * then getting window handle hWnd of that process (using EnumChildWindows),
826 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
828 * Unfortunately, I don't know how to get the process id from the handle */
829 /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
831 * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
832 * running in the same console, I don't know if that is true for our case.
833 * And this also will require to have the process id
835 TerminateProcess((HANDLE) fork_child, 0);
840 #endif /* HAVE_LIBPCAP */