diff --git a/AUTHORS b/AUTHORS index 1d9fac8a6c..29faeae890 100644 --- a/AUTHORS +++ b/AUTHORS @@ -299,6 +299,8 @@ Graham Bloice { add version/copyright/etc. information to Win32 executables Support for sorting columns in the summary by clicking on them Win32 Makefile improvements + Support for "Update list of packets in real time" during capture + on Win32 } Ralf Schneider { diff --git a/capture.c b/capture.c index 6c7ad30494..10d123445c 100644 --- a/capture.c +++ b/capture.c @@ -1,7 +1,7 @@ /* capture.c * Routines for packet capture windows * - * $Id: capture.c,v 1.107 2000/06/15 04:22:58 guy Exp $ + * $Id: capture.c,v 1.108 2000/06/15 08:02:20 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -86,6 +86,10 @@ #include #endif +#ifdef _WIN32 +#include /* For spawning child process */ +#endif + #include "gtk/main.h" #include "gtk/gtkglobals.h" #include "packet.h" @@ -106,10 +110,16 @@ int sync_mode; /* fork a child to do the capture, and sync between them */ static int sync_pipe[2]; /* used to sync father */ +enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */ int quit_after_cap; /* Makes a "capture only mode". Implies -k */ gboolean capture_child; /* if this is the child for "-S" */ static guint cap_input_id; +#ifdef _WIN32 +static guint cap_timer_id; +static int cap_timer_cb(gpointer); /* Win32 kludge to check for pipe input */ +#endif + static void cap_file_input_cb(gpointer, gint, GdkInputCondition); static void capture_delete_cb(GtkWidget *, GdkEvent *, gpointer); static void capture_stop_cb(GtkWidget *, gpointer); @@ -132,6 +142,11 @@ typedef struct _loop_data { #define O_BINARY 0 #endif +#ifdef _WIN32 +/* Win32 needs a handle to the child capture process */ +int child_process; +#endif + /* Open a specified file, or create a temporary file, and start a capture to the file in question. */ void @@ -167,17 +182,53 @@ do_capture(char *capfile_name) cf.save_file = capfile_name; if (sync_mode) { /* do the capture in a child process */ -#ifndef _WIN32 int fork_child; char ssnap[24]; char scount[24]; /* need a constant for len of numbers */ char save_file_fd[24]; char errmsg[1024+1]; int error; +#ifdef _WIN32 + char sync_pipe_fd[24]; + char *filterstring; +#endif sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */ sprintf(scount,"%d",cf.count); sprintf(save_file_fd,"%d",cf.save_file_fd); + +#ifdef _WIN32 + /* Create a pipe for the child process */ + + if(_pipe(sync_pipe, 512, O_BINARY) < 0) { + /* Couldn't create the pipe between parent and child. */ + error = errno; + unlink(cf.save_file); + g_free(cf.save_file); + cf.save_file = NULL; + simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't create sync pipe: %s", + strerror(error)); + return; + } + + /* Convert pipe write handle to a string and pass to child */ + itoa(sync_pipe[WRITE], sync_pipe_fd, 10); + /* Convert filter string to a quote delimited string */ + filterstring = g_new(char, strlen(cf.cfilter) + 3); + sprintf(filterstring, "\"%s\"", cf.cfilter); + filterstring[strlen(cf.cfilter) + 2] = 0; + /* Spawn process */ + fork_child = spawnlp(_P_NOWAIT, ethereal_path, CHILD_NAME, "-i", cf.iface, + "-w", cf.save_file, "-W", save_file_fd, + "-c", scount, "-s", ssnap, + "-Z", sync_pipe_fd, + strlen(cf.cfilter) == 0 ? (const char *)NULL : "-f", + strlen(cf.cfilter) == 0 ? (const char *)NULL : filterstring, + (const char *)NULL); + g_free(filterstring); + /* Keep a copy for later evaluation by _cwait() */ + child_process = fork_child; +#else signal(SIGCHLD, SIG_IGN); if (pipe(sync_pipe) < 0) { /* Couldn't create the pipe between parent and child. */ @@ -204,8 +255,8 @@ do_capture(char *capfile_name) * -f "filter expression" */ close(1); - dup(sync_pipe[1]); - close(sync_pipe[0]); + dup(sync_pipe[WRITE]); + close(sync_pipe[READ]); execlp(ethereal_path, CHILD_NAME, "-i", cf.iface, "-w", cf.save_file, "-W", save_file_fd, "-c", scount, "-s", ssnap, @@ -223,6 +274,7 @@ do_capture(char *capfile_name) our parent). */ _exit(2); } +#endif /* Parent process - read messages from the child process over the sync pipe. */ @@ -231,7 +283,7 @@ do_capture(char *capfile_name) open, and thus it completely closes, and thus returns to us an EOF indication, if the child closes it (either deliberately or by exiting abnormally). */ - close(sync_pipe[1]); + close(sync_pipe[WRITE]); /* Close the save file FD, as we won't be using it - we'll be opening it and reading the save file through Wiretap. */ @@ -240,7 +292,7 @@ do_capture(char *capfile_name) if (fork_child == -1) { /* We couldn't even create the child process. */ error = errno; - close(sync_pipe[0]); + close(sync_pipe[READ]); unlink(cf.save_file); g_free(cf.save_file); cf.save_file = NULL; @@ -249,20 +301,20 @@ do_capture(char *capfile_name) return; } - /* Read a byte count from "sync_pipe[0]", terminated with a + /* Read a byte count from "sync_pipe[READ]", terminated with a colon; if the count is 0, the child process created the capture file and we should start reading from it, otherwise the capture couldn't start and the count is a count of bytes of error message, and we should display the message. */ byte_count = 0; for (;;) { - i = read(sync_pipe[0], &c, 1); + i = read(sync_pipe[READ], &c, 1); if (i == 0) { /* EOF - the child process died. Close the read side of the sync pipe, remove the capture file, and report the failure. XXX - reap the child process and report the status in detail. */ - close(sync_pipe[0]); + close(sync_pipe[READ]); unlink(cf.save_file); g_free(cf.save_file); cf.save_file = NULL; @@ -275,7 +327,7 @@ do_capture(char *capfile_name) /* Child process handed us crap. Close the read side of the sync pipe, remove the capture file, and report the failure. */ - close(sync_pipe[0]); + close(sync_pipe[READ]); unlink(cf.save_file); g_free(cf.save_file); cf.save_file = NULL; @@ -293,12 +345,21 @@ do_capture(char *capfile_name) arrange that our callback be called whenever it's possible to read from the sync pipe, so that it's called when the child process wants to tell us something. */ - cap_input_id = gtk_input_add_full(sync_pipe[0], +#ifdef _WIN32 + /* Tricky to use pipes in win9x, as no concept of wait. NT can + do this but that doesn't cover all win32 platforms. GTK can do + this but doesn't seem to work over processes. Attempt to do + something similar here, start a timer and check for data on every + timeout. */ + cap_timer_id = gtk_timeout_add(1000, cap_timer_cb, NULL); +#else + cap_input_id = gtk_input_add_full(sync_pipe[READ], GDK_INPUT_READ|GDK_INPUT_EXCEPTION, cap_file_input_cb, NULL, (gpointer) &cf, NULL); +#endif } else { /* We weren't able to open the capture file; complain, and close the sync pipe. */ @@ -306,7 +367,7 @@ do_capture(char *capfile_name) file_open_error_message(err, FALSE), cf.save_file); /* Close the sync pipe. */ - close(sync_pipe[0]); + close(sync_pipe[READ]); /* Don't unlink the save file - leave it around, for debugging purposes. */ @@ -321,7 +382,7 @@ do_capture(char *capfile_name) simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process failed, but its error message was too big."); } else { - i = read(sync_pipe[0], msg, byte_count); + i = read(sync_pipe[READ], msg, byte_count); if (i < 0) { simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process failed: Error %s reading its error message.", @@ -334,7 +395,7 @@ do_capture(char *capfile_name) g_free(msg); /* Close the sync pipe. */ - close(sync_pipe[0]); + close(sync_pipe[READ]); /* Get rid of the save file - the capture never started. */ unlink(cf.save_file); @@ -342,7 +403,6 @@ do_capture(char *capfile_name) cf.save_file = NULL; } } -#endif } else { /* Not sync mode. */ capture_succeeded = capture(); @@ -365,7 +425,46 @@ do_capture(char *capfile_name) } } -#ifndef _WIN32 +#ifdef _WIN32 +/* The timer has expired, see if there's stuff to read from the pipe, + if so call the cap_file_input_cb */ +static gint +cap_timer_cb(gpointer data) +{ + HANDLE handle; + DWORD avail = 0; + gboolean result, result1; + DWORD childstatus; + + /* Oddly enough although Named pipes don't work on win9x, + PeekNamedPipe does !!! */ + handle = (HANDLE) _get_osfhandle (sync_pipe[READ]); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + + /* Get the child process exit status */ + result1 = GetExitCodeProcess((HANDLE)child_process, &childstatus); + + /* If the Peek returned an error, or there are bytes to be read + or the childwatcher thread has terminated then call the normal + callback */ + if (!result || avail > 0 || childstatus != STILL_ACTIVE) { + + /* avoid reentrancy problems and stack overflow */ + gtk_timeout_remove(cap_timer_id); + + /* And call the real handler */ + cap_file_input_cb((gpointer) &cf, 0, 0); + + /* Return false so that the timer is not run again */ + return FALSE; + } + else { + /* No data so let timer run again */ + return TRUE; + } +} +#endif + /* There's stuff to read from the sync pipe, meaning the child has sent us a message, or the sync pipe has closed, meaning the child has closed it (perhaps because it exited). */ @@ -385,13 +484,22 @@ cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition) char sigmsg_buf[6+1+3+1]; char *coredumped; +#ifndef _WIN32 /* avoid reentrancy problems and stack overflow */ gtk_input_remove(cap_input_id); +#endif - if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) { + if ((nread = read(sync_pipe[READ], buffer, 256)) <= 0) { /* The child has closed the sync pipe, meaning it's not going to be capturing any more packets. Pick up its exit status, and complain if it died of a signal. */ +#ifdef _WIN32 + /* XXX - analyze the wait stuatus and display more information + in the dialog box? */ + if (_cwait(&wstatus, child_process, _WAIT_CHILD) == -1) { + simple_dialog(ESD_TYPE_WARN, NULL, "Child capture process stopped unexpectedly"); + } +#else if (wait(&wstatus) != -1) { /* XXX - are there any platforms on which we can run that *don't* support POSIX.1's and macros therein? */ @@ -489,6 +597,7 @@ cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition) "Child capture process %s: %s%s", msg, sigmsg, coredumped); } } +#endif /* Read what remains of the capture file, and finish the capture. XXX - do something if this fails? */ @@ -528,14 +637,17 @@ cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition) err = continue_tail_cap_file(cf, to_read); /* restore pipe handler */ - cap_input_id = gtk_input_add_full (sync_pipe[0], +#ifdef _WIN32 + cap_timer_id = gtk_timeout_add(1000, cap_timer_cb, NULL); +#else + cap_input_id = gtk_input_add_full (sync_pipe[READ], GDK_INPUT_READ|GDK_INPUT_EXCEPTION, cap_file_input_cb, NULL, (gpointer) cf, NULL); +#endif } -#endif /* _WIN32 */ /* * Timeout, in milliseconds, for reads from the stream of captured packets. diff --git a/gtk/capture_dlg.c b/gtk/capture_dlg.c index 0fc3094bc6..ac26f4a5bb 100644 --- a/gtk/capture_dlg.c +++ b/gtk/capture_dlg.c @@ -1,7 +1,7 @@ /* capture_dlg.c * Routines for packet capture windows * - * $Id: capture_dlg.c,v 1.25 2000/05/08 07:13:39 guy Exp $ + * $Id: capture_dlg.c,v 1.26 2000/06/15 08:02:42 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -246,18 +246,12 @@ capture_prep_cb(GtkWidget *w, gpointer d) sync_cb = dlg_check_button_new_with_label_with_mnemonic( "_Update list of packets in real time", accel_group); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(sync_cb), sync_mode); -#ifdef _WIN32 - gtk_widget_set_sensitive(sync_cb, FALSE); -#endif gtk_container_add(GTK_CONTAINER(main_vb), sync_cb); gtk_widget_show(sync_cb); auto_scroll_cb = dlg_check_button_new_with_label_with_mnemonic( "_Automatic scrolling in live capture", accel_group); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(auto_scroll_cb), auto_scroll_live); -#ifdef _WIN32 - gtk_widget_set_sensitive(auto_scroll_cb, FALSE); -#endif gtk_container_add(GTK_CONTAINER(main_vb), auto_scroll_cb); gtk_widget_show(auto_scroll_cb); diff --git a/gtk/main.c b/gtk/main.c index b5d3f611e7..05b2952af0 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1,6 +1,6 @@ /* main.c * - * $Id: main.c,v 1.120 2000/06/05 03:09:21 gram Exp $ + * $Id: main.c,v 1.121 2000/06/15 08:02:43 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -1299,7 +1299,7 @@ main(int argc, char *argv[]) ); /* Now get our args */ - while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) { + while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) { switch (opt) { case 'b': /* Bold font */ bold_font = g_strdup(optarg); @@ -1429,6 +1429,23 @@ main(int argc, char *argv[]) arg_error = TRUE; #endif break; + +#ifdef _WIN32 + case 'Z': /* Write to pipe FD XXX */ +#ifdef HAVE_LIBPCAP + /* associate stdout with pipe */ + i = atoi(optarg); + if (dup2(i, 1) < 0) { + fprintf(stderr, "Unable to dup pipe handle\n"); + exit(1); + } +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif /* HAVE_LIBPCAP */ + break; +#endif /* _WIN32 */ + default: case '?': /* Bad flag - print usage message */ arg_error = TRUE;