/* capture.c
* Routines for packet capture windows
*
- * $Id: capture.c,v 1.217 2003/11/17 19:40:09 guy Exp $
+ * $Id: capture.c,v 1.228 2004/01/25 21:55:09 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
# include <io.h>
#endif
-#include <gtk/gtk.h>
+#include <pcap.h>
+
+#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
-#include <pcap.h>
-
#ifdef NEED_SNPRINTF_H
# include "snprintf.h"
#endif
#include <epan/packet.h>
#include <epan/dfilter/dfilter.h>
+#include <epan/filesystem.h>
#include "file.h"
#include "capture.h"
#include "util.h"
#ifdef _WIN32
#include "capture-wpcap.h"
#endif
+#include "ui_util.h"
/*
* Capture options.
int quit_after_cap; /* Makes a "capture only mode". Implies -k */
gboolean capture_child; /* if this is the child for "-S" */
static int fork_child = -1; /* If not -1, in parent, process ID of child */
-static guint cap_input_id;
/*
* Indications sent out on the sync pipe.
#define SP_ERROR_MSG '!' /* followed by length of error message that follows */
#define SP_DROPS '#' /* followed by count of packets dropped in capture */
-#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 gboolean cap_pipe_input_cb(gint source, gpointer user_data);
static void wait_for_child(gboolean);
#ifndef _WIN32
static char *signame(int);
#define O_BINARY 0
#endif
-#ifdef _WIN32
-/* Win32 needs a handle to the child capture process */
-int child_process;
-#endif
-
/* Add a string pointer to a NULL-terminated array of string pointers. */
static char **
add_arg(char **args, int *argc, char *arg)
ringbuf_error_cleanup();
}
simple_dialog(ESD_TYPE_CRIT, NULL,
- file_open_error_message(errno, TRUE, WTAP_FILE_PCAP), capfile_name);
+ file_open_error_message(errno, TRUE), capfile_name);
}
g_free(capfile_name);
return FALSE;
char sautostop_filesize[24]; /* need a constant for len of numbers */
char sautostop_duration[24]; /* need a constant for len of numbers */
char save_file_fd[24];
+#ifndef _WIN32
char errmsg[1024+1];
+#endif
int error;
int argc;
char **argv;
/* Convert font name to a quote-encapsulated string and pass to child */
argv = add_arg(argv, &argc, "-m");
- fontstring = quote_encapsulate(prefs.gui_font_name);
+ fontstring = quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
argv = add_arg(argv, &argc, fontstring);
/* Convert pipe write handle to a string and pass to child */
if (filterstring) {
g_free(filterstring);
}
- /* Keep a copy for later evaluation by _cwait() */
- child_process = fork_child;
#else
if (pipe(sync_pipe) < 0) {
/* Couldn't create the pipe between parent and child. */
}
argv = add_arg(argv, &argc, "-m");
- argv = add_arg(argv, &argc, prefs.gui_font_name);
+ argv = add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) {
argv = add_arg(argv, &argc, "-f");
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. */
-#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) &cfile,
- NULL);
-#endif
+ pipe_input_set_handler(sync_pipe[READ], (gpointer) &cfile, &fork_child, cap_pipe_input_cb);
} else {
/* Not sync mode. */
capture_succeeded = capture(&stats_known, &stats);
if (quit_after_cap) {
/* DON'T unlink the save file. Presumably someone wants it. */
- gtk_exit(0);
+ main_window_exit();
}
if (!capture_succeeded) {
/* We didn't succeed in doing the capture, so we don't have a save
supplies, allowing us to display only the ones it does. */
cfile.drops = stats.ps_drop;
}
- switch (cf_read(&cfile, &err)) {
+ switch (cf_read(&cfile)) {
case READ_SUCCESS:
case READ_ERROR:
case READ_ABORTED:
/* Exit by leaving the main loop, so that any quit functions
we registered get called. */
- if (gtk_main_level() > 0)
- gtk_main_quit();
+ main_window_nested_quit();
return FALSE;
}
return TRUE;
}
-#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) &cfile, 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). */
-static void
-cap_file_input_cb(gpointer data, gint source _U_,
- GdkInputCondition condition _U_)
+static gboolean
+cap_pipe_input_cb(gint source, gpointer user_data)
{
- capture_file *cf = (capture_file *)data;
+ capture_file *cf = (capture_file *)user_data;
#define BUFSIZE 4096
char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
int nread, msglen, chars_to_copy;
int to_read = 0;
int err;
-#ifndef _WIN32
- /* avoid reentrancy problems and stack overflow */
- gtk_input_remove(cap_input_id);
-#endif
- if ((nread = read(sync_pipe[READ], buffer, BUFSIZE)) <= 0) {
+ if ((nread = read(source, buffer, BUFSIZE)) <= 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 did anything other than exit with status 0. */
case READ_ABORTED:
/* Exit by leaving the main loop, so that any quit functions
we registered get called. */
- gtk_main_quit();
- return;
+ main_window_quit();
+ return FALSE;
}
/* We're not doing a capture any more, so we don't have a save
g_free(cf->save_file);
cf->save_file = NULL;
- return;
+ return FALSE;
}
buffer[nread] = '\0';
while (msglen != 0) {
if (nread == 0) {
/* Read more. */
- if ((nread = read(sync_pipe[READ], buffer, BUFSIZE)) <= 0)
+ if ((nread = read(source, buffer, BUFSIZE)) <= 0)
break;
p = buffer;
q = buffer;
case READ_ABORTED:
/* Kill the child capture process; the user wants to exit, and we
shouldn't just leave it running. */
-#ifdef _WIN32
- /* XXX - kill it. */
-#else
- kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
-#endif
+ kill_capture_child();
break;
}
- /* restore pipe handler */
-#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
+ return TRUE;
}
static void
int wstatus;
#ifdef _WIN32
- /* XXX - analyze the wait stuatus and display more information
- in the dialog box? */
- if (_cwait(&wstatus, child_process, _WAIT_CHILD) == -1) {
+ /* XXX - analyze the wait status and display more information
+ in the dialog box?
+ XXX - set "fork_child" to -1 if we find it exited? */
+ if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) {
simple_dialog(ESD_TYPE_WARN, NULL, "Child capture process stopped unexpectedly");
}
#else
char errmsg[4096+1];
gboolean write_ok;
gboolean close_ok;
- fd_set set1;
- struct timeval timeout;
capture_info capture_ui;
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
#else
+ fd_set set1;
+ struct timeval timeout;
static const char ppamsg[] = "can't find PPA for ";
char *libpcap_warn;
int sel_ret;
capture-progress window, and, since we couldn't start the
capture, we haven't popped it up. */
if (!capture_child) {
- while (gtk_events_pending()) gtk_main_iteration();
+ main_window_update();
}
/* On Win32 OSes, the capture devices are probably available to all
"The capture session could not be initiated (%s).\n"
"Please check that you have the proper interface specified.\n"
"\n"
- "Note that the driver Ethereal uses for packet capture on Windows doesn't\n"
- "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
+ "Note that the WinPcap 2.x version of the driver Ethereal uses for packet\n"
+ "capture on Windows doesn't support capturing on PPP/WAN interfaces in\n"
+ "Windows NT/2000/XP/2003 Server, and that the WinPcap 3.0 and later versions\n"
+ "don't support capturing on PPP/WAN interfaces at all.",
open_err_str);
goto error;
#else
* capture, we haven't popped it up.
*/
if (!capture_child) {
- while (gtk_events_pending()) gtk_main_iteration();
+ main_window_update();
}
if (ld.pipe_err == PIPNEXIST) {
/* WOW, everything is prepared! */
/* please fasten your seat belts, we will enter now the actual capture loop */
while (ld.go) {
- while (gtk_events_pending()) gtk_main_iteration();
+ main_window_update();
#ifndef _WIN32
if (ld.from_pipe) {
void
capture_stop(void)
{
- /*
- * XXX - find some way of signaling the child in Win32.
- */
#ifndef _WIN32
if (fork_child != -1)
kill(fork_child, SIGUSR1);
+#else
+ if (fork_child != -1) {
+ /* XXX: this is not the preferred method of closing a process!
+ * the clean way would be getting the process id of the child process,
+ * then getting window handle hWnd of that process (using EnumChildWindows),
+ * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
+ *
+ * Unfortunately, I don't know how to get the process id from the handle */
+ /* Hint: OpenProcess will get an handle from the id, not vice versa :-(
+ *
+ * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are
+ * running in the same console, I don't know if that is true for our case.
+ * And this also will require to have the process id
+ */
+ TerminateProcess((HANDLE) fork_child, 0);
+ }
#endif
}
void
kill_capture_child(void)
{
- /*
- * XXX - find some way of signaling the child in Win32.
- */
#ifndef _WIN32
if (fork_child != -1)
kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
+#else
+ capture_stop();
#endif
}