summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2006-03-05 03:14:16 +0000
committerGuy Harris <guy@alum.mit.edu>2006-03-05 03:14:16 +0000
commitcbe69401ccddfe65c2320f06592e868f980b101a (patch)
tree96501d3ec05c28eb6978a72e86c1e480b2293ab1
parentfd39d0ebed46f2c127653e98940a6f9bb529effa (diff)
downloadwireshark-cbe69401ccddfe65c2320f06592e868f980b101a.tar.gz
Pass two strings in capture child messages, so the child can send
primary and secondary error messages and let the parent worry about how to display them. This means dumpcap doesn't need stub routines for generating the formatting tags for the primary and secondary messages. Have a separate message for capture filter errors, so that the parent can check whether the capture filter looks like a display filter and report the appropriate message. This means that dumpcap doesn't need a stub routine for compiling display filters (a stub routine also means that Ethereal won't do the check for capture filters that look like display filters!). svn path=/trunk/; revision=17465
-rw-r--r--capture.c86
-rw-r--r--capture.h16
-rw-r--r--capture_loop.c142
-rw-r--r--capture_loop.h14
-rw-r--r--capture_sync.c89
-rw-r--r--capture_sync.h8
-rw-r--r--dumpcap.c98
-rw-r--r--tethereal.c126
8 files changed, 358 insertions, 221 deletions
diff --git a/capture.c b/capture.c
index 18158aec46..4ddf910acd 100644
--- a/capture.c
+++ b/capture.c
@@ -240,7 +240,7 @@ guint32 drops)
}
-/* capture child tells us, we have a new (or the first) capture file */
+/* capture child tells us we have a new (or the first) capture file */
gboolean
capture_input_new_file(capture_options *capture_opts, gchar *new_file)
{
@@ -308,7 +308,7 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file)
}
-/* capture child tells us, we have new packets to read */
+/* capture child tells us we have new packets to read */
void
capture_input_new_packets(capture_options *capture_opts, int to_read)
{
@@ -353,7 +353,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read)
}
-/* Capture child told us, how many dropped packets it counted.
+/* Capture child told us how many dropped packets it counted.
*/
void
capture_input_drops(capture_options *capture_opts, int dropped)
@@ -367,21 +367,91 @@ capture_input_drops(capture_options *capture_opts, int dropped)
}
-/* Capture child told us, that an error has occurred while starting/running the capture. */
+/* Capture child told us that an error has occurred while starting/running
+ the capture.
+ The buffer we're handed has *two* null-terminated strings in it - a
+ primary message and a secondary message, one right after the other.
+ The secondary message might be a null string.
+ */
void
-capture_input_error_message(capture_options *capture_opts, char *error_message)
+capture_input_error_message(capture_options *capture_opts, char *error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\"", error_message);
+ char *secondary_error_msg = strchr(error_msg, '\0') + 1;
+ gchar *safe_error_msg;
+ gchar *safe_secondary_error_msg;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
+ error_msg, secondary_error_msg);
g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_message);
+ safe_error_msg = simple_dialog_format_message(error_msg);
+ if (*secondary_error_msg != '\0') {
+ /* We have both primary and secondary messages. */
+ safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
+ simple_dialog_primary_start(), safe_error_msg,
+ simple_dialog_primary_end(), safe_secondary_error_msg);
+ g_free(safe_secondary_error_msg);
+ } else {
+ /* We have only a primary message. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
+ simple_dialog_primary_start(), safe_error_msg,
+ simple_dialog_primary_end());
+ }
+ g_free(safe_error_msg);
+
+ /* the capture child will close the sync_pipe if required, nothing to do for now */
+}
+
+
+
+/* Capture child told us that an error has occurred while parsing a
+ capture filter when starting/running the capture.
+ */
+void
+capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
+{
+ dfilter_t *rfcode = NULL;
+ gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
+ gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
+
+ g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
+
+ /* Did the user try a display filter? */
+ if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%sInvalid capture filter: \"%s\"!%s\n"
+ "\n"
+ "That string looks like a valid display filter; however, it isn't a valid\n"
+ "capture filter (%s).\n"
+ "\n"
+ "Note that display filters and capture filters don't have the same syntax,\n"
+ "so you can't use most display filter expressions as capture filters.\n"
+ "\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ simple_dialog_primary_start(), safe_cfilter,
+ simple_dialog_primary_end(), safe_cfilter_error_msg);
+ dfilter_free(rfcode);
+ } else {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%sInvalid capture filter: \"%s\"!%s\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ simple_dialog_primary_start(), safe_cfilter,
+ simple_dialog_primary_end(), safe_cfilter_error_msg);
+ }
+ g_free(safe_cfilter_error_msg);
+ g_free(safe_cfilter);
/* the capture child will close the sync_pipe if required, nothing to do for now */
}
-/* capture child closed it's side ot the pipe, do the required cleanup */
+/* capture child closed its side of the pipe, do the required cleanup */
void
capture_input_closed(capture_options *capture_opts)
{
diff --git a/capture.h b/capture.h
index 671fe281e0..f36dd50348 100644
--- a/capture.h
+++ b/capture.h
@@ -51,27 +51,33 @@ extern void capture_restart(capture_options *capture_opts);
extern void capture_kill_child(capture_options *capture_opts);
/**
- * Capture child told us, we have a new (or the first) capture file.
+ * Capture child told us we have a new (or the first) capture file.
*/
extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file);
/**
- * Capture child told us, we have new packets to read.
+ * Capture child told us we have new packets to read.
*/
extern void capture_input_new_packets(capture_options *capture_opts, int to_read);
/**
- * Capture child told us, how many dropped packets it counted.
+ * Capture child told us how many dropped packets it counted.
*/
extern void capture_input_drops(capture_options *capture_opts, int dropped);
/**
- * Capture child told us, that an error has occurred while starting the capture.
+ * Capture child told us that an error has occurred while starting the capture.
*/
extern void capture_input_error_message(capture_options *capture_opts, char *error_message);
/**
- * Capture child closed it's side ot the pipe, do the required cleanup.
+ * Capture child told us that an error has occurred while parsing a
+ * capture filter when starting/running the capture.
+ */
+extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message);
+
+/**
+ * Capture child closed its side of the pipe, do the required cleanup.
*/
extern void capture_input_closed(capture_options *capture_opts);
diff --git a/capture_loop.c b/capture_loop.c
index dc4eb74c51..492f6011c3 100644
--- a/capture_loop.c
+++ b/capture_loop.c
@@ -87,7 +87,11 @@
#include "capture_loop.h"
-
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+ "Please report this to the Ethereal developers";
/*
* This needs to be static, so that the SIGUSR1 handler can clear the "go"
@@ -429,7 +433,11 @@ cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
/* open the capture input file (pcap or capture pipe) */
-gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len) {
+gboolean
+capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len)
+{
gchar open_err_str[PCAP_ERRBUF_SIZE];
gchar *sync_msg_str;
const char *set_linktype_err_str;
@@ -489,6 +497,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
"Couldn't initialize Windows Sockets: error %d", err);
break;
}
+ g_snprintf(secondary_errmsg, secondary_errmsg_len, please_report);
return FALSE;
}
#endif
@@ -509,16 +518,15 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
#ifdef _WIN32
/* try to set the capture buffer size */
if (pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
- sync_msg_str = g_strdup_printf(
- "%sCouldn't set the capture buffer size!%s\n"
- "\n"
+ sync_secondary_msg_str = g_strdup_printf(
"The capture buffer size of %luMB seems to be too high for your machine,\n"
"the default of 1MB will be used.\n"
"\n"
"Nonetheless, the capture is started.\n",
- simple_dialog_primary_start(), simple_dialog_primary_end(), capture_opts->buffer_size);
- sync_pipe_errmsg_to_parent(sync_msg_str);
- g_free(sync_msg_str);
+ capture_opts->buffer_size);
+ sync_pipe_errmsg_to_parent("Couldn't set the capture buffer size!",
+ sync_secondary_msg_str);
+ g_free(sync_secondary_msg_str);
}
#endif
@@ -528,7 +536,9 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
capture_opts->linktype);
if (set_linktype_err_str != NULL) {
g_snprintf(errmsg, errmsg_len, "Unable to set data link type (%s).",
- set_linktype_err_str);
+ set_linktype_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
+ "Please report this to the Ethereal developers");
return FALSE;
}
}
@@ -543,9 +553,9 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
Do, however, warn about the lack of 64-bit support, and warn that
WAN devices aren't supported. */
g_snprintf(errmsg, errmsg_len,
-"%sThe capture session could not be initiated!%s\n"
-"\n"
-"(%s)\n"
+"The capture session could not be initiated (%s).",
+ open_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
"\n"
"Please check that \"%s\" is the proper interface.\n"
"\n"
@@ -555,7 +565,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
" %shttp://wiki.ethereal.com/CaptureSetup%s\n"
"\n"
"64-bit Windows:\n"
-"WinPcap does not support 64-bit Windows, you will have to use some other\n"
+"WinPcap does not support 64-bit Windows; you will have to use some other\n"
"tool to capture traffic, such as netcap.\n"
"For netcap details see: http://support.microsoft.com/?id=310875\n"
"\n"
@@ -565,10 +575,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
"Server 2003.\n"
"WinPcap 3.1 has support for it on Windows 2000 / XP / Server 2003, but has no\n"
"support for it on Windows NT 4.0 or Windows Vista (Beta 1).",
- simple_dialog_primary_start(), simple_dialog_primary_end(),
- open_err_str,
- capture_opts->iface,
- simple_dialog_primary_start(), simple_dialog_primary_end());
+ open_err_str, capture_opts->iface);
return FALSE;
#else
/* try to open iface as a pipe */
@@ -599,10 +606,10 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
else
libpcap_warn = "";
g_snprintf(errmsg, errmsg_len,
- "The capture session could not be initiated (%s).\n"
- "Please check to make sure you have sufficient permissions, and that\n"
- "you have the proper interface or pipe specified.%s", open_err_str,
- libpcap_warn);
+ "The capture session could not be initiated (%s).", open_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
+"Please check to make sure you have sufficient permissions, and that\n"
+"you have the proper interface or pipe specified.%s", libpcap_warn);
}
/*
* Else pipe (or file) does exist and cap_pipe_open_live() has
@@ -631,7 +638,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
returned a warning; print it, but keep capturing. */
if (open_err_str[0] != '\0') {
sync_msg_str = g_strdup_printf("%s.", open_err_str);
- sync_pipe_errmsg_to_parent(sync_msg_str);
+ sync_pipe_errmsg_to_parent(sync_msg_str, "");
g_free(sync_msg_str);
}
@@ -666,7 +673,7 @@ static void capture_loop_close_input(loop_data *ld) {
/* init the capture filter */
-gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len) {
+initfilter_status_t capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter) {
bpf_u_int32 netnum, netmask;
gchar lookup_net_err_str[PCAP_ERRBUF_SIZE];
struct bpf_program fcode;
@@ -692,56 +699,23 @@ gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const
netmask = 0;
}
if (pcap_compile(pcap_h, &fcode, cfilter, 1, netmask) < 0) {
- dfilter_t *rfcode = NULL;
- gchar *safe_cfilter = simple_dialog_format_message(cfilter);
- gchar *safe_cfilter_error_msg = simple_dialog_format_message(
- pcap_geterr(pcap_h));
-
- /* filter string invalid, did the user tried a display filter? */
-#ifndef DUMPCAP
- if (dfilter_compile(cfilter, &rfcode) && rfcode != NULL) {
- g_snprintf(errmsg, errmsg_len,
- "%sInvalid capture filter: \"%s\"!%s\n"
- "\n"
- "That string looks like a valid display filter; however, it isn't a valid\n"
- "capture filter (%s).\n"
- "\n"
- "Note that display filters and capture filters don't have the same syntax,\n"
- "so you can't use most display filter expressions as capture filters.\n"
- "\n"
- "See the User's Guide for a description of the capture filter syntax.",
- simple_dialog_primary_start(), safe_cfilter,
- simple_dialog_primary_end(), safe_cfilter_error_msg);
- dfilter_free(rfcode);
- } else
-#endif
- {
- g_snprintf(errmsg, errmsg_len,
- "%sInvalid capture filter: \"%s\"!%s\n"
- "\n"
- "That string isn't a valid capture filter (%s).\n"
- "See the User's Guide for a description of the capture filter syntax.",
- simple_dialog_primary_start(), safe_cfilter,
- simple_dialog_primary_end(), safe_cfilter_error_msg);
- }
- g_free(safe_cfilter_error_msg);
- g_free(safe_cfilter);
- return FALSE;
+ /* Treat this specially - our caller might try to compile this
+ as a display filter and, if that succeeds, warn the user that
+ the display and capture filter syntaxes are different. */
+ return INITFILTER_BAD_FILTER;
}
if (pcap_setfilter(pcap_h, &fcode) < 0) {
- g_snprintf(errmsg, errmsg_len, "Can't install filter (%s).",
- pcap_geterr(pcap_h));
#ifdef HAVE_PCAP_FREECODE
pcap_freecode(&fcode);
#endif
- return FALSE;
+ return INITFILTER_OTHER_ERROR;
}
#ifdef HAVE_PCAP_FREECODE
pcap_freecode(&fcode);
#endif
}
- return TRUE;
+ return INITFILTER_NO_ERROR;
}
@@ -850,7 +824,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
if (sel_ret < 0 && errno != EINTR) {
g_snprintf(errmsg, errmsg_len,
"Unexpected error from select: %s", strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
ld->go = FALSE;
}
} else {
@@ -930,7 +904,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
if (sel_ret < 0 && errno != EINTR) {
g_snprintf(errmsg, errmsg_len,
"Unexpected error from select: %s", strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
ld->go = FALSE;
}
}
@@ -1106,7 +1080,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
guint32 autostop_files = 0;
gboolean write_ok;
gboolean close_ok;
+ gboolean cfilter_error = FALSE;
char errmsg[4096+1];
+ char secondary_errmsg[4096+1];
int save_file_fd;
@@ -1147,21 +1123,38 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* open the output file (temporary/specified name/ringbuffer) */
if (!capture_loop_open_output(capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
/* open the "input file" from network interface or capture pipe */
- if (!capture_loop_open_input(capture_opts, &ld, errmsg, sizeof(errmsg))) {
+ if (!capture_loop_open_input(capture_opts, &ld, errmsg, sizeof(errmsg),
+ secondary_errmsg, sizeof(secondary_errmsg))) {
goto error;
}
/* init the input filter from the network interface (capture pipe will do nothing) */
- if (!capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter, errmsg, sizeof(errmsg))) {
+ switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter)) {
+
+ case INITFILTER_NO_ERROR:
+ break;
+
+ case INITFILTER_BAD_FILTER:
+ cfilter_error = TRUE;
+ g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+ *secondary_errmsg = '\0';
+ goto error;
+
+ case INITFILTER_OTHER_ERROR:
+ g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+ pcap_geterr(ld.pcap_h));
+ g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
goto error;
}
/* set up to write to the already-opened capture output file/files */
if (!capture_loop_init_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
@@ -1344,11 +1337,11 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (ld.pcap_err) {
g_snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
pcap_geterr(ld.pcap_h));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
}
#ifndef _WIN32
else if (ld.from_cap_pipe && ld.cap_pipe_err == PIPERR)
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, "");
#endif
/* did we had an error while capturing? */
@@ -1357,7 +1350,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} else {
capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file, ld.err,
FALSE);
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
write_ok = FALSE;
}
@@ -1376,7 +1369,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (!close_ok && write_ok) {
capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file, err_close,
TRUE);
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, "");
}
/*
@@ -1401,7 +1394,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
g_snprintf(errmsg, sizeof(errmsg),
"Can't get packet-drop statistics: %s",
pcap_geterr(ld.pcap_h));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
}
}
@@ -1418,7 +1411,7 @@ error:
/* cleanup ringbuffer */
ringbuf_error_cleanup();
} else {
- /* We can't use the save file, and we have no wtap_dump stream
+ /* We can't use the save file, and we have no FILE * for the stream
to close in order to close it, so close the FD directly. */
eth_close(save_file_fd);
@@ -1428,7 +1421,10 @@ error:
g_free(capture_opts->save_file);
}
capture_opts->save_file = NULL;
- sync_pipe_errmsg_to_parent(errmsg);
+ if (cfilter_error)
+ sync_pipe_cfilter_error_to_parent(capture_opts->cfilter, errmsg);
+ else
+ sync_pipe_errmsg_to_parent(errmsg, secondary_errmsg);
/* close the input file (pcap or cap_pipe) */
capture_loop_close_input(&ld);
diff --git a/capture_loop.h b/capture_loop.h
index bfdf734388..73aafdab60 100644
--- a/capture_loop.h
+++ b/capture_loop.h
@@ -129,8 +129,14 @@ typedef struct _loop_data {
/** init the capture filter */
-extern gboolean
-capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len);
+typedef enum {
+ INITFILTER_NO_ERROR,
+ INITFILTER_BAD_FILTER,
+ INITFILTER_OTHER_ERROR
+} initfilter_status_t;
+
+extern initfilter_status_t
+capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter);
/** Take care of byte order in the libpcap headers read from pipes. */
extern void
@@ -148,7 +154,9 @@ cap_pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
#endif
extern gboolean
-capture_loop_open_input(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len);
+capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len);
extern gboolean
capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len);
diff --git a/capture_sync.c b/capture_sync.c
index 2a34f79375..45dc5ff7d4 100644
--- a/capture_sync.c
+++ b/capture_sync.c
@@ -120,25 +120,42 @@ static void sync_pipe_wait_for_child(capture_options *capture_opts);
#define SP_MAX_MSG_LEN 4096
- /* write a message to the recipient pipe in the standard format
+/* write a message to the recipient pipe in the standard format
(3 digit message length (excluding length and indicator field),
- 1 byte message indicator and the rest is the message) */
+ 1 byte message indicator and the rest is the message).
+ If msg is NULL, the message has only a length and indicator.
+ Otherwise, if secondary_msg isn't NULL, send both msg and
+ secondary_msg as null-terminated strings, otherwise just send
+ msg as a null-terminated string and follow it with an empty string. */
static void
-pipe_write_block(int pipe, char indicator, int len, const char *msg)
+pipe_write_block(int pipe, char indicator, const char *msg,
+ const char *secondary_msg)
{
guchar header[3+1]; /* indicator + 3-byte len */
int ret;
+ size_t len, secondary_len, total_len;
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d enter", pipe);
+ len = 0;
+ secondary_len = 0;
+ total_len = 0;
+ if(msg != NULL) {
+ len = strlen(msg) + 1; /* include the terminating '\0' */
+ total_len = len;
+ if(secondary_msg == NULL)
+ secondary_msg = ""; /* default to an empty string */
+ secondary_len = strlen(secondary_msg) + 1;
+ total_len += secondary_len;
+ }
g_assert(indicator < '0' || indicator > '9');
- g_assert(len <= SP_MAX_MSG_LEN);
+ g_assert(total_len <= SP_MAX_MSG_LEN);
/* write header (indicator + 3-byte len) */
header[0] = indicator;
- header[1] = (len >> 16) & 0xFF;
- header[2] = (len >> 8) & 0xFF;
- header[3] = (len >> 0) & 0xFF;
+ header[1] = (total_len >> 16) & 0xFF;
+ header[2] = (total_len >> 8) & 0xFF;
+ header[3] = (total_len >> 0) & 0xFF;
ret = write(pipe, header, sizeof header);
if(ret == -1) {
@@ -150,14 +167,21 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
/* write value (if we have one) */
if(len) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "write %d indicator: %c value len: %u msg: %s", pipe, indicator,
- len, msg);
+ "write %d indicator: %c value len: %lu msg: \"%s\" secondary len: %lu secondary msg: \"%s\"", pipe, indicator,
+ (unsigned long)len, msg, (unsigned long)secondary_len,
+ secondary_msg);
ret = write(pipe, msg, len);
if(ret == -1) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
"write %d value: error %s", pipe, strerror(errno));
return;
}
+ ret = write(pipe, msg, secondary_len);
+ if(ret == -1) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "write %d value: error %s", pipe, strerror(errno));
+ return;
+ }
} else {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
"write %d indicator: %c no value", pipe, indicator);
@@ -169,11 +193,12 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
#ifndef _WIN32
void
-sync_pipe_errmsg_to_parent(const char *errmsg)
+sync_pipe_errmsg_to_parent(const char *error_msg,
+ const char *secondary_error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", error_msg);
- pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
+ pipe_write_block(1, SP_ERROR_MSG, error_msg, secondary_error_msg);
}
#endif
@@ -185,7 +210,7 @@ signal_pipe_capquit_to_child(capture_options *capture_opts)
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
- pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, 0, NULL);
+ pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, NULL, NULL);
}
#endif
@@ -602,7 +627,7 @@ sync_pipe_start(capture_options *capture_opts) {
execv(exename, argv);
g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
exename, strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, NULL);
/* Exit with "_exit()", so that we don't close the connection
to the X server (and cause stuff buffered up by our parent but
@@ -694,21 +719,21 @@ sync_pipe_input_cb(gint source, gpointer user_data)
switch(indicator) {
case SP_FILE:
- if(!capture_input_new_file(capture_opts, buffer)) {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
-
- /* We weren't able to open the new capture file; user has been
- alerted. Close the sync pipe. */
- eth_close(source);
-
- /* the child has send us a filename which we couldn't open.
- this probably means, the child is creating files faster than we can handle it.
- this should only be the case for very fast file switches
- we can't do much more than telling the child to stop
- (this is the "emergency brake" if user e.g. wants to switch files every second) */
- sync_pipe_stop(capture_opts);
- }
- break;
+ if(!capture_input_new_file(capture_opts, buffer)) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
+
+ /* We weren't able to open the new capture file; user has been
+ alerted. Close the sync pipe. */
+ eth_close(source);
+
+ /* the child has send us a filename which we couldn't open.
+ this probably means, the child is creating files faster than we can handle it.
+ this should only be the case for very fast file switches
+ we can't do much more than telling the child to stop
+ (this is the "emergency brake" if user e.g. wants to switch files every second) */
+ sync_pipe_stop(capture_opts);
+ }
+ break;
case SP_PACKET_COUNT:
nread = atoi(buffer);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", nread);
@@ -718,11 +743,15 @@ sync_pipe_input_cb(gint source, gpointer user_data)
capture_input_error_message(capture_opts, buffer);
/* the capture child will close the sync_pipe, nothing to do for now */
break;
+ case SP_BAD_FILTER:
+ capture_input_cfilter_error_message(capture_opts, buffer);
+ /* the capture child will close the sync_pipe, nothing to do for now */
+ break;
case SP_DROPS:
capture_input_drops(capture_opts, atoi(buffer));
break;
default:
- g_assert_not_reached();
+ g_assert_not_reached();
}
return TRUE;
diff --git a/capture_sync.h b/capture_sync.h
index 2e08588839..aecb8f00d1 100644
--- a/capture_sync.h
+++ b/capture_sync.h
@@ -44,6 +44,7 @@
*/
#define SP_FILE 'F' /* the name of the recently opened file */
#define SP_ERROR_MSG 'E' /* error message */
+#define SP_BAD_FILTER 'B' /* error message for bad capture filter */
#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */
#define SP_DROPS 'D' /* count of packets dropped in capture */
/*
@@ -89,9 +90,14 @@ sync_pipe_packet_count_to_parent(int packet_count);
extern void
sync_pipe_drops_to_parent(int drops);
+/** the child encountered an error with a capture filter, notify the parent */
+extern void
+sync_pipe_cfilter_error_to_parent(const char *cfilter, const char *errmsg);
+
/** the child encountered an error, notify the parent */
extern void
-sync_pipe_errmsg_to_parent(const char *errmsg);
+sync_pipe_errmsg_to_parent(const char *error_msg,
+ const char *secondary_error_msg);
/** does the parent signalled the child to stop */
diff --git a/dumpcap.c b/dumpcap.c
index a5222655af..268f32615e 100644
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -512,25 +512,42 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
#define SP_MAX_MSG_LEN 4096
- /* write a message to the recipient pipe in the standard format
+/* write a message to the recipient pipe in the standard format
(3 digit message length (excluding length and indicator field),
- 1 byte message indicator and the rest is the message) */
+ 1 byte message indicator and the rest is the message).
+ If msg is NULL, the message has only a length and indicator.
+ Otherwise, if secondary_msg isn't NULL, send both msg and
+ secondary_msg as null-terminated strings, otherwise just send
+ msg as a null-terminated string and follow it with an empty string. */
static void
-pipe_write_block(int pipe, char indicator, int len, const char *msg)
+pipe_write_block(int pipe, char indicator, const char *msg,
+ const char *secondary_msg)
{
guchar header[3+1]; /* indicator + 3-byte len */
int ret;
+ size_t len, secondary_len, total_len;
/*g_warning("write %d enter", pipe);*/
+ len = 0;
+ secondary_len = 0;
+ total_len = 0;
+ if(msg != NULL) {
+ len = strlen(msg) + 1; /* include the terminating '\0' */
+ total_len = len;
+ if(secondary_msg == NULL)
+ secondary_msg = ""; /* default to an empty string */
+ secondary_len = strlen(secondary_msg) + 1;
+ total_len += secondary_len;
+ }
g_assert(indicator < '0' || indicator > '9');
- g_assert(len <= SP_MAX_MSG_LEN);
+ g_assert(total_len <= SP_MAX_MSG_LEN);
/* write header (indicator + 3-byte len) */
header[0] = indicator;
- header[1] = (len >> 16) & 0xFF;
- header[2] = (len >> 8) & 0xFF;
- header[3] = (len >> 0) & 0xFF;
+ header[1] = (total_len >> 16) & 0xFF;
+ header[2] = (total_len >> 8) & 0xFF;
+ header[3] = (total_len >> 0) & 0xFF;
ret = write(pipe, header, sizeof header);
if(ret == -1) {
@@ -544,6 +561,10 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
if(ret == -1) {
return;
}
+ ret = write(pipe, secondary_msg, secondary_len);
+ if(ret == -1) {
+ return;
+ }
} else {
/*g_warning("write %d indicator: %c no value", pipe, indicator);*/
}
@@ -562,7 +583,7 @@ sync_pipe_packet_count_to_parent(int packet_count)
if(capture_child) {
g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
- pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
+ pipe_write_block(1, SP_PACKET_COUNT, tmp, NULL);
} else {
count += packet_count;
fprintf(stderr, "\rPackets: %u ", count);
@@ -579,18 +600,33 @@ sync_pipe_filename_to_parent(const char *filename)
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "File: %s", filename);
if(capture_child) {
- pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
+ pipe_write_block(1, SP_FILE, filename, NULL);
+ }
+}
+
+
+void
+sync_pipe_cfilter_error_to_parent(const char *cfilter _U_, const char *errmsg)
+{
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg);
+
+ if (capture_child) {
+ pipe_write_block(1, SP_BAD_FILTER, errmsg, NULL);
}
}
void
-sync_pipe_errmsg_to_parent(const char *errmsg)
+sync_pipe_errmsg_to_parent(const char *error_msg, const char *secondary_error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Error: %s", errmsg);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Error: %s", error_msg);
+ if (secondary_error_msg != NULL)
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Secondary error: %s",
+ secondary_error_msg);
if(capture_child) {
- pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
+ pipe_write_block(1, SP_ERROR_MSG, error_msg, secondary_error_msg);
}
}
@@ -604,7 +640,7 @@ sync_pipe_drops_to_parent(int drops)
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Packets dropped: %s", tmp);
if(capture_child) {
- pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
+ pipe_write_block(1, SP_DROPS, tmp, NULL);
}
}
@@ -648,43 +684,7 @@ signal_pipe_check_running(void)
/****************************************************************************************************************/
-/* simple_dialog stubs */
-
-
-char *simple_dialog_primary_start(void)
-{
- return "";
-}
-
-char *simple_dialog_primary_end(void)
-{
- return "";
-}
-
-char *
-simple_dialog_format_message(const char *msg)
-{
- char *str;
-
- if (msg) {
-#if GTK_MAJOR_VERSION < 2
- str = g_strdup(msg);
-#else
- str = xml_escape(msg);
-#endif
- } else {
- str = NULL;
- }
- return str;
-}
-
-
-/****************************************************************************************************************/
/* Stub functions */
const char *netsnmp_get_version(void) { return ""; }
-
-gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { (void)text; (void)dfp; return FALSE; }
-
-void dfilter_free(dfilter_t *df) { (void)df; }
diff --git a/tethereal.c b/tethereal.c
index b0775b0625..176607996b 100644
--- a/tethereal.c
+++ b/tethereal.c
@@ -136,6 +136,12 @@ static guint32 cum_bytes = 0;
static print_format_e print_format = PR_FMT_TEXT;
static print_stream_t *print_stream;
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+ "Please report this to the Ethereal developers";
+
#ifdef HAVE_LIBPCAP
/*
* TRUE if we're to print packet counts to keep track of captured packets.
@@ -1499,7 +1505,6 @@ capture(void)
int volatile volatile_err = 0;
int volatile inpkts = 0;
int pcap_cnt;
- char errmsg[1024+1];
condition *volatile cnd_autostop_size = NULL;
condition *volatile cnd_autostop_duration = NULL;
char *descr;
@@ -1510,6 +1515,9 @@ capture(void)
struct pcap_stat stats;
gboolean write_ok;
gboolean close_ok;
+ gboolean cfilter_error = FALSE;
+ char errmsg[1024+1];
+ char secondary_errmsg[4096+1];
int save_file_fd;
/* Initialize all data structures used for dissection. */
@@ -1521,8 +1529,8 @@ capture(void)
/* open the "input file" from network interface or capture pipe */
- if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg)))
- {
+ if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg),
+ secondary_errmsg, sizeof(secondary_errmsg))) {
goto error;
}
@@ -1542,20 +1550,33 @@ capture(void)
/* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */
if (!capture_loop_open_output(&capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
/* init the input filter from the network interface (capture pipe will do nothing) */
- if(!capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe,
- capture_opts.iface, capture_opts.cfilter, errmsg, sizeof errmsg))
- {
- goto error;
+ switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts.iface, capture_opts.cfilter)) {
+
+ case INITFILTER_NO_ERROR:
+ break;
+
+ case INITFILTER_BAD_FILTER:
+ cfilter_error = TRUE;
+ g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+ *secondary_errmsg = '\0';
+ goto error;
+
+ case INITFILTER_OTHER_ERROR:
+ g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+ pcap_geterr(ld.pcap_h));
+ g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
+ goto error;
}
/* set up to write to the already-opened capture output file/files */
- if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg))
- {
- goto error;
+ if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) {
+ *secondary_errmsg = '\0';
+ goto error;
}
ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype);
@@ -1793,7 +1814,36 @@ error:
}
g_free(capture_opts.save_file);
capture_opts.save_file = NULL;
- cmdarg_err("%s", errmsg);
+ if (cfilter_error) {
+ dfilter_t *rfcode = NULL;
+ if (dfilter_compile(capture_opts.cfilter, &rfcode) && rfcode != NULL) {
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string looks like a valid display filter; however, it isn't a valid\n"
+ "capture filter (%s).\n"
+ "\n"
+ "Note that display filters and capture filters don't have the same syntax,\n"
+ "so you can't use most display filter expressions as capture filters.\n"
+ "\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ capture_opts.cfilter, errmsg);
+ dfilter_free(rfcode);
+ } else {
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ capture_opts.cfilter, errmsg);
+ }
+ } else {
+ cmdarg_err("%s", errmsg);
+ if (*secondary_errmsg != '\0') {
+ fprintf(stderr, "\n");
+ cmdarg_err_cont("%s", secondary_errmsg);
+ }
+ }
#ifndef _WIN32
if (ld.from_cap_pipe) {
if (ld.cap_pipe_fd >= 0)
@@ -2971,6 +3021,19 @@ sync_pipe_drops_to_parent(int drops)
g_assert(0);
}
+/** the child encountered an error with a capture filter, notify the parent */
+void
+sync_pipe_cfilter_error_to_parent(const char *cfilter, const char *errmsg)
+{
+
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ cfilter, errmsg);
+}
+
/** the child encountered an error, notify the parent */
void
sync_pipe_errmsg_to_parent(const char *errmsg)
@@ -2996,44 +3059,3 @@ signal_pipe_check_running(void)
#endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */
-
-
-/****************************************************************************************************************/
-/* simple_dialog "dummies", needed for capture_loop.c */
-
-
-#ifdef HAVE_LIBPCAP
-
-char *simple_dialog_primary_start(void)
-{
- return "";
-}
-
-char *simple_dialog_primary_end(void)
-{
- return "";
-}
-
-
-/* XXX - do we need to convert the string for the console? */
-char *
-simple_dialog_format_message(const char *msg)
-{
- char *str;
-
-
- if (msg) {
-#if GTK_MAJOR_VERSION < 2
- str = g_strdup(msg);
-#else
- str = xml_escape(msg);
-#endif
- } else {
- str = NULL;
- }
- return str;
-}
-
-#endif /* HAVE_LIBPCAP */
-
-