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_wait_for_start(capture_options *capture_opts, int sync_pipe_read);
111 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
112 static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report);
114 /* Size of buffer to hold decimal representation of
115 signed/unsigned 64-bit int */
116 #define SP_DECISIZE 20
119 * Indications sent out on the sync pipe.
121 #define SP_CAPSTART ';' /* capture start message */
122 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
123 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
124 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
125 #define SP_FILE ':' /* followed by length of the name of the last opened file that follows */
130 sync_pipe_capstart_to_parent(void)
132 static const char capstart_msg = SP_CAPSTART;
134 write(1, &capstart_msg, 1);
138 sync_pipe_packet_count_to_parent(int packet_count)
140 char tmp[SP_DECISIZE+1+1];
141 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
142 write(1, tmp, strlen(tmp));
146 sync_pipe_filename_to_parent(const char *filename)
148 int msglen = strlen(filename);
149 char lenbuf[SP_DECISIZE+1+1];
151 sprintf(lenbuf, "%u%c", msglen, SP_FILE);
152 write(1, lenbuf, strlen(lenbuf));
153 write(1, filename, msglen);
157 sync_pipe_errmsg_to_parent(const char *errmsg)
159 int msglen = strlen(errmsg);
160 char lenbuf[SP_DECISIZE+1+1];
162 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
163 write(1, lenbuf, strlen(lenbuf));
164 write(1, errmsg, msglen);
168 sync_pipe_drops_to_parent(int drops)
170 char tmp[SP_DECISIZE+1+1];
171 sprintf(tmp, "%d%c", drops, SP_DROPS);
172 write(1, tmp, strlen(tmp));
176 /* Add a string pointer to a NULL-terminated array of string pointers. */
178 sync_pipe_add_arg(char **args, int *argc, char *arg)
180 /* Grow the array; "*argc" currently contains the number of string
181 pointers, *not* counting the NULL pointer at the end, so we have
182 to add 2 in order to get the new size of the array, including the
183 new pointer and the terminating NULL pointer. */
184 args = g_realloc(args, (*argc + 2) * sizeof (char *));
186 /* Stuff the pointer into the penultimate element of the array, which
187 is the one at the index specified by "*argc". */
190 /* Now bump the count. */
193 /* We overwrite the NULL pointer; put it back right after the
201 /* Given a string, return a pointer to a quote-encapsulated version of
202 the string, so we can pass it as an argument with "spawnvp" even
203 if it contains blanks. */
205 sync_pipe_quote_encapsulate(const char *string)
207 char *encapsulated_string;
209 encapsulated_string = g_new(char, strlen(string) + 3);
210 sprintf(encapsulated_string, "\"%s\"", string);
211 return encapsulated_string;
217 #define ARGV_NUMBER_LEN 24
220 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
221 char ssnap[ARGV_NUMBER_LEN];
222 char scount[ARGV_NUMBER_LEN];
223 char sfilesize[ARGV_NUMBER_LEN];
224 char sfile_duration[ARGV_NUMBER_LEN];
225 char sring_num_files[ARGV_NUMBER_LEN];
226 char sautostop_files[ARGV_NUMBER_LEN];
227 char sautostop_filesize[ARGV_NUMBER_LEN];
228 char sautostop_duration[ARGV_NUMBER_LEN];
230 char sync_pipe_fd[ARGV_NUMBER_LEN];
238 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
239 int sync_pipe[2]; /* pipes used to sync between instances */
242 /*g_warning("sync_pipe_do_capture");
243 capture_opts_info(capture_opts);*/
245 capture_opts->fork_child = -1;
247 /* Allocate the string pointer array with enough space for the
248 terminating NULL pointer. */
250 argv = g_malloc(sizeof (char *));
253 /* Now add those arguments used on all platforms. */
254 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
256 argv = sync_pipe_add_arg(argv, &argc, "-i");
257 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
259 if(capture_opts->save_file) {
260 argv = sync_pipe_add_arg(argv, &argc, "-w");
261 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
264 if (capture_opts->has_snaplen) {
265 argv = sync_pipe_add_arg(argv, &argc, "-s");
266 sprintf(ssnap,"%d",capture_opts->snaplen);
267 argv = sync_pipe_add_arg(argv, &argc, ssnap);
270 if (capture_opts->linktype != -1) {
271 argv = sync_pipe_add_arg(argv, &argc, "-y");
272 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
273 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
275 /* XXX - just treat it as a number */
276 sprintf(ssnap,"%d",capture_opts->linktype);
278 argv = sync_pipe_add_arg(argv, &argc, ssnap);
281 if(capture_opts->multi_files_on) {
282 if (capture_opts->has_autostop_filesize) {
283 argv = sync_pipe_add_arg(argv, &argc, "-b");
284 sprintf(sfilesize,"filesize:%d",capture_opts->autostop_filesize);
285 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
288 if (capture_opts->has_file_duration) {
289 argv = sync_pipe_add_arg(argv, &argc, "-b");
290 sprintf(sfile_duration,"duration:%d",capture_opts->file_duration);
291 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
294 if (capture_opts->has_ring_num_files) {
295 argv = sync_pipe_add_arg(argv, &argc, "-b");
296 sprintf(sring_num_files,"files:%d",capture_opts->ring_num_files);
297 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
300 if (capture_opts->has_autostop_files) {
301 argv = sync_pipe_add_arg(argv, &argc, "-a");
302 sprintf(sautostop_files,"files:%d",capture_opts->autostop_files);
303 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
306 if (capture_opts->has_autostop_filesize) {
307 argv = sync_pipe_add_arg(argv, &argc, "-a");
308 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
309 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
313 if (capture_opts->has_autostop_packets) {
314 argv = sync_pipe_add_arg(argv, &argc, "-c");
315 sprintf(scount,"%d",capture_opts->autostop_packets);
316 argv = sync_pipe_add_arg(argv, &argc, scount);
319 if (capture_opts->has_autostop_duration) {
320 argv = sync_pipe_add_arg(argv, &argc, "-a");
321 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
322 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
325 if (!capture_opts->show_info) {
326 argv = sync_pipe_add_arg(argv, &argc, "-H");
329 if (!capture_opts->promisc_mode)
330 argv = sync_pipe_add_arg(argv, &argc, "-p");
333 /* Create a pipe for the child process */
334 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
335 /* Couldn't create the pipe between parent and child. */
336 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
341 /* Convert font name to a quote-encapsulated string and pass to child */
342 argv = sync_pipe_add_arg(argv, &argc, "-m");
343 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
344 argv = sync_pipe_add_arg(argv, &argc, fontstring);
346 /* Convert pipe write handle to a string and pass to child */
347 argv = sync_pipe_add_arg(argv, &argc, "-Z");
348 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
349 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
351 /* Convert filter string to a quote delimited string and pass to child */
353 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
354 argv = sync_pipe_add_arg(argv, &argc, "-f");
355 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
356 argv = sync_pipe_add_arg(argv, &argc, filterstring);
360 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
363 g_free(filterstring);
366 if (pipe(sync_pipe) < 0) {
367 /* Couldn't create the pipe between parent and child. */
368 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
373 argv = sync_pipe_add_arg(argv, &argc, "-m");
374 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
376 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
377 argv = sync_pipe_add_arg(argv, &argc, "-f");
378 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
381 if ((capture_opts->fork_child = fork()) == 0) {
383 * Child process - run Ethereal with the right arguments to make
384 * it just pop up the live capture dialog box and capture with
385 * the specified capture parameters, writing to the specified file.
387 * args: -i interface specification
389 * -W file descriptor to write
390 * -c count to capture
393 * -f "filter expression"
396 dup(sync_pipe[PIPE_WRITE]);
397 close(sync_pipe[PIPE_READ]);
398 execvp(ethereal_path, argv);
399 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
400 ethereal_path, strerror(errno));
401 sync_pipe_errmsg_to_parent(errmsg);
403 /* Exit with "_exit()", so that we don't close the connection
404 to the X server (and cause stuff buffered up by our parent but
405 not yet sent to be sent, as that stuff should only be sent by
411 /* Parent process - read messages from the child process over the
413 g_free(argv); /* free up arg array */
415 /* Close the write side of the pipe, so that only the child has it
416 open, and thus it completely closes, and thus returns to us
417 an EOF indication, if the child closes it (either deliberately
418 or by exiting abnormally). */
419 close(sync_pipe[PIPE_WRITE]);
421 if (capture_opts->fork_child == -1) {
422 /* We couldn't even create the child process. */
423 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
424 "Couldn't create child process: %s", strerror(errno));
425 close(sync_pipe[PIPE_READ]);
429 /* the child have to send us a capture start or error message now */
430 if(!sync_pipe_input_wait_for_start(capture_opts, sync_pipe[PIPE_READ])) {
431 /* Close the sync pipe. */
432 close(sync_pipe[PIPE_READ]);
436 /* We were able to set up to read the capture file;
437 arrange that our callback be called whenever it's possible
438 to read from the sync pipe, so that it's called when
439 the child process wants to tell us something. */
441 /* we have a running capture, now wait for the real capture filename */
442 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts,
443 &capture_opts->fork_child, sync_pipe_input_cb);
449 /* capture prepared, waiting for the child to signal us capture has indeed started */
451 sync_pipe_input_wait_for_start(capture_options *capture_opts, int sync_pipe_read) {
458 /* Read a byte count from "sync_pipe_read", terminated with a
459 colon; if the count is 0, the child process created the
460 capture file and we should start reading from it, otherwise
461 the capture couldn't start and the count is a count of bytes
462 of error message, and we should display the message. */
465 i = read(sync_pipe_read, &c, 1);
467 /* EOF - the child process died, report the failure. */
468 sync_pipe_wait_for_child(capture_opts, TRUE);
472 /* the first message should be the capture start or an error message */
473 if (c == SP_CAPSTART || c == SP_ERROR_MSG) {
478 /* Child process handed us crap, report the failure. */
479 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
480 "Capture child process sent us a bad message");
484 byte_count = byte_count*10 + c - '0';
486 if (c != SP_CAPSTART) {
487 /* Failure - the child process sent us a message indicating
488 what the problem was. */
489 if (byte_count == 0) {
490 /* Zero-length message? */
491 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
492 "Capture child process failed, but its error message was empty.");
496 msg = g_malloc(byte_count + 1);
498 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
499 "Capture child process failed, but its error message was too big.");
503 i = read(sync_pipe_read, msg, byte_count);
504 msg[byte_count] = '\0';
506 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
507 "Capture child process failed: Error %s reading its error message.",
514 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
515 "Capture child process failed: EOF reading its error message.");
516 sync_pipe_wait_for_child(capture_opts, FALSE);
521 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
527 g_assert_not_reached();
532 /* There's stuff to read from the sync pipe, meaning the child has sent
533 us a message, or the sync pipe has closed, meaning the child has
534 closed it (perhaps because it exited). */
536 sync_pipe_input_cb(gint source, gpointer user_data)
538 capture_options *capture_opts = (capture_options *)user_data;
540 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
541 int nread, msglen, chars_to_copy;
545 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
546 /* The child has closed the sync pipe, meaning it's not going to be
547 capturing any more packets. Pick up its exit status, and
548 complain if it did anything other than exit with status 0. */
549 sync_pipe_wait_for_child(capture_opts, FALSE);
550 capture_input_closed(capture_opts);
554 buffer[nread] = '\0';
557 /* look for (possibly multiple) indications */
559 case SP_PACKET_COUNT :
566 cf_set_drops_known(capture_opts->cf, TRUE);
567 cf_set_drops(capture_opts->cf, atoi(p));
578 /* Read the entire message.
579 XXX - if the child hasn't sent it all yet, this could cause us
580 to hang until they do. */
581 msg = g_malloc(msglen + 1);
583 while (msglen != 0) {
586 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
591 chars_to_copy = MIN(msglen, nread);
592 memcpy(r, q, chars_to_copy);
595 nread -= chars_to_copy;
596 msglen -= chars_to_copy;
599 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
608 /* Read the entire file name.
609 XXX - if the child hasn't sent it all yet, this could cause us
610 to hang until they do. */
611 msg = g_malloc(msglen + 1);
613 while (msglen != 0) {
616 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
621 chars_to_copy = MIN(msglen, nread);
622 memcpy(r, q, chars_to_copy);
625 nread -= chars_to_copy;
626 msglen -= chars_to_copy;
630 if(!capture_input_new_file(capture_opts, msg)) {
631 /* We weren't able to open the new capture file; user has been
632 alerted. Close the sync pipe. */
633 /* close(sync_pipe[PIPE_READ]);*/
635 /* XXX - how to kill things here ? */
636 /* XXX - is it safe to close the pipe inside this callback? */
650 capture_input_new_packets(capture_opts, to_read);
656 /* the child process is going down, wait until it's completely terminated */
658 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
663 g_assert(capture_opts->fork_child != -1);
666 /* XXX - analyze the wait status and display more information
668 XXX - set "fork_child" to -1 if we find it exited? */
669 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
670 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
671 "Child capture process stopped unexpectedly");
674 if (wait(&wstatus) != -1) {
675 if (WIFEXITED(wstatus)) {
676 /* The child exited; display its exit status, if it's not zero,
677 and even if it's zero if "always_report" is true. */
678 if (always_report || WEXITSTATUS(wstatus) != 0) {
679 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
680 "Child capture process exited: exit status %d",
681 WEXITSTATUS(wstatus));
683 } else if (WIFSTOPPED(wstatus)) {
684 /* It stopped, rather than exiting. "Should not happen." */
685 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
686 "Child capture process stopped: %s",
687 sync_pipe_signame(WSTOPSIG(wstatus)));
688 } else if (WIFSIGNALED(wstatus)) {
689 /* It died with a signal. */
690 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
691 "Child capture process died: %s%s",
692 sync_pipe_signame(WTERMSIG(wstatus)),
693 WCOREDUMP(wstatus) ? " - core dumped" : "");
695 /* What? It had to either have exited, or stopped, or died with
696 a signal; what happened here? */
697 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
698 "Child capture process died: wait status %#o", wstatus);
702 /* No more child process. */
703 capture_opts->fork_child = -1;
710 sync_pipe_signame(int sig)
713 static char sigmsg_buf[6+1+3+1];
722 sigmsg = "Interrupted";
730 sigmsg = "Illegal instruction";
734 sigmsg = "Trace trap";
742 sigmsg = "Arithmetic exception";
750 sigmsg = "Bus error";
754 sigmsg = "Segmentation violation";
757 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
758 Linux is POSIX compliant. These are not POSIX-defined signals ---
759 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
761 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
762 were omitted from POSIX.1 because their behavior is
763 implementation dependent and could not be adequately catego-
764 rized. Conforming implementations may deliver these sig-
765 nals, but must document the circumstances under which they
766 are delivered and note any restrictions concerning their
769 So we only check for SIGSYS on those systems that happen to
770 implement them (a system can be POSIX-compliant and implement
771 them, it's just that POSIX doesn't *require* a POSIX-compliant
772 system to implement them).
777 sigmsg = "Bad system call";
782 sigmsg = "Broken pipe";
786 sigmsg = "Alarm clock";
790 sigmsg = "Terminated";
794 sprintf(sigmsg_buf, "Signal %d", sig);
804 sync_pipe_stop(capture_options *capture_opts)
806 /* XXX - in which cases this will be 0? */
807 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
809 kill(capture_opts->fork_child, SIGUSR1);
811 /* XXX: this is not the preferred method of closing a process!
812 * the clean way would be getting the process id of the child process,
813 * then getting window handle hWnd of that process (using EnumChildWindows),
814 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
816 * Unfortunately, I don't know how to get the process id from the
817 * handle. OpenProcess will get an handle (not a window handle)
818 * from the process ID; it will not get a window handle from the
819 * process ID. (How could it? A process can have more than one
822 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
823 * running in the same console; that's not necessarily the case for
824 * us, as we might not be running in a console.
825 * And this also will require to have the process id.
827 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
834 sync_pipe_kill(capture_options *capture_opts)
836 /* XXX - in which cases this will be 0? */
837 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
839 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
841 /* XXX: this is not the preferred method of closing a process!
842 * the clean way would be getting the process id of the child process,
843 * then getting window handle hWnd of that process (using EnumChildWindows),
844 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
846 * Unfortunately, I don't know how to get the process id from the
847 * handle. OpenProcess will get an handle (not a window handle)
848 * from the process ID; it will not get a window handle from the
849 * process ID. (How could it? A process can have more than one
852 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
853 * running in the same console; that's not necessarily the case for
854 * us, as we might not be running in a console.
855 * And this also will require to have the process id.
857 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
862 #endif /* HAVE_LIBPCAP */