Changes from Graham Bloice to support "Update list of packets in real

time" during captures on Win32.

svn path=/trunk/; revision=2074
This commit is contained in:
Guy Harris 2000-06-15 08:02:43 +00:00
parent 65b907e98d
commit f3eddb46cc
4 changed files with 153 additions and 28 deletions

View File

@ -299,6 +299,8 @@ Graham Bloice <graham.bloice@trihedral.com> {
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 <ralf.schneider@alcatel.se> {

150
capture.c
View File

@ -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 <gerald@zing.org>
@ -86,6 +86,10 @@
#include <pcap.h>
#endif
#ifdef _WIN32
#include <process.h> /* 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 <sys/wait.h> 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.

View File

@ -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 <gerald@zing.org>
@ -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);

View File

@ -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 <gerald@zing.org>
@ -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;