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(capture_options *capture_opts, 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 */
124 #define SP_FILE ':' /* followed by length of the name of the last opened file that follows */
129 sync_pipe_capstart_to_parent(void)
131 static const char capstart_msg = SP_CAPSTART;
133 write(1, &capstart_msg, 1);
137 sync_pipe_packet_count_to_parent(int packet_count)
139 char tmp[SP_DECISIZE+1+1];
140 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
141 write(1, tmp, strlen(tmp));
145 sync_pipe_filename_to_parent(const char *filename)
147 int msglen = strlen(filename);
148 char lenbuf[SP_DECISIZE+1+1];
150 sprintf(lenbuf, "%u%c", msglen, SP_FILE);
151 write(1, lenbuf, strlen(lenbuf));
152 write(1, filename, msglen);
156 sync_pipe_errmsg_to_parent(const char *errmsg)
158 int msglen = strlen(errmsg);
159 char lenbuf[SP_DECISIZE+1+1];
161 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
162 write(1, lenbuf, strlen(lenbuf));
163 write(1, errmsg, msglen);
167 sync_pipe_drops_to_parent(int drops)
169 char tmp[SP_DECISIZE+1+1];
170 sprintf(tmp, "%d%c", drops, SP_DROPS);
171 write(1, tmp, strlen(tmp));
175 /* Add a string pointer to a NULL-terminated array of string pointers. */
177 sync_pipe_add_arg(char **args, int *argc, char *arg)
179 /* Grow the array; "*argc" currently contains the number of string
180 pointers, *not* counting the NULL pointer at the end, so we have
181 to add 2 in order to get the new size of the array, including the
182 new pointer and the terminating NULL pointer. */
183 args = g_realloc(args, (*argc + 2) * sizeof (char *));
185 /* Stuff the pointer into the penultimate element of the array, which
186 is the one at the index specified by "*argc". */
189 /* Now bump the count. */
192 /* We overwrite the NULL pointer; put it back right after the
200 /* Given a string, return a pointer to a quote-encapsulated version of
201 the string, so we can pass it as an argument with "spawnvp" even
202 if it contains blanks. */
204 sync_pipe_quote_encapsulate(const char *string)
206 char *encapsulated_string;
208 encapsulated_string = g_new(char, strlen(string) + 3);
209 sprintf(encapsulated_string, "\"%s\"", string);
210 return encapsulated_string;
217 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
223 char scount[24]; /* need a constant for len of numbers */
224 char sfilesize[24]; /* need a constant for len of numbers */
225 char sfile_duration[24]; /* need a constant for len of numbers */
226 char sring_num_files[24]; /* need a constant for len of numbers */
227 char sautostop_files[24]; /* need a constant for len of numbers */
228 char sautostop_filesize[24]; /* need a constant for len of numbers */
229 char sautostop_duration[24]; /* need a constant for len of numbers */
236 char sync_pipe_fd[24];
240 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
241 int sync_pipe[2]; /* pipes used to sync between instances */
244 /*g_warning("sync_pipe_do_capture");
245 capture_opts_info(capture_opts);*/
247 capture_opts->fork_child = -1;
249 /* Allocate the string pointer array with enough space for the
250 terminating NULL pointer. */
252 argv = g_malloc(sizeof (char *));
255 /* Now add those arguments used on all platforms. */
256 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
258 argv = sync_pipe_add_arg(argv, &argc, "-i");
259 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
261 if(capture_opts->save_file) {
262 argv = sync_pipe_add_arg(argv, &argc, "-w");
263 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
266 if (capture_opts->has_snaplen) {
267 argv = sync_pipe_add_arg(argv, &argc, "-s");
268 sprintf(ssnap,"%d",capture_opts->snaplen);
269 argv = sync_pipe_add_arg(argv, &argc, ssnap);
272 if (capture_opts->linktype != -1) {
273 argv = sync_pipe_add_arg(argv, &argc, "-y");
274 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
275 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
277 /* XXX - just treat it as a number */
278 sprintf(ssnap,"%d",capture_opts->linktype);
280 argv = sync_pipe_add_arg(argv, &argc, ssnap);
283 if(capture_opts->multi_files_on) {
284 if (capture_opts->has_autostop_filesize) {
285 argv = sync_pipe_add_arg(argv, &argc, "-b");
286 sprintf(sfilesize,"filesize:%d",capture_opts->autostop_filesize);
287 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
290 if (capture_opts->has_file_duration) {
291 argv = sync_pipe_add_arg(argv, &argc, "-b");
292 sprintf(sfile_duration,"duration:%d",capture_opts->file_duration);
293 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
296 if (capture_opts->has_ring_num_files) {
297 argv = sync_pipe_add_arg(argv, &argc, "-b");
298 sprintf(sring_num_files,"files:%d",capture_opts->ring_num_files);
299 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
302 if (capture_opts->has_autostop_files) {
303 argv = sync_pipe_add_arg(argv, &argc, "-a");
304 sprintf(sautostop_files,"files:%d",capture_opts->autostop_files);
305 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
308 if (capture_opts->has_autostop_filesize) {
309 argv = sync_pipe_add_arg(argv, &argc, "-a");
310 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
311 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
315 if (capture_opts->has_autostop_packets) {
316 argv = sync_pipe_add_arg(argv, &argc, "-c");
317 sprintf(scount,"%d",capture_opts->autostop_packets);
318 argv = sync_pipe_add_arg(argv, &argc, scount);
321 if (capture_opts->has_autostop_duration) {
322 argv = sync_pipe_add_arg(argv, &argc, "-a");
323 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
324 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
327 if (!capture_opts->show_info) {
328 argv = sync_pipe_add_arg(argv, &argc, "-H");
331 if (!capture_opts->promisc_mode)
332 argv = sync_pipe_add_arg(argv, &argc, "-p");
335 /* Create a pipe for the child process */
336 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
337 /* Couldn't create the pipe between parent and child. */
338 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
343 /* Convert font name to a quote-encapsulated string and pass to child */
344 argv = sync_pipe_add_arg(argv, &argc, "-m");
345 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
346 argv = sync_pipe_add_arg(argv, &argc, fontstring);
348 /* Convert pipe write handle to a string and pass to child */
349 argv = sync_pipe_add_arg(argv, &argc, "-Z");
350 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
351 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
353 /* Convert filter string to a quote delimited string and pass to child */
355 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
356 argv = sync_pipe_add_arg(argv, &argc, "-f");
357 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
358 argv = sync_pipe_add_arg(argv, &argc, filterstring);
362 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
365 g_free(filterstring);
368 if (pipe(sync_pipe) < 0) {
369 /* Couldn't create the pipe between parent and child. */
370 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
375 argv = sync_pipe_add_arg(argv, &argc, "-m");
376 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
378 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
379 argv = sync_pipe_add_arg(argv, &argc, "-f");
380 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
383 if ((capture_opts->fork_child = fork()) == 0) {
385 * Child process - run Ethereal with the right arguments to make
386 * it just pop up the live capture dialog box and capture with
387 * the specified capture parameters, writing to the specified file.
389 * args: -i interface specification
391 * -W file descriptor to write
392 * -c count to capture
395 * -f "filter expression"
398 dup(sync_pipe[PIPE_WRITE]);
399 close(sync_pipe[PIPE_READ]);
400 execvp(ethereal_path, argv);
401 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
402 ethereal_path, strerror(errno));
403 sync_pipe_errmsg_to_parent(errmsg);
405 /* Exit with "_exit()", so that we don't close the connection
406 to the X server (and cause stuff buffered up by our parent but
407 not yet sent to be sent, as that stuff should only be sent by
413 /* Parent process - read messages from the child process over the
415 g_free(argv); /* free up arg array */
417 /* Close the write side of the pipe, so that only the child has it
418 open, and thus it completely closes, and thus returns to us
419 an EOF indication, if the child closes it (either deliberately
420 or by exiting abnormally). */
421 close(sync_pipe[PIPE_WRITE]);
423 if (capture_opts->fork_child == -1) {
424 /* We couldn't even create the child process. */
425 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
426 "Couldn't create child process: %s", strerror(errno));
427 close(sync_pipe[PIPE_READ]);
431 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
432 colon; if the count is 0, the child process created the
433 capture file and we should start reading from it, otherwise
434 the capture couldn't start and the count is a count of bytes
435 of error message, and we should display the message. */
438 i = read(sync_pipe[PIPE_READ], &c, 1);
440 /* EOF - the child process died.
441 Close the read side of the sync pipe, remove the capture file,
442 and report the failure. */
443 close(sync_pipe[PIPE_READ]);
444 sync_pipe_wait_for_child(capture_opts, TRUE);
448 /* the first message should be the capture start or an error message */
449 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
452 /* Child process handed us crap.
453 Close the read side of the sync pipe, remove the capture file,
454 and report the failure. */
455 close(sync_pipe[PIPE_READ]);
456 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
457 "Capture child process sent us a bad message");
460 byte_count = byte_count*10 + c - '0';
462 if (c != SP_CAPSTART) {
463 /* Failure - the child process sent us a message indicating
464 what the problem was. */
465 if (byte_count == 0) {
466 /* Zero-length message? */
467 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
468 "Capture child process failed, but its error message was empty.");
470 msg = g_malloc(byte_count + 1);
472 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
473 "Capture child process failed, but its error message was too big.");
475 i = read(sync_pipe[PIPE_READ], msg, byte_count);
476 msg[byte_count] = '\0';
478 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
479 "Capture child process failed: Error %s reading its error message.",
482 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
483 "Capture child process failed: EOF reading its error message.");
484 sync_pipe_wait_for_child(capture_opts, FALSE);
486 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
490 /* Close the sync pipe. */
491 close(sync_pipe[PIPE_READ]);
496 /* We were able to set up to read the capture file;
497 arrange that our callback be called whenever it's possible
498 to read from the sync pipe, so that it's called when
499 the child process wants to tell us something. */
501 /* we have a running capture, now wait for the real capture filename */
502 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts,
503 &capture_opts->fork_child, sync_pipe_input_cb);
509 /* There's stuff to read from the sync pipe, meaning the child has sent
510 us a message, or the sync pipe has closed, meaning the child has
511 closed it (perhaps because it exited). */
513 sync_pipe_input_cb(gint source, gpointer user_data)
515 capture_options *capture_opts = (capture_options *)user_data;
517 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
518 int nread, msglen, chars_to_copy;
522 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
523 /* The child has closed the sync pipe, meaning it's not going to be
524 capturing any more packets. Pick up its exit status, and
525 complain if it did anything other than exit with status 0. */
526 sync_pipe_wait_for_child(capture_opts, FALSE);
527 capture_input_closed(capture_opts);
531 buffer[nread] = '\0';
534 /* look for (possibly multiple) indications */
536 case SP_PACKET_COUNT :
543 cf_set_drops_known(capture_opts->cf, TRUE);
544 cf_set_drops(capture_opts->cf, atoi(p));
555 /* Read the entire message.
556 XXX - if the child hasn't sent it all yet, this could cause us
557 to hang until they do. */
558 msg = g_malloc(msglen + 1);
560 while (msglen != 0) {
563 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
568 chars_to_copy = MIN(msglen, nread);
569 memcpy(r, q, chars_to_copy);
572 nread -= chars_to_copy;
573 msglen -= chars_to_copy;
576 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
585 /* Read the entire file name.
586 XXX - if the child hasn't sent it all yet, this could cause us
587 to hang until they do. */
588 msg = g_malloc(msglen + 1);
590 while (msglen != 0) {
593 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
598 chars_to_copy = MIN(msglen, nread);
599 memcpy(r, q, chars_to_copy);
602 nread -= chars_to_copy;
603 msglen -= chars_to_copy;
607 if(!capture_input_new_file(capture_opts, msg)) {
608 /* We weren't able to open the new capture file; user has been
609 alerted. Close the sync pipe. */
610 /* close(sync_pipe[PIPE_READ]);*/
612 /* XXX - how to kill things here ? */
613 /* XXX - is it safe to close the pipe inside this callback? */
627 capture_input_new_packets(capture_opts, to_read);
633 /* the child process is going down, wait until it's completely terminated */
635 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
640 g_assert(capture_opts->fork_child != -1);
643 /* XXX - analyze the wait status and display more information
645 XXX - set "fork_child" to -1 if we find it exited? */
646 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
647 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
648 "Child capture process stopped unexpectedly");
651 if (wait(&wstatus) != -1) {
652 if (WIFEXITED(wstatus)) {
653 /* The child exited; display its exit status, if it's not zero,
654 and even if it's zero if "always_report" is true. */
655 if (always_report || WEXITSTATUS(wstatus) != 0) {
656 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
657 "Child capture process exited: exit status %d",
658 WEXITSTATUS(wstatus));
660 } else if (WIFSTOPPED(wstatus)) {
661 /* It stopped, rather than exiting. "Should not happen." */
662 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
663 "Child capture process stopped: %s",
664 sync_pipe_signame(WSTOPSIG(wstatus)));
665 } else if (WIFSIGNALED(wstatus)) {
666 /* It died with a signal. */
667 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
668 "Child capture process died: %s%s",
669 sync_pipe_signame(WTERMSIG(wstatus)),
670 WCOREDUMP(wstatus) ? " - core dumped" : "");
672 /* What? It had to either have exited, or stopped, or died with
673 a signal; what happened here? */
674 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
675 "Child capture process died: wait status %#o", wstatus);
679 /* No more child process. */
680 capture_opts->fork_child = -1;
687 sync_pipe_signame(int sig)
690 static char sigmsg_buf[6+1+3+1];
699 sigmsg = "Interrupted";
707 sigmsg = "Illegal instruction";
711 sigmsg = "Trace trap";
719 sigmsg = "Arithmetic exception";
727 sigmsg = "Bus error";
731 sigmsg = "Segmentation violation";
734 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
735 Linux is POSIX compliant. These are not POSIX-defined signals ---
736 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
738 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
739 were omitted from POSIX.1 because their behavior is
740 implementation dependent and could not be adequately catego-
741 rized. Conforming implementations may deliver these sig-
742 nals, but must document the circumstances under which they
743 are delivered and note any restrictions concerning their
746 So we only check for SIGSYS on those systems that happen to
747 implement them (a system can be POSIX-compliant and implement
748 them, it's just that POSIX doesn't *require* a POSIX-compliant
749 system to implement them).
754 sigmsg = "Bad system call";
759 sigmsg = "Broken pipe";
763 sigmsg = "Alarm clock";
767 sigmsg = "Terminated";
771 sprintf(sigmsg_buf, "Signal %d", sig);
781 sync_pipe_stop(capture_options *capture_opts)
783 /* XXX - in which cases this will be 0? */
784 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
786 kill(capture_opts->fork_child, SIGUSR1);
788 /* XXX: this is not the preferred method of closing a process!
789 * the clean way would be getting the process id of the child process,
790 * then getting window handle hWnd of that process (using EnumChildWindows),
791 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
793 * Unfortunately, I don't know how to get the process id from the
794 * handle. OpenProcess will get an handle (not a window handle)
795 * from the process ID; it will not get a window handle from the
796 * process ID. (How could it? A process can have more than one
799 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
800 * running in the same console; that's not necessarily the case for
801 * us, as we might not be running in a console.
802 * And this also will require to have the process id.
804 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
811 sync_pipe_kill(capture_options *capture_opts)
813 /* XXX - in which cases this will be 0? */
814 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
816 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
818 /* XXX: this is not the preferred method of closing a process!
819 * the clean way would be getting the process id of the child process,
820 * then getting window handle hWnd of that process (using EnumChildWindows),
821 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
823 * Unfortunately, I don't know how to get the process id from the
824 * handle. OpenProcess will get an handle (not a window handle)
825 * from the process ID; it will not get a window handle from the
826 * process ID. (How could it? A process can have more than one
829 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
830 * running in the same console; that's not necessarily the case for
831 * us, as we might not be running in a console.
832 * And this also will require to have the process id.
834 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
839 #endif /* HAVE_LIBPCAP */