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) {
224 char scount[24]; /* need a constant for len of numbers */
225 char sautostop_filesize[24]; /* need a constant for len of numbers */
226 char sautostop_duration[24]; /* need a constant for len of numbers */
227 char save_file_fd_str[24];
235 char sync_pipe_fd[24];
239 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
240 int sync_pipe[2]; /* pipes used to sync between instances */
242 capture_opts->fork_child = -1;
244 /* Allocate the string pointer array with enough space for the
245 terminating NULL pointer. */
247 argv = g_malloc(sizeof (char *));
250 /* Now add those arguments used on all platforms. */
251 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
253 argv = sync_pipe_add_arg(argv, &argc, "-i");
254 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
256 argv = sync_pipe_add_arg(argv, &argc, "-w");
257 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
259 argv = sync_pipe_add_arg(argv, &argc, "-W");
260 sprintf(save_file_fd_str,"%d",capture_opts->save_file_fd); /* in lieu of itoa */
261 argv = sync_pipe_add_arg(argv, &argc, save_file_fd_str);
263 if (capture_opts->has_autostop_packets) {
264 argv = sync_pipe_add_arg(argv, &argc, "-c");
265 sprintf(scount,"%d",capture_opts->autostop_packets);
266 argv = sync_pipe_add_arg(argv, &argc, scount);
269 if (capture_opts->has_snaplen) {
270 argv = sync_pipe_add_arg(argv, &argc, "-s");
271 sprintf(ssnap,"%d",capture_opts->snaplen);
272 argv = sync_pipe_add_arg(argv, &argc, ssnap);
275 if (capture_opts->linktype != -1) {
276 argv = sync_pipe_add_arg(argv, &argc, "-y");
277 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
278 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
280 /* XXX - just treat it as a number */
281 sprintf(ssnap,"%d",capture_opts->linktype);
283 argv = sync_pipe_add_arg(argv, &argc, ssnap);
286 if (capture_opts->has_autostop_filesize) {
287 argv = sync_pipe_add_arg(argv, &argc, "-a");
288 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
289 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
292 if (capture_opts->has_autostop_duration) {
293 argv = sync_pipe_add_arg(argv, &argc, "-a");
294 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
295 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
298 if (!capture_opts->show_info) {
299 argv = sync_pipe_add_arg(argv, &argc, "-H");
302 if (!capture_opts->promisc_mode)
303 argv = sync_pipe_add_arg(argv, &argc, "-p");
306 /* Create a pipe for the child process */
308 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
309 /* Couldn't create the pipe between parent and child. */
311 unlink(capture_opts->save_file);
312 g_free(capture_opts->save_file);
313 capture_opts->save_file = NULL;
314 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
319 /* Convert font name to a quote-encapsulated string and pass to child */
320 argv = sync_pipe_add_arg(argv, &argc, "-m");
321 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
322 argv = sync_pipe_add_arg(argv, &argc, fontstring);
324 /* Convert pipe write handle to a string and pass to child */
325 argv = sync_pipe_add_arg(argv, &argc, "-Z");
326 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
327 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
329 /* Convert filter string to a quote delimited string and pass to child */
331 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
332 argv = sync_pipe_add_arg(argv, &argc, "-f");
333 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
334 argv = sync_pipe_add_arg(argv, &argc, filterstring);
338 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
341 g_free(filterstring);
344 if (pipe(sync_pipe) < 0) {
345 /* Couldn't create the pipe between parent and child. */
347 unlink(capture_opts->save_file);
348 g_free(capture_opts->save_file);
349 capture_opts->save_file = NULL;
350 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
355 argv = sync_pipe_add_arg(argv, &argc, "-m");
356 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
358 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
359 argv = sync_pipe_add_arg(argv, &argc, "-f");
360 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
363 if ((capture_opts->fork_child = fork()) == 0) {
365 * Child process - run Ethereal with the right arguments to make
366 * it just pop up the live capture dialog box and capture with
367 * the specified capture parameters, writing to the specified file.
369 * args: -i interface specification
371 * -W file descriptor to write
372 * -c count to capture
375 * -f "filter expression"
378 dup(sync_pipe[PIPE_WRITE]);
379 close(sync_pipe[PIPE_READ]);
380 execvp(ethereal_path, argv);
381 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
382 ethereal_path, strerror(errno));
383 sync_pipe_errmsg_to_parent(errmsg);
385 /* Exit with "_exit()", so that we don't close the connection
386 to the X server (and cause stuff buffered up by our parent but
387 not yet sent to be sent, as that stuff should only be sent by
393 /* Parent process - read messages from the child process over the
395 g_free(argv); /* free up arg array */
397 /* Close the write side of the pipe, so that only the child has it
398 open, and thus it completely closes, and thus returns to us
399 an EOF indication, if the child closes it (either deliberately
400 or by exiting abnormally). */
401 close(sync_pipe[PIPE_WRITE]);
403 /* Close the save file FD, as we won't be using it - we'll be opening
404 it and reading the save file through Wiretap. */
405 close(capture_opts->save_file_fd);
407 if (capture_opts->fork_child == -1) {
408 /* We couldn't even create the child process. */
410 close(sync_pipe[PIPE_READ]);
411 unlink(capture_opts->save_file);
412 g_free(capture_opts->save_file);
413 capture_opts->save_file = NULL;
414 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
415 "Couldn't create child process: %s", strerror(error));
419 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
420 colon; if the count is 0, the child process created the
421 capture file and we should start reading from it, otherwise
422 the capture couldn't start and the count is a count of bytes
423 of error message, and we should display the message. */
426 i = read(sync_pipe[PIPE_READ], &c, 1);
428 /* EOF - the child process died.
429 Close the read side of the sync pipe, remove the capture file,
430 and report the failure. */
431 close(sync_pipe[PIPE_READ]);
432 unlink(capture_opts->save_file);
433 g_free(capture_opts->save_file);
434 capture_opts->save_file = NULL;
435 sync_pipe_wait_for_child(capture_opts, TRUE);
438 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
441 /* Child process handed us crap.
442 Close the read side of the sync pipe, remove the capture file,
443 and report the failure. */
444 close(sync_pipe[PIPE_READ]);
445 unlink(capture_opts->save_file);
446 g_free(capture_opts->save_file);
447 capture_opts->save_file = NULL;
448 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
449 "Capture child process sent us a bad message");
452 byte_count = byte_count*10 + c - '0';
454 if (c != SP_CAPSTART) {
455 /* Failure - the child process sent us a message indicating
456 what the problem was. */
457 if (byte_count == 0) {
458 /* Zero-length message? */
459 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
460 "Capture child process failed, but its error message was empty.");
462 msg = g_malloc(byte_count + 1);
464 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
465 "Capture child process failed, but its error message was too big.");
467 i = read(sync_pipe[PIPE_READ], msg, byte_count);
468 msg[byte_count] = '\0';
470 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
471 "Capture child process failed: Error %s reading its error message.",
474 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
475 "Capture child process failed: EOF reading its error message.");
476 sync_pipe_wait_for_child(capture_opts, FALSE);
478 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
482 /* Close the sync pipe. */
483 close(sync_pipe[PIPE_READ]);
485 /* Get rid of the save file - the capture never started. */
486 unlink(capture_opts->save_file);
487 g_free(capture_opts->save_file);
488 capture_opts->save_file = NULL;
493 /* The child process started a capture.
494 Attempt to open the capture file and set up to read it. */
495 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
497 /* We were able to open and set up to read the capture file;
498 arrange that our callback be called whenever it's possible
499 to read from the sync pipe, so that it's called when
500 the child process wants to tell us something. */
501 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
506 /* We weren't able to open the capture file; user has been
507 alerted. Close the sync pipe. */
509 close(sync_pipe[PIPE_READ]);
511 /* Don't unlink the save file - leave it around, for debugging
513 g_free(capture_opts->save_file);
514 capture_opts->save_file = NULL;
519 g_assert_not_reached();
524 /* There's stuff to read from the sync pipe, meaning the child has sent
525 us a message, or the sync pipe has closed, meaning the child has
526 closed it (perhaps because it exited). */
528 sync_pipe_input_cb(gint source, gpointer user_data)
530 capture_options *capture_opts = (capture_options *)user_data;
532 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
533 int nread, msglen, chars_to_copy;
538 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
539 /* The child has closed the sync pipe, meaning it's not going to be
540 capturing any more packets. Pick up its exit status, and
541 complain if it did anything other than exit with status 0. */
542 sync_pipe_wait_for_child(capture_opts, FALSE);
544 /* Read what remains of the capture file, and finish the capture.
545 XXX - do something if this fails? */
546 switch (cf_finish_tail(capture_opts->cf, &err)) {
549 if(cf_packet_count(capture_opts->cf) == 0) {
550 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
551 "%sNo packets captured!%s\n\n"
552 "As no data was captured, closing the %scapture file!",
553 simple_dialog_primary_start(), simple_dialog_primary_end(),
554 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
555 cf_close(capture_opts->cf);
559 /* Just because we got an error, that doesn't mean we were unable
560 to read any of the file; we handle what we could get from the
564 case CF_READ_ABORTED:
565 /* Exit by leaving the main loop, so that any quit functions
566 we registered get called. */
571 /* We're not doing a capture any more, so we don't have a save
573 g_free(capture_opts->save_file);
574 capture_opts->save_file = NULL;
579 buffer[nread] = '\0';
582 /* look for (possibly multiple) indications */
584 case SP_PACKET_COUNT :
591 cf_set_drops_known(capture_opts->cf, TRUE);
592 cf_set_drops(capture_opts->cf, atoi(p));
603 /* Read the entire message.
604 XXX - if the child hasn't sent it all yet, this could cause us
605 to hang until they do. */
606 msg = g_malloc(msglen + 1);
608 while (msglen != 0) {
611 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
616 chars_to_copy = MIN(msglen, nread);
617 memcpy(r, q, chars_to_copy);
620 nread -= chars_to_copy;
621 msglen -= chars_to_copy;
624 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
633 /* Read the entire message.
634 XXX - if the child hasn't sent it all yet, this could cause us
635 to hang until they do. */
636 msg = g_malloc(msglen + 1);
638 while (msglen != 0) {
641 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
646 chars_to_copy = MIN(msglen, nread);
647 memcpy(r, q, chars_to_copy);
650 nread -= chars_to_copy;
651 msglen -= chars_to_copy;
654 /*simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);*/
655 /* XXX - save the current filename?! */
656 if(capture_opts->sync_mode) {
668 /* Read from the capture file the number of records the child told us
670 XXX - do something if this fails? */
671 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
675 /* Just because we got an error, that doesn't mean we were unable
676 to read any of the file; we handle what we could get from the
679 XXX - abort on a read error? */
682 case CF_READ_ABORTED:
683 /* Kill the child capture process; the user wants to exit, and we
684 shouldn't just leave it running. */
685 capture_kill_child(capture_opts);
693 /* the child process is going down, wait until it's completely terminated */
695 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
700 g_assert(capture_opts->fork_child != -1);
703 /* XXX - analyze the wait status and display more information
705 XXX - set "fork_child" to -1 if we find it exited? */
706 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
707 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
708 "Child capture process stopped unexpectedly");
711 if (wait(&wstatus) != -1) {
712 if (WIFEXITED(wstatus)) {
713 /* The child exited; display its exit status, if it's not zero,
714 and even if it's zero if "always_report" is true. */
715 if (always_report || WEXITSTATUS(wstatus) != 0) {
716 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
717 "Child capture process exited: exit status %d",
718 WEXITSTATUS(wstatus));
720 } else if (WIFSTOPPED(wstatus)) {
721 /* It stopped, rather than exiting. "Should not happen." */
722 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
723 "Child capture process stopped: %s",
724 sync_pipe_signame(WSTOPSIG(wstatus)));
725 } else if (WIFSIGNALED(wstatus)) {
726 /* It died with a signal. */
727 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
728 "Child capture process died: %s%s",
729 sync_pipe_signame(WTERMSIG(wstatus)),
730 WCOREDUMP(wstatus) ? " - core dumped" : "");
732 /* What? It had to either have exited, or stopped, or died with
733 a signal; what happened here? */
734 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
735 "Child capture process died: wait status %#o", wstatus);
739 /* No more child process. */
740 capture_opts->fork_child = -1;
747 sync_pipe_signame(int sig)
750 static char sigmsg_buf[6+1+3+1];
759 sigmsg = "Interrupted";
767 sigmsg = "Illegal instruction";
771 sigmsg = "Trace trap";
779 sigmsg = "Arithmetic exception";
787 sigmsg = "Bus error";
791 sigmsg = "Segmentation violation";
794 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
795 Linux is POSIX compliant. These are not POSIX-defined signals ---
796 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
798 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
799 were omitted from POSIX.1 because their behavior is
800 implementation dependent and could not be adequately catego-
801 rized. Conforming implementations may deliver these sig-
802 nals, but must document the circumstances under which they
803 are delivered and note any restrictions concerning their
806 So we only check for SIGSYS on those systems that happen to
807 implement them (a system can be POSIX-compliant and implement
808 them, it's just that POSIX doesn't *require* a POSIX-compliant
809 system to implement them).
814 sigmsg = "Bad system call";
819 sigmsg = "Broken pipe";
823 sigmsg = "Alarm clock";
827 sigmsg = "Terminated";
831 sprintf(sigmsg_buf, "Signal %d", sig);
841 sync_pipe_stop(capture_options *capture_opts)
843 /* XXX - in which cases this will be 0? */
844 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
846 kill(capture_opts->fork_child, SIGUSR1);
848 /* XXX: this is not the preferred method of closing a process!
849 * the clean way would be getting the process id of the child process,
850 * then getting window handle hWnd of that process (using EnumChildWindows),
851 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
853 * Unfortunately, I don't know how to get the process id from the
854 * handle. OpenProcess will get an handle (not a window handle)
855 * from the process ID; it will not get a window handle from the
856 * process ID. (How could it? A process can have more than one
859 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
860 * running in the same console; that's not necessarily the case for
861 * us, as we might not be running in a console.
862 * And this also will require to have the process id.
864 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
871 sync_pipe_kill(capture_options *capture_opts)
873 /* XXX - in which cases this will be 0? */
874 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
876 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
878 /* XXX: this is not the preferred method of closing a process!
879 * the clean way would be getting the process id of the child process,
880 * then getting window handle hWnd of that process (using EnumChildWindows),
881 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
883 * Unfortunately, I don't know how to get the process id from the
884 * handle. OpenProcess will get an handle (not a window handle)
885 * from the process ID; it will not get a window handle from the
886 * process ID. (How could it? A process can have more than one
889 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
890 * running in the same console; that's not necessarily the case for
891 * us, as we might not be running in a console.
892 * And this also will require to have the process id.
894 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
899 #endif /* HAVE_LIBPCAP */