Add a compile-time option to use a separate thread for reading from

pipes. Enable this by default on Windows. Remove code that tried to
use WaitForSingleObject on a pipe (which Windows doesn't support). Use
native file handles and system calls on Windows (which fixes a problem
with partial reads I ran into during testing).

This should fix bug 1759.

svn path=/trunk/; revision=29574
This commit is contained in:
Gerald Combs 2009-08-26 23:16:37 +00:00
parent 228bc22aa9
commit 4c7f40f3f5
4 changed files with 350 additions and 140 deletions

View File

@ -159,6 +159,7 @@ dumpcap_LIBS= wiretap\wiretap-$(WTAP_VERSION).lib \
wsock32.lib user32.lib \
wsutil\libwsutil.lib \
$(GLIB_LIBS) \
$(GTHREAD_LIBS) \
$(GNUTLS_LIBS)
dftest_LIBS= wiretap\wiretap-$(WTAP_VERSION).lib \
@ -1043,6 +1044,7 @@ install-all: install-generated-files
xcopy $(GLIB_DIR)\bin\libglib-2.0-0.dll $(INSTALL_DIR) /d
xcopy $(GLIB_DIR)\bin\libgmodule-2.0-0.dll $(INSTALL_DIR) /d
xcopy $(GLIB_DIR)\bin\libgobject-2.0-0.dll $(INSTALL_DIR) /d
xcopy $(GLIB_DIR)\bin\libgthread-2.0-0.dll $(INSTALL_DIR) /d
!IFDEF ICONV_DIR
xcopy $(ICONV_DIR)\bin\iconv.dll $(INSTALL_DIR) /d
!ENDIF

View File

@ -907,6 +907,7 @@ GCC_GLIB_CFLAGS=-I$(GLIB_DIR)\include\glib-$(GLIB_VERSION) \
GLIB_LIBS=$(GLIB_DIR)\lib\glib-$(GLIB_VERSION).lib \
$(GLIB_DIR)\lib\gmodule-$(GLIB_VERSION).lib \
$(GLIB_DIR)\lib\gobject-$(GLIB_VERSION).lib
GTHREAD_LIBS=$(GLIB_DIR)\lib\gthread-$(GLIB_VERSION).lib \
# GTK+
GTK_CFLAGS=$(GLIB_CFLAGS) /I$(GTK_DIR)\include\gtk-2.0 \

486
dumpcap.c
View File

@ -76,9 +76,6 @@
#ifdef _WIN32
#include "capture-wpcap.h"
#endif
#ifdef _WIN32
#include <wsutil/unicode-utils.h>
#endif
@ -111,10 +108,20 @@ FILE *debug_log; /* for logging debug messages to */
/* is defined */
#endif
#ifdef _WIN32
#define USE_THREADS
#endif
static gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
#ifdef _WIN32
static gchar *sig_pipe_name = NULL;
static HANDLE sig_pipe_handle = NULL;
static gboolean signal_pipe_check_running(void);
#endif
#ifdef USE_THREADS
static GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q;
static GMutex *cap_pipe_read_mtx;
#endif
/** Stop a low-level capture (stops the capture child). */
@ -197,11 +204,18 @@ typedef struct _loop_data {
gboolean from_cap_pipe; /* TRUE if we are capturing data from a capture pipe */
struct pcap_hdr cap_pipe_hdr; /* Pcap header when capturing from a pipe */
struct pcaprec_modified_hdr cap_pipe_rechdr; /* Pcap record header when capturing from a pipe */
#ifdef _WIN32
HANDLE cap_pipe_h; /* The handle of the capture pipe */
#else
int cap_pipe_fd; /* the file descriptor of the capture pipe */
#endif
gboolean cap_pipe_modified; /* TRUE if data in the pipe uses modified pcap headers */
gboolean cap_pipe_byte_swapped; /* TRUE if data in the pipe is byte swapped */
unsigned int cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */
unsigned int cap_pipe_bytes_read; /* Used by cap_pipe_dispatch */
#ifdef USE_THREADS
char * cap_pipe_buf; /* Pointer to the data buffer we read into */
#endif /* USE_THREADS */
int cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */
int cap_pipe_bytes_read; /* Used by cap_pipe_dispatch */
enum {
STATE_EXPECT_REC_HDR,
STATE_READ_REC_HDR,
@ -237,6 +251,10 @@ static loop_data global_ld;
* Timeout, in milliseconds, for reads from the stream of captured packets.
*/
#define CAP_READ_TIMEOUT 250
/*
* Timeout, in microseconds, for threaded reads from a pipe.
*/
#define THREAD_READ_TIMEOUT 100
static char *cap_pipe_err_str;
static void
@ -264,10 +282,6 @@ static void report_packet_drops(guint32 drops);
static void report_capture_error(const char *error_msg, const char *secondary_error_msg);
static void report_cfilter_error(const char *cfilter, const char *errmsg);
#ifdef _WIN32
static gboolean signal_pipe_check_running(void);
#endif
static void
print_usage(gboolean print_ver) {
@ -471,7 +485,8 @@ print_statistics_loop(gboolean machine_readable)
}
}
#ifdef _WIN32
Sleep(1 * 1000);
if (! global_ld.from_cap_pipe)
Sleep(1 * 1000);
#else
sleep(1);
#endif
@ -674,18 +689,100 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr
}
}
#ifdef USE_THREADS
/*
* Thread function that reads from a pipe and pushes the data
* to the main application thread.
*/
/*
* XXX Right now we use async queues for basic signaling. The main thread
* sets cap_pipe_buf and cap_bytes_to_read, then pushes an item onto
* cap_pipe_pending_q which triggers a read in the cap_pipe_read thread.
* Iff the read is successful cap_pipe_read pushes an item onto
* cap_pipe_done_q, otherwise an error is signaled. No data is passed in
* the queues themselves (yet).
*
* We might want to move some of the cap_pipe_dispatch logic here so that
* we can let cap_pipe_read run independently, queuing up multiple reads
* for the main thread (and possibly get rid of cap_pipe_read_mtx).
*/
static void *cap_pipe_read(void *ld_ptr) {
loop_data *ld = (loop_data *)ld_ptr;
int bytes_read;
#ifdef _WIN32
BOOL res;
DWORD b, last_err;
#else /* _WIN32 */
int b;
#endif /* _WIN32 */
while (ld->cap_pipe_err == PIPOK) {
g_async_queue_pop(cap_pipe_pending_q); /* Wait for our cue (ahem) from the main thread */
g_mutex_lock(cap_pipe_read_mtx);
bytes_read = 0;
while (bytes_read < (int) ld->cap_pipe_bytes_to_read) {
#ifdef _WIN32
/* If we try to use read() on a named pipe on Windows with partial
* data it appears to return EOF.
*/
res = ReadFile(ld->cap_pipe_h, ld->cap_pipe_buf+bytes_read,
ld->cap_pipe_bytes_to_read - bytes_read,
&b, NULL);
bytes_read += b;
if (!res) {
last_err = GetLastError();
if (last_err == ERROR_MORE_DATA) {
continue;
} else if (last_err == ERROR_HANDLE_EOF || last_err == ERROR_BROKEN_PIPE || last_err == ERROR_PIPE_NOT_CONNECTED) {
ld->cap_pipe_err = PIPEOF;
bytes_read = 0;
break;
}
ld->cap_pipe_err = PIPERR;
bytes_read = -1;
break;
} else if (b == 0 && ld->cap_pipe_bytes_to_read > 0) {
ld->cap_pipe_err = PIPEOF;
bytes_read = 0;
break;
}
#else /* _WIN32 */
b = read(ld->cap_pipe_fd, ld->cap_pipe_buf+bytes_read,
ld->cap_pipe_bytes_to_read - bytes_read);
if (b <= 0) {
if (b == 0) {
ld->cap_pipe_err = PIPEOF;
bytes_read = 0;
break;
} else {
ld->cap_pipe_err = PIPERR;
bytes_read = -1;
break;
}
} else {
bytes_read += b;
}
#endif /*_WIN32 */
}
ld->cap_pipe_bytes_read = bytes_read;
if (ld->cap_pipe_bytes_read >= ld->cap_pipe_bytes_to_read) {
g_async_queue_push(cap_pipe_done_q, ld->cap_pipe_buf); /* Any non-NULL value will do */
}
g_mutex_unlock(cap_pipe_read_mtx);
}
return NULL;
}
#endif /* USE_THREADS */
/* Provide select() functionality for a single file descriptor
* on both UNIX/POSIX and Windows.
*
* The Windows version calls WaitForSingleObject instead of
* select().
* on UNIX/POSIX. Windows uses cap_pipe_read via a thread.
*
* Returns the same values as select. If an error is returned,
* the string cap_pipe_err_str should be used instead of errno.
*/
static int
cap_pipe_select(int pipe_fd) {
#ifndef _WIN32
fd_set rfds;
struct timeval timeout, *pto;
int sel_ret;
@ -704,44 +801,6 @@ cap_pipe_select(int pipe_fd) {
cap_pipe_err_str = strerror(errno);
return sel_ret;
}
#else
/* XXX - Should we just use file handles exclusively under Windows?
* Otherwise we have to convert between file handles and file descriptors
* here and when we open a named pipe.
*/
HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
wchar_t *err_str;
DWORD wait_ret;
if (hPipe == INVALID_HANDLE_VALUE) {
cap_pipe_err_str = "Could not open standard input";
return -1;
}
cap_pipe_err_str = "Unknown error";
wait_ret = WaitForSingleObject(hPipe, CAP_READ_TIMEOUT);
switch (wait_ret) {
/* XXX - This probably isn't correct */
case WAIT_ABANDONED:
errno = EINTR;
return -1;
case WAIT_OBJECT_0:
return 1;
case WAIT_TIMEOUT:
return 0;
case WAIT_FAILED:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
cap_pipe_err_str = utf_16to8(err_str);
LocalFree(err_str);
return -1;
default:
g_assert_not_reached();
return -1;
}
}
#endif
/* Mimic pcap_open_live() for pipe captures
@ -749,38 +808,39 @@ cap_pipe_select(int pipe_fd) {
* header.
* N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
* because we can't seek on pipes (see wiretap/libpcap.c for details) */
static int
static void
cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
char *errmsg, int errmsgl)
{
#ifndef _WIN32
struct stat pipe_stat;
#else
int sel_ret;
int b;
unsigned int bytes_read;
int fd;
#else /* _WIN32 */
#if 1
char *pncopy, *pos;
wchar_t *err_str;
#endif
HANDLE hPipe = NULL;
#endif
int sel_ret;
int fd;
int b;
guint32 magic;
unsigned int bytes_read;
#ifndef _WIN32
ld->cap_pipe_fd = -1;
#else
ld->cap_pipe_h = NULL;
#endif
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
/*
* XXX (T)Wireshark blocks until we return
*/
if (strcmp(pipename, "-") == 0) {
#ifndef _WIN32
fd = 0; /* read from stdin */
#ifdef _WIN32
/*
* This is needed to set the stdin pipe into binary mode, otherwise
* CR/LF are mangled...
*/
_setmode(0, _O_BINARY);
#else /* _WIN32 */
ld->cap_pipe_h = GetStdHandle(STD_INPUT_HANDLE);
#endif /* _WIN32 */
} else {
#ifndef _WIN32
@ -793,7 +853,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
"due to error on pipe: %s", strerror(errno));
ld->cap_pipe_err = PIPERR;
}
return -1;
return;
}
if (! S_ISFIFO(pipe_stat.st_mode)) {
if (S_ISCHR(pipe_stat.st_mode)) {
@ -809,7 +869,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
"\"%s\" is neither an interface nor a pipe", pipename);
ld->cap_pipe_err = PIPERR;
}
return -1;
return;
}
fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
if (fd == -1) {
@ -817,7 +877,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
"The capture session could not be initiated "
"due to error on pipe open: %s", strerror(errno));
ld->cap_pipe_err = PIPERR;
return -1;
return;
}
#else /* _WIN32 */
#define PIPE_STR "\\pipe\\"
@ -838,15 +898,15 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
"The capture session could not be initiated because\n"
"\"%s\" is neither an interface nor a pipe", pipename);
ld->cap_pipe_err = PIPNEXIST;
return -1;
return;
}
/* Wait for the pipe to appear */
while (1) {
hPipe = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
ld->cap_pipe_h = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hPipe != INVALID_HANDLE_VALUE)
if (ld->cap_pipe_h != INVALID_HANDLE_VALUE)
break;
if (GetLastError() != ERROR_PIPE_BUSY) {
@ -855,10 +915,10 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
g_snprintf(errmsg, errmsgl,
"The capture session on \"%s\" could not be initiated "
"due to error on pipe open: pipe busy: %s (error %d)",
pipename, utf_16to8(err_str), GetLastError());
pipename, utf_16to8(err_str), GetLastError());
LocalFree(err_str);
ld->cap_pipe_err = PIPERR;
return -1;
return;
}
if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) {
@ -867,26 +927,19 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
g_snprintf(errmsg, errmsgl,
"The capture session could not be initiated "
"due to error on named pipe open: %s (error %d)",
utf_16to8(err_str), GetLastError());
utf_16to8(err_str), GetLastError());
LocalFree(err_str);
ld->cap_pipe_err = PIPERR;
return -1;
return;
}
}
fd = _open_osfhandle((long) hPipe, _O_RDONLY);
if (fd == -1) {
g_snprintf(errmsg, errmsgl,
"The capture session could not be initiated "
"due to error on pipe open: %s", strerror(errno));
ld->cap_pipe_err = PIPERR;
return -1;
}
#endif /* _WIN32 */
}
ld->from_cap_pipe = TRUE;
#ifndef USE_THREADS
/* read the pcap header */
bytes_read = 0;
while (bytes_read < sizeof magic) {
@ -899,15 +952,33 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
if (b <= 0) {
if (b == 0)
g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open");
else
g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s",
strerror(errno));
goto error;
}
bytes_read += b;
}
}
#else /* USE_THREADS */
g_thread_create(&cap_pipe_read, ld, FALSE, NULL);
ld->cap_pipe_buf = (char *) &magic;
ld->cap_pipe_bytes_read = 0;
ld->cap_pipe_bytes_to_read = sizeof(magic);
/* We don't have to worry about cap_pipe_read_mtx here */
g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
g_async_queue_pop(cap_pipe_done_q);
if (ld->cap_pipe_bytes_read <= 0) {
if (ld->cap_pipe_bytes_read == 0)
g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open");
else
g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s",
strerror(errno));
goto error;
}
#endif /* USE_THREADS */
switch (magic) {
case PCAP_MAGIC:
@ -942,6 +1013,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
goto error;
}
#ifndef USE_THREADS
/* Read the rest of the header */
bytes_read = 0;
while (bytes_read < sizeof(struct pcap_hdr)) {
@ -955,15 +1027,30 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
sizeof(struct pcap_hdr) - bytes_read);
if (b <= 0) {
if (b == 0)
g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
g_snprintf(errmsg, errmsgl, "End of file on pipe header during open");
else
g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s",
strerror(errno));
goto error;
}
bytes_read += b;
}
}
#else /* USE_THREADS */
ld->cap_pipe_buf = (char *) hdr;
ld->cap_pipe_bytes_read = 0;
ld->cap_pipe_bytes_to_read = sizeof(struct pcap_hdr);
g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
g_async_queue_pop(cap_pipe_done_q);
if (ld->cap_pipe_bytes_read <= 0) {
if (ld->cap_pipe_bytes_read == 0)
g_snprintf(errmsg, errmsgl, "End of file on pipe header during open");
else
g_snprintf(errmsg, errmsgl, "Error on pipe header header during open: %s",
strerror(errno));
goto error;
}
#endif /* USE_THREADS */
if (ld->cap_pipe_byte_swapped) {
/* Byte-swap the header fields about which we care. */
@ -981,13 +1068,16 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
ld->cap_pipe_state = STATE_EXPECT_REC_HDR;
ld->cap_pipe_err = PIPOK;
return fd;
return;
error:
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg);
ld->cap_pipe_err = PIPERR;
#ifndef _WIN32
ws_close(fd);
return -1;
ld->cap_pipe_fd = -1;
#endif
return;
}
@ -998,10 +1088,17 @@ static int
cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
{
struct pcap_pkthdr phdr;
int b;
enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
PD_ERR } result;
PD_ERR } result;
#ifdef USE_THREADS
GTimeVal wait_time;
gpointer q_status;
#else
int b;
#endif
#ifdef _WIN32
wchar_t *err_str;
#endif
#ifdef LOG_CAPTURE_VERBOSE
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_dispatch");
@ -1010,13 +1107,25 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
switch (ld->cap_pipe_state) {
case STATE_EXPECT_REC_HDR:
#ifdef USE_THREADS
if (g_mutex_trylock(cap_pipe_read_mtx)) {
#endif
ld->cap_pipe_state = STATE_READ_REC_HDR;
ld->cap_pipe_bytes_to_read = ld->cap_pipe_modified ?
sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
ld->cap_pipe_bytes_read = 0;
ld->cap_pipe_state = STATE_READ_REC_HDR;
#ifdef USE_THREADS
ld->cap_pipe_buf = (char *) &ld->cap_pipe_rechdr;
g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
g_mutex_unlock(cap_pipe_read_mtx);
}
#endif
/* Fall through */
case STATE_READ_REC_HDR:
#ifndef USE_THREADS
b = read(ld->cap_pipe_fd, ((char *)&ld->cap_pipe_rechdr)+ld->cap_pipe_bytes_read,
ld->cap_pipe_bytes_to_read - ld->cap_pipe_bytes_read);
if (b <= 0) {
@ -1026,19 +1135,48 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
result = PD_PIPE_ERR;
break;
}
if ((ld->cap_pipe_bytes_read += b) < ld->cap_pipe_bytes_to_read)
ld->cap_pipe_bytes_read += b;
#else /* USE_THREADS */
g_get_current_time(&wait_time);
g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
if (ld->cap_pipe_err == PIPEOF) {
result = PD_PIPE_EOF;
break;
} else if (ld->cap_pipe_err == PIPERR) {
result = PD_PIPE_ERR;
break;
}
if (!q_status) {
return 0;
}
#endif /* USE_THREADS */
if ((ld->cap_pipe_bytes_read) < ld->cap_pipe_bytes_to_read)
return 0;
result = PD_REC_HDR_READ;
break;
case STATE_EXPECT_DATA:
ld->cap_pipe_bytes_read = 0;
#ifdef USE_THREADS
if (g_mutex_trylock(cap_pipe_read_mtx)) {
#endif
ld->cap_pipe_state = STATE_READ_DATA;
ld->cap_pipe_bytes_to_read = ld->cap_pipe_rechdr.hdr.incl_len;
ld->cap_pipe_bytes_read = 0;
#ifdef USE_THREADS
ld->cap_pipe_buf = (char *) data;
g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
g_mutex_unlock(cap_pipe_read_mtx);
}
#endif
/* Fall through */
case STATE_READ_DATA:
#ifndef USE_THREADS
b = read(ld->cap_pipe_fd, data+ld->cap_pipe_bytes_read,
ld->cap_pipe_rechdr.hdr.incl_len - ld->cap_pipe_bytes_read);
ld->cap_pipe_bytes_to_read - ld->cap_pipe_bytes_read);
if (b <= 0) {
if (b == 0)
result = PD_PIPE_EOF;
@ -1046,8 +1184,24 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
result = PD_PIPE_ERR;
break;
}
if ((ld->cap_pipe_bytes_read += b) < ld->cap_pipe_rechdr.hdr.incl_len)
ld->cap_pipe_bytes_read += b;
#else /* USE_THREADS */
g_get_current_time(&wait_time);
g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
if (ld->cap_pipe_err == PIPEOF) {
result = PD_PIPE_EOF;
break;
} else if (ld->cap_pipe_err == PIPERR) {
result = PD_PIPE_ERR;
break;
}
if (!q_status) {
return 0;
}
#endif /* USE_THREADS */
if ((ld->cap_pipe_bytes_read) < ld->cap_pipe_bytes_to_read)
return 0;
result = PD_DATA_READ;
break;
@ -1091,8 +1245,17 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
return -1;
case PD_PIPE_ERR:
#ifdef _WIN32
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
g_snprintf(errmsg, errmsgl,
"Error reading from pipe: %s (error %d)",
utf_16to8(err_str), GetLastError());
LocalFree(err_str);
#else
g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
strerror(errno));
#endif
/* Fall through */
case PD_ERR:
break;
@ -1199,10 +1362,10 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
CAP_READ_TIMEOUT, &auth, open_err_str);
#else
ld->pcap_h = pcap_open_live(capture_opts->iface,
capture_opts->has_snaplen ? capture_opts->snaplen :
WTAP_MAX_PACKET_SIZE,
capture_opts->promisc_mode, CAP_READ_TIMEOUT,
open_err_str);
capture_opts->has_snaplen ? capture_opts->snaplen :
WTAP_MAX_PACKET_SIZE,
capture_opts->promisc_mode, CAP_READ_TIMEOUT,
open_err_str);
#endif
/* If not using libcap: we now can now set euid/egid to ruid/rgid */
@ -1221,7 +1384,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
#ifdef _WIN32
/* try to set the capture buffer size */
if (capture_opts->buffer_size > 1 &&
pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
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"
@ -1274,48 +1437,52 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
/* setting the data link type only works on real interfaces */
if (capture_opts->linktype != -1) {
set_linktype_err_str = set_pcap_linktype(ld->pcap_h, capture_opts->iface,
capture_opts->linktype);
capture_opts->linktype);
if (set_linktype_err_str != NULL) {
g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type (%s).",
set_linktype_err_str);
g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type (%s).",
set_linktype_err_str);
g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
return FALSE;
return FALSE;
}
}
ld->linktype = get_pcap_linktype(ld->pcap_h, capture_opts->iface);
} else {
/* We couldn't open "iface" as a network device. */
/* Try to open it as a pipe */
ld->cap_pipe_fd = cap_pipe_open_live(capture_opts->iface, &ld->cap_pipe_hdr, ld, errmsg, (int) errmsg_len);
cap_pipe_open_live(capture_opts->iface, &ld->cap_pipe_hdr, ld, errmsg, (int) errmsg_len);
#ifndef _WIN32
if (ld->cap_pipe_fd == -1) {
#else
if (ld->cap_pipe_h == NULL) {
#endif
if (ld->cap_pipe_err == PIPNEXIST) {
/* Pipe doesn't exist, so output message for interface */
/* If we got a "can't find PPA for X" message, warn the user (who
is running (T)Wireshark on HP-UX) that they don't have a version
of libpcap that properly handles HP-UX (libpcap 0.6.x and later
versions, which properly handle HP-UX, say "can't find /dev/dlpi
PPA for X" rather than "can't find PPA for X"). */
if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
libpcap_warn =
"\n\n"
"You are running (T)Wireshark with a version of the libpcap library\n"
"that doesn't handle HP-UX network devices well; this means that\n"
"(T)Wireshark may not be able to capture packets.\n"
"\n"
"To fix this, you should install libpcap 0.6.2, or a later version\n"
"of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
"packaged binary form from the Software Porting And Archive Centre\n"
"for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
"at the URL lists a number of mirror sites.";
else
libpcap_warn = "";
g_snprintf(errmsg, (gulong) errmsg_len,
"The capture session could not be initiated (%s).", open_err_str);
/* Pipe doesn't exist, so output message for interface */
/* If we got a "can't find PPA for X" message, warn the user (who
is running (T)Wireshark on HP-UX) that they don't have a version
of libpcap that properly handles HP-UX (libpcap 0.6.x and later
versions, which properly handle HP-UX, say "can't find /dev/dlpi
PPA for X" rather than "can't find PPA for X"). */
if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
libpcap_warn =
"\n\n"
"You are running (T)Wireshark with a version of the libpcap library\n"
"that doesn't handle HP-UX network devices well; this means that\n"
"(T)Wireshark may not be able to capture packets.\n"
"\n"
"To fix this, you should install libpcap 0.6.2, or a later version\n"
"of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
"packaged binary form from the Software Porting And Archive Centre\n"
"for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
"at the URL lists a number of mirror sites.";
else
libpcap_warn = "";
g_snprintf(errmsg, (gulong) errmsg_len,
"The capture session could not be initiated (%s).", open_err_str);
#ifndef _WIN32
g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
"Please check to make sure you have sufficient permissions, and that you have "
"the proper interface or pipe specified.%s", libpcap_warn);
#else
@ -1371,11 +1538,19 @@ static void capture_loop_close_input(loop_data *ld) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input");
/* if open, close the capture pipe "input file" */
#ifndef _WIN32
if (ld->cap_pipe_fd >= 0) {
g_assert(ld->from_cap_pipe);
ws_close(ld->cap_pipe_fd);
ld->cap_pipe_fd = 0;
}
#else
if (ld->cap_pipe_h) {
g_assert(ld->from_cap_pipe);
CloseHandle(ld->cap_pipe_h);
ld->cap_pipe_h = NULL;
}
#endif
/* if open, close the pcap "input file" */
if(ld->pcap_h != NULL) {
@ -1502,14 +1677,14 @@ capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_d
default:
if (err < 0) {
g_snprintf(errmsg, errmsg_len,
"The file to which the capture would be"
" saved (\"%s\") could not be opened: Error %d.",
capture_opts->save_file, err);
"The file to which the capture would be"
" saved (\"%s\") could not be opened: Error %d.",
capture_opts->save_file, err);
} else {
g_snprintf(errmsg, errmsg_len,
"The file to which the capture would be"
" saved (\"%s\") could not be opened: %s.",
capture_opts->save_file, strerror(err));
"The file to which the capture would be"
" saved (\"%s\") could not be opened: %s.",
capture_opts->save_file, strerror(err));
}
break;
}
@ -1551,9 +1726,11 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
char *errmsg, int errmsg_len)
{
int inpkts;
int sel_ret;
gint packet_count_before;
guchar pcap_data[WTAP_MAX_PACKET_SIZE];
#ifndef USE_THREADS
int sel_ret;
#endif
packet_count_before = ld->packet_count;
if (ld->from_cap_pipe) {
@ -1561,6 +1738,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
#ifdef LOG_CAPTURE_VERBOSE
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
#endif
#ifndef USE_THREADS
sel_ret = cap_pipe_select(ld->cap_pipe_fd);
if (sel_ret <= 0) {
inpkts = 0;
@ -1574,11 +1752,14 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
/*
* "select()" says we can read from the pipe without blocking
*/
#endif /* USE_THREADS */
inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
if (inpkts < 0) {
ld->go = FALSE;
}
#ifndef USE_THREADS
}
#endif
}
else
{
@ -1853,7 +2034,11 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
global_ld.pcap_err = FALSE;
global_ld.from_cap_pipe = FALSE;
global_ld.pdh = NULL;
#ifndef _WIN32
global_ld.cap_pipe_fd = -1;
#else
global_ld.cap_pipe_h = NULL;
#endif
#ifdef MUST_DO_SELECT
global_ld.pcap_fd = 0;
#endif
@ -2492,6 +2677,14 @@ main(int argc, char *argv[])
/* Set handler for Ctrl+C key */
SetConsoleCtrlHandler(capture_cleanup, TRUE);
/* Prepare to read from a pipe */
if (!g_thread_supported ())
g_thread_init (NULL);
cap_pipe_pending_q = g_async_queue_new();
cap_pipe_done_q = g_async_queue_new();
cap_pipe_read_mtx = g_mutex_new();
#else
/* Catch SIGINT and SIGTERM and, if we get either of them, clean up
and exit. */
@ -2649,7 +2842,7 @@ main(int argc, char *argv[])
status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
if(status != 0) {
exit_main(status);
}
}
break;
/*** hidden option: Wireshark child mode (using binary output messages) ***/
case 'Z':
@ -3003,3 +3196,16 @@ signal_pipe_check_running(void)
}
}
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -368,6 +368,7 @@ File "${GLIB_DIR}\bin\libgio-2.0-0.dll"
File "${GLIB_DIR}\bin\libglib-2.0-0.dll"
File "${GLIB_DIR}\bin\libgobject-2.0-0.dll"
File "${GLIB_DIR}\bin\libgmodule-2.0-0.dll"
File "${GLIB_DIR}\bin\libgthread-2.0-0.dll"
!ifdef ICONV_DIR
File "${ICONV_DIR}\bin\iconv.dll"
!endif