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
This commit is contained in:
Guy Harris 2006-03-05 03:14:16 +00:00
parent fd39d0ebed
commit cbe69401cc
8 changed files with 356 additions and 219 deletions

View File

@ -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 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.
*/
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 its side of the pipe, do the required cleanup */
void
capture_input_closed(capture_options *capture_opts)
{

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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");
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);
/* 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;
/* 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;

View File

@ -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 */

View File

@ -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);
}
}
@ -647,44 +683,8 @@ signal_pipe_check_running(void)
#endif
/****************************************************************************************************************/
/* 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; }

View File

@ -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 */