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 */
132 /* Add a string pointer to a NULL-terminated array of string pointers. */
134 sync_pipe_add_arg(char **args, int *argc, char *arg)
136 /* Grow the array; "*argc" currently contains the number of string
137 pointers, *not* counting the NULL pointer at the end, so we have
138 to add 2 in order to get the new size of the array, including the
139 new pointer and the terminating NULL pointer. */
140 args = g_realloc(args, (*argc + 2) * sizeof (char *));
142 /* Stuff the pointer into the penultimate element of the array, which
143 is the one at the index specified by "*argc". */
146 /* Now bump the count. */
149 /* We overwrite the NULL pointer; put it back right after the
157 /* Given a string, return a pointer to a quote-encapsulated version of
158 the string, so we can pass it as an argument with "spawnvp" even
159 if it contains blanks. */
161 sync_pipe_quote_encapsulate(const char *string)
163 char *encapsulated_string;
165 encapsulated_string = g_new(char, strlen(string) + 3);
166 sprintf(encapsulated_string, "\"%s\"", string);
167 return encapsulated_string;
174 sync_pipe_do_capture(gboolean is_tempfile) {
181 char scount[24]; /* need a constant for len of numbers */
182 char sautostop_filesize[24]; /* need a constant for len of numbers */
183 char sautostop_duration[24]; /* need a constant for len of numbers */
184 char save_file_fd[24];
192 char sync_pipe_fd[24];
196 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
197 int sync_pipe[2]; /* pipes used to sync between instances */
202 /* Allocate the string pointer array with enough space for the
203 terminating NULL pointer. */
205 argv = g_malloc(sizeof (char *));
208 /* Now add those arguments used on all platforms. */
209 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
211 argv = sync_pipe_add_arg(argv, &argc, "-i");
212 argv = sync_pipe_add_arg(argv, &argc, cfile.iface);
214 argv = sync_pipe_add_arg(argv, &argc, "-w");
215 argv = sync_pipe_add_arg(argv, &argc, cfile.save_file);
217 argv = sync_pipe_add_arg(argv, &argc, "-W");
218 sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */
219 argv = sync_pipe_add_arg(argv, &argc, save_file_fd);
221 if (capture_opts.has_autostop_packets) {
222 argv = sync_pipe_add_arg(argv, &argc, "-c");
223 sprintf(scount,"%d",capture_opts.autostop_packets);
224 argv = sync_pipe_add_arg(argv, &argc, scount);
227 if (capture_opts.has_snaplen) {
228 argv = sync_pipe_add_arg(argv, &argc, "-s");
229 sprintf(ssnap,"%d",capture_opts.snaplen);
230 argv = sync_pipe_add_arg(argv, &argc, ssnap);
233 if (capture_opts.linktype != -1) {
234 argv = sync_pipe_add_arg(argv, &argc, "-y");
235 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
236 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts.linktype));
238 /* XXX - just treat it as a number */
239 sprintf(ssnap,"%d",capture_opts.linktype);
241 argv = sync_pipe_add_arg(argv, &argc, ssnap);
244 if (capture_opts.has_autostop_filesize) {
245 argv = sync_pipe_add_arg(argv, &argc, "-a");
246 sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize);
247 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
250 if (capture_opts.has_autostop_duration) {
251 argv = sync_pipe_add_arg(argv, &argc, "-a");
252 sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration);
253 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
256 if (!capture_opts.show_info) {
257 argv = sync_pipe_add_arg(argv, &argc, "-H");
260 if (!capture_opts.promisc_mode)
261 argv = sync_pipe_add_arg(argv, &argc, "-p");
264 /* Create a pipe for the child process */
266 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
267 /* Couldn't create the pipe between parent and child. */
269 unlink(cfile.save_file);
270 g_free(cfile.save_file);
271 cfile.save_file = NULL;
272 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
277 /* Convert font name to a quote-encapsulated string and pass to child */
278 argv = sync_pipe_add_arg(argv, &argc, "-m");
279 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
280 argv = sync_pipe_add_arg(argv, &argc, fontstring);
282 /* Convert pipe write handle to a string and pass to child */
283 argv = sync_pipe_add_arg(argv, &argc, "-Z");
284 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
285 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
287 /* Convert filter string to a quote delimited string and pass to child */
289 if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
290 argv = sync_pipe_add_arg(argv, &argc, "-f");
291 filterstring = sync_pipe_quote_encapsulate(cfile.cfilter);
292 argv = sync_pipe_add_arg(argv, &argc, filterstring);
296 fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
299 g_free(filterstring);
302 if (pipe(sync_pipe) < 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 argv = sync_pipe_add_arg(argv, &argc, "-m");
314 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
316 if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
317 argv = sync_pipe_add_arg(argv, &argc, "-f");
318 argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter);
321 if ((fork_child = fork()) == 0) {
323 * Child process - run Ethereal with the right arguments to make
324 * it just pop up the live capture dialog box and capture with
325 * the specified capture parameters, writing to the specified file.
327 * args: -i interface specification
329 * -W file descriptor to write
330 * -c count to capture
333 * -f "filter expression"
336 dup(sync_pipe[PIPE_WRITE]);
337 close(sync_pipe[PIPE_READ]);
338 execvp(ethereal_path, argv);
339 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
340 ethereal_path, strerror(errno));
341 sync_pipe_errmsg_to_parent(errmsg);
343 /* Exit with "_exit()", so that we don't close the connection
344 to the X server (and cause stuff buffered up by our parent but
345 not yet sent to be sent, as that stuff should only be sent by
351 /* Parent process - read messages from the child process over the
353 g_free(argv); /* free up arg array */
355 /* Close the write side of the pipe, so that only the child has it
356 open, and thus it completely closes, and thus returns to us
357 an EOF indication, if the child closes it (either deliberately
358 or by exiting abnormally). */
359 close(sync_pipe[PIPE_WRITE]);
361 /* Close the save file FD, as we won't be using it - we'll be opening
362 it and reading the save file through Wiretap. */
363 close(cfile.save_file_fd);
365 if (fork_child == -1) {
366 /* We couldn't even create the child process. */
368 close(sync_pipe[PIPE_READ]);
369 unlink(cfile.save_file);
370 g_free(cfile.save_file);
371 cfile.save_file = NULL;
372 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
373 "Couldn't create child process: %s", strerror(error));
377 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
378 colon; if the count is 0, the child process created the
379 capture file and we should start reading from it, otherwise
380 the capture couldn't start and the count is a count of bytes
381 of error message, and we should display the message. */
384 i = read(sync_pipe[PIPE_READ], &c, 1);
386 /* EOF - the child process died.
387 Close the read side of the sync pipe, remove the capture file,
388 and report the failure. */
389 close(sync_pipe[PIPE_READ]);
390 unlink(cfile.save_file);
391 g_free(cfile.save_file);
392 cfile.save_file = NULL;
393 sync_pipe_wait_for_child(TRUE);
396 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
399 /* Child process handed us crap.
400 Close the read side of the sync pipe, remove the capture file,
401 and report the failure. */
402 close(sync_pipe[PIPE_READ]);
403 unlink(cfile.save_file);
404 g_free(cfile.save_file);
405 cfile.save_file = NULL;
406 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
407 "Capture child process sent us a bad message");
410 byte_count = byte_count*10 + c - '0';
412 if (c != SP_CAPSTART) {
413 /* Failure - the child process sent us a message indicating
414 what the problem was. */
415 if (byte_count == 0) {
416 /* Zero-length message? */
417 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
418 "Capture child process failed, but its error message was empty.");
420 msg = g_malloc(byte_count + 1);
422 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
423 "Capture child process failed, but its error message was too big.");
425 i = read(sync_pipe[PIPE_READ], msg, byte_count);
426 msg[byte_count] = '\0';
428 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
429 "Capture child process failed: Error %s reading its error message.",
432 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
433 "Capture child process failed: EOF reading its error message.");
434 sync_pipe_wait_for_child(FALSE);
436 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
440 /* Close the sync pipe. */
441 close(sync_pipe[PIPE_READ]);
443 /* Get rid of the save file - the capture never started. */
444 unlink(cfile.save_file);
445 g_free(cfile.save_file);
446 cfile.save_file = NULL;
451 /* The child process started a capture.
452 Attempt to open the capture file and set up to read it. */
453 err = cf_start_tail(cfile.save_file, is_tempfile, &cfile);
455 /* We weren't able to open the capture file; user has been
456 alerted. Close the sync pipe. */
458 close(sync_pipe[PIPE_READ]);
460 /* Don't unlink the save file - leave it around, for debugging
462 g_free(cfile.save_file);
463 cfile.save_file = NULL;
466 /* We were able to open and set up to read the capture file;
467 arrange that our callback be called whenever it's possible
468 to read from the sync pipe, so that it's called when
469 the child process wants to tell us something. */
470 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb);
476 /* There's stuff to read from the sync pipe, meaning the child has sent
477 us a message, or the sync pipe has closed, meaning the child has
478 closed it (perhaps because it exited). */
480 sync_pipe_input_cb(gint source, gpointer user_data)
482 capture_file *cf = (capture_file *)user_data;
484 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
485 int nread, msglen, chars_to_copy;
490 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
491 /* The child has closed the sync pipe, meaning it's not going to be
492 capturing any more packets. Pick up its exit status, and
493 complain if it did anything other than exit with status 0. */
494 sync_pipe_wait_for_child(FALSE);
496 /* Read what remains of the capture file, and finish the capture.
497 XXX - do something if this fails? */
498 switch (cf_finish_tail(cf, &err)) {
502 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
503 "%sNo packets captured!%s\n\n"
504 "As no data was captured, closing the %scapture file!",
505 simple_dialog_primary_start(), simple_dialog_primary_end(),
506 (cf->is_tempfile) ? "temporary " : "");
511 /* Just because we got an error, that doesn't mean we were unable
512 to read any of the file; we handle what we could get from the
517 /* Exit by leaving the main loop, so that any quit functions
518 we registered get called. */
523 /* We're not doing a capture any more, so we don't have a save
525 g_free(cf->save_file);
526 cf->save_file = NULL;
531 buffer[nread] = '\0';
534 /* look for (possibly multiple) indications */
536 case SP_PACKET_COUNT :
543 cf->drops_known = TRUE;
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);
586 /* Read from the capture file the number of records the child told us
588 XXX - do something if this fails? */
589 switch (cf_continue_tail(cf, to_read, &err)) {
593 /* Just because we got an error, that doesn't mean we were unable
594 to read any of the file; we handle what we could get from the
597 XXX - abort on a read error? */
601 /* Kill the child capture process; the user wants to exit, and we
602 shouldn't just leave it running. */
603 kill_capture_child();
611 sync_pipe_wait_for_child(gboolean always_report)
616 /* XXX - analyze the wait status and display more information
618 XXX - set "fork_child" to -1 if we find it exited? */
619 if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
620 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
621 "Child capture process stopped unexpectedly");
624 if (wait(&wstatus) != -1) {
625 if (WIFEXITED(wstatus)) {
626 /* The child exited; display its exit status, if it's not zero,
627 and even if it's zero if "always_report" is true. */
628 if (always_report || WEXITSTATUS(wstatus) != 0) {
629 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
630 "Child capture process exited: exit status %d",
631 WEXITSTATUS(wstatus));
633 } else if (WIFSTOPPED(wstatus)) {
634 /* It stopped, rather than exiting. "Should not happen." */
635 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
636 "Child capture process stopped: %s",
637 sync_pipe_signame(WSTOPSIG(wstatus)));
638 } else if (WIFSIGNALED(wstatus)) {
639 /* It died with a signal. */
640 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
641 "Child capture process died: %s%s",
642 sync_pipe_signame(WTERMSIG(wstatus)),
643 WCOREDUMP(wstatus) ? " - core dumped" : "");
645 /* What? It had to either have exited, or stopped, or died with
646 a signal; what happened here? */
647 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
648 "Child capture process died: wait status %#o", wstatus);
652 /* No more child process. */
658 sync_pipe_errmsg_to_parent(const char *errmsg)
660 int msglen = strlen(errmsg);
661 char lenbuf[SP_DECISIZE+1+1];
663 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
664 write(1, lenbuf, strlen(lenbuf));
665 write(1, errmsg, msglen);
669 sync_pipe_drops_to_parent(int drops)
671 char tmp[SP_DECISIZE+1+1];
672 sprintf(tmp, "%d%c", drops, SP_DROPS);
673 write(1, tmp, strlen(tmp));
677 sync_pipe_packet_count_to_parent(int packet_count)
679 char tmp[SP_DECISIZE+1+1];
680 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
681 write(1, tmp, strlen(tmp));
685 sync_pipe_capstart_to_parent(void)
687 static const char capstart_msg = SP_CAPSTART;
689 write(1, &capstart_msg, 1);
694 sync_pipe_signame(int sig)
697 static char sigmsg_buf[6+1+3+1];
706 sigmsg = "Interrupted";
714 sigmsg = "Illegal instruction";
718 sigmsg = "Trace trap";
726 sigmsg = "Arithmetic exception";
734 sigmsg = "Bus error";
738 sigmsg = "Segmentation violation";
741 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
742 Linux is POSIX compliant. These are not POSIX-defined signals ---
743 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
745 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
746 were omitted from POSIX.1 because their behavior is
747 implementation dependent and could not be adequately catego-
748 rized. Conforming implementations may deliver these sig-
749 nals, but must document the circumstances under which they
750 are delivered and note any restrictions concerning their
753 So we only check for SIGSYS on those systems that happen to
754 implement them (a system can be POSIX-compliant and implement
755 them, it's just that POSIX doesn't *require* a POSIX-compliant
756 system to implement them).
761 sigmsg = "Bad system call";
766 sigmsg = "Broken pipe";
770 sigmsg = "Alarm clock";
774 sigmsg = "Terminated";
778 sprintf(sigmsg_buf, "Signal %d", sig);
790 if (fork_child != -1) {
792 kill(fork_child, SIGUSR1);
794 /* XXX: this is not the preferred method of closing a process!
795 * the clean way would be getting the process id of the child process,
796 * then getting window handle hWnd of that process (using EnumChildWindows),
797 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
799 * Unfortunately, I don't know how to get the process id from the handle */
800 /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
802 * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
803 * running in the same console, I don't know if that is true for our case.
804 * And this also will require to have the process id
806 TerminateProcess((HANDLE) fork_child, 0);
815 if (fork_child != -1)
817 kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
819 /* XXX: this is not the preferred method of closing a process!
820 * the clean way would be getting the process id of the child process,
821 * then getting window handle hWnd of that process (using EnumChildWindows),
822 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
824 * Unfortunately, I don't know how to get the process id from the handle */
825 /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
827 * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
828 * running in the same console, I don't know if that is true for our case.
829 * And this also will require to have the process id
831 TerminateProcess((HANDLE) fork_child, 0);
836 #endif /* HAVE_LIBPCAP */