Add a "-S" flag to dumpcap, which prints out interface statistics. Use

this in the GUI rather than calling pcap_stats() directly. This gets rid
of the last pcap_open_live() call in the GUI code. Update
README.packaging.

svn path=/trunk/; revision=22443
This commit is contained in:
Gerald Combs 2007-08-02 21:45:27 +00:00
parent 98309a6c83
commit 89a2966ced
10 changed files with 531 additions and 132 deletions

View File

@ -72,7 +72,7 @@ GList *get_interface_list(int *err, char **err_str);
/* Error values from "get_interface_list()/capture_interface_list()". */
#define CANT_GET_INTERFACE_LIST 1 /* error getting list */
#define NO_INTERFACES_FOUND 2 /* list is empty */
#define CANT_RUN_DUMPCAP 3 /* problem running 'dumpcap -I l' */
#define CANT_RUN_DUMPCAP 3 /* problem running dumpcap */
void free_interface_list(GList *if_list);

139
capture.c
View File

@ -44,14 +44,18 @@
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> /* needed to define AF_ values on UNIX */
#endif
@ -92,7 +96,16 @@
#include "file_util.h"
#include "log.h"
typedef struct if_stat_cache_item_s {
char *name;
struct pcap_stat ps;
} if_stat_cache_item_t;
struct if_stat_cache_s {
int stat_fd;
int fork_child;
GList *cache_list; /* List of if_stat_chache_entry_t */
};
/**
* Start a capture.
@ -675,7 +688,7 @@ capture_interface_list(int *err, char **err_str)
/* Check to see if we built a list */
if (if_list == NULL) {
if (*err_str)
if (err_str && *err_str)
*err_str = g_strdup("No interfaces found");
*err = NO_INTERFACES_FOUND;
}
@ -722,7 +735,7 @@ capture_pcap_linktype_list(gchar *ifname, char **err_str)
data_link_info = g_malloc(sizeof (data_link_info_t));
data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
data_link_info->name = g_strdup(lt_parts[1]);
if (strcmp(lt_parts[2], "(not supported)") != NULL)
if (strcmp(lt_parts[2], "(not supported)") != 0)
data_link_info->description = g_strdup(lt_parts[2]);
else
data_link_info->description = NULL;
@ -739,5 +752,119 @@ capture_pcap_linktype_list(gchar *ifname, char **err_str)
return linktype_list;
}
if_stat_cache_t *
capture_stat_start(GList *if_list) {
int stat_fd, fork_child;
gchar *msg;
if_stat_cache_t *sc = NULL;
GList *if_entry;
if_info_t *if_info;
if_stat_cache_item_t *sc_item;
/* Fire up dumpcap. */
/*
* XXX - on systems with BPF, the number of BPF devices limits the
* number of devices on which you can capture simultaneously.
*
* This means that
*
* 1) this might fail if you run out of BPF devices
*
* and
*
* 2) opening every interface could leave too few BPF devices
* for *other* programs.
*
* It also means the system could end up getting a lot of traffic
* that it has to pass through the networking stack and capture
* mechanism, so opening all the devices and presenting packet
* counts might not always be a good idea.
*/
if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
sc = g_malloc(sizeof(if_stat_cache_t));
sc->stat_fd = stat_fd;
sc->fork_child = fork_child;
sc->cache_list = NULL;
/* Initialize the cache */
for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
if_info = if_entry->data;
sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
sc_item->name = g_strdup(if_info->name);
sc->cache_list = g_list_append(sc->cache_list, sc_item);
}
}
return sc;
}
#define MAX_STAT_LINE_LEN 500
static void
capture_stat_cache_update(if_stat_cache_t *sc) {
gchar stat_line[MAX_STAT_LINE_LEN];
gchar **stat_parts;
GList *sc_entry;
if_stat_cache_item_t *sc_item;
if (!sc)
return;
while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
g_strstrip(stat_line);
stat_parts = g_strsplit(stat_line, "\t", 3);
if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
stat_parts[2] == NULL) {
g_strfreev(stat_parts);
continue;
}
for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
sc_item = sc_entry->data;
if (strcmp(sc_item->name, stat_parts[0]) == 0) {
sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
}
}
g_strfreev(stat_parts);
}
}
gboolean
capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
GList *sc_entry;
if_stat_cache_item_t *sc_item;
if (!sc || !ifname || !ps) {
return FALSE;
}
capture_stat_cache_update(sc);
for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
sc_item = sc_entry->data;
if (strcmp(sc_item->name, ifname) == 0) {
memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
return TRUE;
}
}
return FALSE;
}
void
capture_stat_stop(if_stat_cache_t *sc) {
GList *sc_entry;
if_stat_cache_item_t *sc_item;
gchar *msg;
if (!sc)
return;
sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
sc_item = sc_entry->data;
g_free(sc_item->name);
g_free(sc_item);
}
g_free(sc);
}
#endif /* HAVE_LIBPCAP */

View File

@ -81,6 +81,7 @@ extern void capture_input_cfilter_error_message(capture_options *capture_opts, c
*/
extern void capture_input_closed(capture_options *capture_opts);
#ifdef HAVE_LIBPCAP
/**
* Fetch the interface list from a child process.
*/
@ -92,4 +93,26 @@ extern GList *capture_interface_list(int *err, char **err_str);
extern GList *capture_pcap_linktype_list(char *devname, char **err_str);
struct if_stat_cache_s;
typedef struct if_stat_cache_s if_stat_cache_t;
/**
* Start gathering capture statistics for the interfaces specified.
* @param A GList of if_info_t items
* @return A pointer to the statistics state data.
*/
extern if_stat_cache_t * capture_stat_start(GList *if_list);
/**
* Fetch capture statistics, similar to pcap_stats().
*/
struct pcap_stat; /* Stub in case we don't or haven't yet included pcap.h */
extern gboolean capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps);
/**
* Stop gathering capture statistics.
*/
void capture_stat_stop(if_stat_cache_t *sc);
#endif /* HAVE_LIBPCAP */
#endif /* capture.h */

View File

@ -31,6 +31,10 @@
#include <string.h>
#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
@ -68,6 +72,10 @@
#include "capture-pcap-util.h"
#include <wiretap/file_util.h>
typedef struct {
char *name;
pcap_t *pch;
} if_stat_t;
static gboolean capture_opts_output_to_pipe(const char *save_file, gboolean *is_pipe);
@ -558,6 +566,90 @@ capture_opts_list_interfaces(gboolean machine_readable)
return 0;
}
/* Print the number of packets captured for each interface until we're killed. */
int
capture_opts_print_statistics(gboolean machine_readable)
{
GList *if_list, *if_entry, *stat_list = NULL, *stat_entry;
if_info_t *if_info;
if_stat_t *if_stat;
int err;
gchar *err_str;
pcap_t *pch;
char errbuf[PCAP_ERRBUF_SIZE];
struct pcap_stat ps;
if_list = get_interface_list(&err, &err_str);
if (if_list == NULL) {
switch (err) {
case CANT_GET_INTERFACE_LIST:
cmdarg_err("%s", err_str);
g_free(err_str);
break;
case NO_INTERFACES_FOUND:
cmdarg_err("There are no interfaces on which a capture can be done");
break;
}
return err;
}
for (if_entry = g_list_first(if_list); if_entry != NULL; if_entry = g_list_next(if_entry)) {
if_info = if_entry->data;
pch = pcap_open_live(if_info->name, MIN_PACKET_SIZE, 0, 0, errbuf);
if (pch) {
if_stat = g_malloc(sizeof(if_stat_t));
if_stat->name = g_strdup(if_info->name);
if_stat->pch = pch;
stat_list = g_list_append(stat_list, if_stat);
}
}
if (!stat_list) {
cmdarg_err("There are no interfaces on which a capture can be done");
return 2;
}
if (!machine_readable) {
printf("%-15s %10s %10s\n", "Interface", "Received",
"Dropped");
}
while (1) { /* XXX - Add signal handling? */
for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
if_stat = stat_entry->data;
pcap_stats(if_stat->pch, &ps);
if (!machine_readable) {
printf("%-15s %10d %10d\n", if_stat->name,
ps.ps_recv, ps.ps_drop);
} else {
printf("%s\t%d\t%d\n", if_stat->name,
ps.ps_recv, ps.ps_drop);
fflush(stdout);
}
}
#ifdef _WIN32
Sleep(1 * 1000);
#else
sleep(1);
#endif
}
/* XXX - Not reached. Should we look for 'q' in stdin? */
for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
if_stat = stat_entry->data;
pcap_close(if_stat->pch);
g_free(if_stat->name);
g_free(if_stat);
}
g_list_free(stat_list);
free_interface_list(if_list);
return 0;
}
void capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min)
{

View File

@ -120,6 +120,10 @@ capture_opts_list_link_layer_types(capture_options *capture_opts, gboolean machi
extern int
capture_opts_list_interfaces(gboolean machine_readable);
/* print interface statistics */
extern int
capture_opts_print_statistics(gboolean machine_readable);
/* trim the snaplen entry */
extern void
capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min);

View File

@ -37,10 +37,13 @@
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <signal.h>
#ifdef _WIN32
#include <fcntl.h>
#include "epan/unicode-utils.h"
#endif
@ -523,15 +526,17 @@ sync_pipe_start(capture_options *capture_opts) {
}
/*
* Run dumpcap with the supplied arguments. On success, msg points to
* a buffer containing the dumpcap output and returns 0. On failure, msg
* points to the error message returned by dumpcap, and returns dumpcap's
* exit value. In either case, msg must be freed with g_free().
* Open dumpcap with the supplied arguments. On success, msg points to
* a buffer containing the dumpcap output and returns 0. read_fd and
* fork_child point to the pipe's file descriptor and child PID/handle,
* respectively. On failure, msg points to the error message returned by
* dumpcap, and returns dumpcap's exit value. In either case, msg must be
* freed with g_free().
*/
/* XXX - This duplicates a lot of code in sync_pipe_start() */
#define PIPE_BUF_SIZE 5120
static int
sync_pipe_run_command(const char** argv, gchar **msg) {
sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar **msg) {
#ifdef _WIN32
HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
HANDLE sync_pipe_write; /* pipe used to send messages from parent to child */
@ -545,12 +550,9 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
int sync_pipe[2]; /* pipe used to send messages from child to parent */
enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
#endif
int fork_child = -1, fork_child_status;
int sync_pipe_read_fd = -1;
GString *msg_buf = NULL;
gchar buf[PIPE_BUF_SIZE+1];
int count;
*fork_child = -1;
*read_fd = -1;
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_run_command");
if (!msg) {
@ -613,12 +615,12 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
g_free( (gpointer) argv);
return CANT_RUN_DUMPCAP;
}
fork_child = (int) pi.hProcess;
*fork_child = (int) pi.hProcess;
g_string_free(args, TRUE);
/* associate the operating system filehandle to a C run-time file handle */
/* (good file handle infos at: http://www.flounder.com/handles.htm) */
sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
*read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
#else /* _WIN32 */
if (pipe(sync_pipe) < 0) {
@ -629,7 +631,7 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
return CANT_RUN_DUMPCAP;
}
if ((fork_child = fork()) == 0) {
if ((*fork_child = fork()) == 0) {
/*
* Child process - run dumpcap with the right arguments to make
* it just capture with the specified capture parameters
@ -643,7 +645,7 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
return CANT_RUN_DUMPCAP;
}
sync_pipe_read_fd = sync_pipe[PIPE_READ];
*read_fd = sync_pipe[PIPE_READ];
#endif
g_free( (gpointer) argv[0]); /* exename */
@ -662,31 +664,34 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
eth_close(sync_pipe[PIPE_WRITE]);
#endif
if (fork_child == -1) {
if (*fork_child == -1) {
/* We couldn't even create the child process. */
*msg = g_strdup_printf("Couldn't create child process: %s", strerror(errno));
eth_close(sync_pipe_read_fd);
eth_close(*read_fd);
return CANT_RUN_DUMPCAP;
}
/* we might wait for a moment till child is ready, so update screen now */
main_window_update();
return 0;
}
/* We were able to set up to read dumpcap's output. Do so and
return its exit value. */
msg_buf = g_string_new("");
while ((count = eth_read(sync_pipe_read_fd, buf, PIPE_BUF_SIZE)) > 0) {
buf[count] = '\0';
g_string_append(msg_buf, buf);
}
static int
#ifdef _WIN32
sync_pipe_close_command(int *read_fd, int *fork_child, gchar **msg) {
#else
sync_pipe_close_command(int *read_fd, gchar **msg) {
#endif
int fork_child_status;
eth_close(sync_pipe_read_fd);
eth_close(*read_fd);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_list_open: wait till child closed");
#ifdef _WIN32
if (_cwait(&fork_child_status, fork_child, _WAIT_CHILD) == -1) {
g_string_free(msg_buf, TRUE);
/* XXX - Should we signal the child somehow? */
sync_pipe_kill(*fork_child);
if (_cwait(&fork_child_status, *fork_child, _WAIT_CHILD) == -1) {
*msg = g_strdup_printf("Child capture process stopped unexpectedly "
"(errno:%u)", errno);
return CANT_RUN_DUMPCAP;
@ -697,7 +702,6 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
/* The child exited. */
fork_child_status = WEXITSTATUS(fork_child_status);
} else {
g_string_free(msg_buf, TRUE);
if (WIFSTOPPED(fork_child_status)) {
/* It stopped, rather than exiting. "Should not happen." */
*msg = g_strdup_printf("Child capture process stopped: %s",
@ -716,16 +720,56 @@ sync_pipe_run_command(const char** argv, gchar **msg) {
return CANT_RUN_DUMPCAP;
}
} else {
g_string_free(msg_buf, TRUE);
*msg = g_strdup_printf("Child capture process stopped unexpectedly "
"(errno:%u)", errno);
return CANT_RUN_DUMPCAP;
}
#endif
return 0;
}
/*
* Run dumpcap with the supplied arguments. On success, msg points to
* a buffer containing the dumpcap output and returns 0. On failure, msg
* points to the error message returned by dumpcap, and returns dumpcap's
* exit value. In either case, msg must be freed with g_free().
*/
/* XXX - This duplicates a lot of code in sync_pipe_start() */
#define PIPE_BUF_SIZE 5120
static int
sync_pipe_run_command(const char** argv, gchar **msg) {
int sync_pipe_read_fd, fork_child, ret;
gchar buf[PIPE_BUF_SIZE+1];
GString *msg_buf = NULL;
int count;
ret = sync_pipe_open_command(argv, &sync_pipe_read_fd, &fork_child, msg);
if (ret)
return ret;
/* We were able to set up to read dumpcap's output. Do so and
return its exit value. */
msg_buf = g_string_new("");
while ((count = eth_read(sync_pipe_read_fd, buf, PIPE_BUF_SIZE)) > 0) {
buf[count] = '\0';
g_string_append(msg_buf, buf);
}
#ifdef _WIN32
ret = sync_pipe_close_command(&sync_pipe_read_fd, &fork_child, msg);
#else
ret = sync_pipe_close_command(&sync_pipe_read_fd, msg);
#endif
if (ret) {
g_string_free(msg_buf, TRUE);
return ret;
}
*msg = msg_buf->str;
g_string_free(msg_buf, FALSE);
return fork_child_status;
return 0;
}
/*
@ -804,6 +848,52 @@ sync_linktype_list_open(gchar *ifname, gchar **msg) {
return sync_pipe_run_command(argv, msg);
}
/*
* Start getting interface statistics using dumpcap. On success, read_fd
* contains the file descriptor for the pipe's stdout, msg is unchanged,
* and zero is returned. On failure, msg will point to an error message
* that must be g_free()d and a nonzero error value will be returned.
*/
int
sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg) {
int argc;
const char **argv;
if (!msg) {
/* We can't return anything */
return -1;
}
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_linktype_list_open");
argv = init_pipe_args(&argc);
if (!argv) {
*msg = g_strdup_printf("We don't know where to find dumpcap.");
return CANT_RUN_DUMPCAP;
}
/* Ask for the linktype list */
argv = sync_pipe_add_arg(argv, &argc, "-S");
argv = sync_pipe_add_arg(argv, &argc, "-M");
/* dumpcap should be running in capture child mode (hidden feature) */
#ifndef DEBUG_CHILD
argv = sync_pipe_add_arg(argv, &argc, "-Z");
#endif
return sync_pipe_open_command(argv, read_fd, fork_child, msg);
}
/* Close down the stats process */
int
sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg) {
#ifdef _WIN32
return sync_pipe_close_command(read_fd, fork_child, msg);
#else
return sync_pipe_close_command(read_fd, msg);
#endif
}
/* read a number of bytes from a pipe */
/* (blocks until enough bytes read or an error occurs) */
@ -812,7 +902,6 @@ pipe_read_bytes(int pipe, char *bytes, int required) {
int newly;
int offset = 0;
while(required) {
newly = read(pipe, &bytes[offset], required);
if (newly == 0) {
@ -835,6 +924,67 @@ pipe_read_bytes(int pipe, char *bytes, int required) {
return offset;
}
static gboolean pipe_data_available(int pipe) {
#ifdef _WIN32 /* PeekNamedPipe */
HANDLE hPipe = (HANDLE) _get_osfhandle(pipe);
DWORD bytes_avail;
if (hPipe == INVALID_HANDLE_VALUE)
return FALSE;
if (! PeekNamedPipe(hPipe, NULL, 0, NULL, &bytes_avail, NULL))
return FALSE;
if (bytes_avail > 0)
return TRUE;
return FALSE;
#else /* select */
fd_set rfds;
struct timeval timeout;
FD_ZERO(&rfds);
FD_SET(pipe, &rfds);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select(pipe+1, &rfds, NULL, NULL, &timeout) > 0)
return TRUE;
return FALSE;
#endif
}
/* Read a line from a pipe, similar to fgets */
int
sync_pipe_gets_nonblock(int pipe, char *bytes, int max) {
int newly;
int offset = -1;
while(offset < max - 1) {
offset++;
if (! pipe_data_available(pipe))
break;
newly = read(pipe, &bytes[offset], 1);
if (newly == 0) {
/* EOF - not necessarily an error */
break;
} else if (newly < 0) {
/* error */
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"read from pipe %d: error(%u): %s", pipe, errno, strerror(errno));
return newly;
} else if (bytes[offset] == '\n') {
break;
}
}
if (offset >= 0)
bytes[offset] = '\0';
return offset;
}
/* convert header values (indicator and 4-byte length) */
static void
pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) {

View File

@ -71,4 +71,17 @@ sync_interface_list_open(gchar **msg);
extern int
sync_linktype_list_open(gchar *ifname, gchar **msg);
/** Start getting interface statistics using dumpcap. */
extern int
sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg);
/** Stop gathering statistics. */
extern int
sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg);
/** Read a line from a pipe, similar to fgets. Non-blocking. */
extern int
sync_pipe_gets_nonblock(int pipe, char *bytes, int max);
#endif /* capture_sync.h */

View File

@ -1,37 +1,66 @@
Here's a brief list of information that might be useful to anyone
distributing a software package containing Wireshark:
The following guidelines should be followed by anyone distributing a software
package containing Wireshark:
1. The canonical location for every Wireshark source release is
1. URLs.
1.1. Wireshark web site.
The Wireshark web site URL is http://www.wireshark.org/ .
1.2. Wireshark releases.
The canonical location for every Wireshark source release is
http://www.wireshark.org/download/src/all-versions/, e.g.
http://www.wireshark.org/download/src/all-versions/wireshark-0.99.55.tar.bz2
If your packaging system downloads a copy of the Wireshark sources,
use this location. Don't use http://www.wireshark.org/download/src.
If your packaging system downloads a copy of the Wireshark sources, use
this location. Don't use http://www.wireshark.org/download/src.
2. The Wireshark web site URL is http://www.wireshark.org/ .
1.3. Artwork.
3. Wireshark is released under the GNU General Public License. Make sure
your package complies with this license, or we send in the marmots.
Logo and icon artwork can be found in the "image" directory in the
distribution. This is available online at
4. Wireshark and the "fin" logo are registered trademarks of Gerald
Combs.
http://anonsvn.wireshark.org/wireshark/trunk/image/
5. Custom version information can be added by creating a file called
"version.conf". See make-version.pl for details. If your package
contains significant changes we recommend that you use this to
differentiate it from official Wireshark releases.
2. Licensing.
6. The SVN version corresponding to each release is in svnversion.h.
It's defined as a string. If you need a numeric definition, let
us know.
Wireshark is released under the GNU General Public License. Make sure
your package complies with this license, or we send in the marmots.
7. Wireshark icons, logos, and other artwork can be found in the
"image" directory of the Wireshark sources.
3. Privileges.
In versions up to and including 0.99.6, it was necessary to run
Wireshark with elevated privileges in order to be able to capture
traffic. With version 0.99.7, all function calls that require elevated
privliges have been moved out of the GUI.
WIRESHARK CONTAINS OVER ONE POINT FIVE MILLION LINES OF SOURCE CODE. DO
NOT RUN THEM AS ROOT.
4. Customization.
Custom version information can be added by creating a file called
"version.conf". See make-version.pl for details. If your package
contains significant changes we recommend that you use this to
differentiate it from official Wireshark releases.
4.1. Source-level version detection.
The SVN version corresponding to each release is in svnversion.h. It's
defined as a string. If you need a numeric definition, let us know.
5. Trademarks.
Wireshark and the "fin" logo are registered trademarks of Gerald Combs.
6. Spelling.
Wireshark is spelled with a capital "W", and with everything else lower
case. E.g., "WireShark" is incorrect.
8. Wireshark is spelled with a capital "W", and with everything else
lower case. E.g., "WireShark" is incorrect.
If you have a question not addressed here, send it to
wireshark-dev@wireshark.org.

View File

@ -115,7 +115,8 @@ print_usage(gboolean print_ver) {
fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
fprintf(output, " -D print list of interfaces and exit\n");
fprintf(output, " -L print list of link-layer types of iface and exit\n");
fprintf(output, " -M for -D and -L, produce machine-readable output\n");
fprintf(output, " -S print statistics for each interface once every second\n");
fprintf(output, " -M for -D, -L, and -S produce machine-readable output\n");
fprintf(output, "\n");
fprintf(output, "Stop conditions:\n");
fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n");
@ -249,9 +250,10 @@ main(int argc, char *argv[])
gboolean list_interfaces = FALSE;
gboolean list_link_layer_types = FALSE;
gboolean machine_readable = FALSE;
int status;
gboolean print_statistics = FALSE;
int status, run_once_args = 0;
#define OPTSTRING_INIT "a:b:c:Df:hi:LMps:vw:y:Z"
#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z"
#ifdef _WIN32
#define OPTSTRING_WIN32 "B:"
@ -369,9 +371,15 @@ main(int argc, char *argv[])
/*** all non capture option specific ***/
case 'D': /* Print a list of capture devices and exit */
list_interfaces = TRUE;
run_once_args++;
break;
case 'L': /* Print list of link-layer types and exit */
list_link_layer_types = TRUE;
run_once_args++;
break;
case 'S': /* Print interface statistics once a second */
print_statistics = TRUE;
run_once_args++;
break;
case 'M': /* For -D and -L, print machine-readable output */
machine_readable = TRUE;
@ -406,8 +414,8 @@ main(int argc, char *argv[])
exit_main(1);
}
if (list_interfaces && list_link_layer_types) {
cmdarg_err("Only one of -D or -L may be supplied.");
if (run_once_args > 1) {
cmdarg_err("Only one of -D, -L, or -S may be supplied.");
exit_main(1);
} else if (list_link_layer_types) {
/* We're supposed to list the link-layer types for an interface;
@ -452,6 +460,9 @@ main(int argc, char *argv[])
} else if (list_link_layer_types) {
status = capture_opts_list_link_layer_types(capture_opts, machine_readable);
exit_main(status);
} else if (print_statistics) {
status = capture_opts_print_statistics(machine_readable);
exit_main(status);
}
capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);

View File

@ -107,7 +107,6 @@ GList *if_list;
/* the "runtime" data of one interface */
typedef struct if_dlg_data_s {
pcap_t *pch;
GtkWidget *device_lb;
GtkWidget *descr_lb;
GtkWidget *ip_lb;
@ -123,8 +122,6 @@ typedef struct if_dlg_data_s {
if_info_t if_info;
} if_dlg_data_t;
void update_if(if_dlg_data_t *if_dlg_data);
/* start capture button was pressed */
static void
@ -185,48 +182,9 @@ capture_details_cb(GtkWidget *details_bt _U_, gpointer if_data)
}
#endif
/* open a single interface */
static void
open_if(gchar *name, if_dlg_data_t *if_dlg_data)
{
gchar open_err_str[PCAP_ERRBUF_SIZE];
/*
* XXX - on systems with BPF, the number of BPF devices limits the
* number of devices on which you can capture simultaneously.
*
* This means that
*
* 1) this might fail if you run out of BPF devices
*
* and
*
* 2) opening every interface could leave too few BPF devices
* for *other* programs.
*
* It also means the system could end up getting a lot of traffic
* that it has to pass through the networking stack and capture
* mechanism, so opening all the devices and presenting packet
* counts might not always be a good idea.
*/
if_dlg_data->pch = pcap_open_live(name,
MIN_PACKET_SIZE,
capture_opts->promisc_mode, CAP_READ_TIMEOUT,
open_err_str);
if (if_dlg_data->pch != NULL) {
update_if(if_dlg_data);
} else {
printf("open_if: %s\n", open_err_str);
gtk_label_set_text(GTK_LABEL(if_dlg_data->curr_lb), "error");
gtk_label_set_text(GTK_LABEL(if_dlg_data->last_lb), "error");
}
}
/* update a single interface */
void
update_if(if_dlg_data_t *if_dlg_data)
update_if(if_dlg_data_t *if_dlg_data, if_stat_cache_t *sc)
{
struct pcap_stat stats;
gchar *str;
@ -243,8 +201,8 @@ update_if(if_dlg_data_t *if_dlg_data)
* (Note also that some versions of libpcap, on some versions of UN*X,
* have the same bug.)
*/
if (if_dlg_data->pch) {
if(pcap_stats(if_dlg_data->pch, &stats) >= 0) {
if (sc) {
if(capture_stats(sc, if_dlg_data->device, &stats)) {
#ifdef _WIN32
diff = stats.ps_recv - if_dlg_data->last_packets;
if_dlg_data->last_packets = stats.ps_recv;
@ -269,31 +227,20 @@ update_if(if_dlg_data_t *if_dlg_data)
}
}
/* close a single interface */
static void
close_if(if_dlg_data_t *if_dlg_data)
{
if(if_dlg_data->pch)
pcap_close(if_dlg_data->pch);
}
/* update all interfaces */
static gboolean
update_all(gpointer data)
{
GList *curr;
int ifs;
if_stat_cache_t *sc = data;
if(!cap_if_w) {
return FALSE;
}
for(ifs = 0; (curr = g_list_nth(data, ifs)); ifs++) {
update_if(curr->data);
for(ifs = 0; (curr = g_list_nth(if_data, ifs)); ifs++) {
update_if(curr->data, sc);
}
return TRUE;
@ -322,17 +269,15 @@ set_capture_if_dialog_for_capture_in_progress(gboolean capture_in_progress)
/* the window was closed, cleanup things */
static void
capture_if_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
capture_if_destroy_cb(GtkWidget *win _U_, gpointer user_data)
{
GList *curr;
int ifs;
if_stat_cache_t *sc = user_data;
gtk_timeout_remove(timer_id);
for(ifs = 0; (curr = g_list_nth(if_data, ifs)); ifs++) {
if_dlg_data_t *if_dlg_data = curr->data;
close_if(if_dlg_data);
g_free(curr->data);
}
@ -343,8 +288,10 @@ capture_if_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
/* Note that we no longer have a "Capture Options" dialog box. */
cap_if_w = NULL;
capture_stat_stop(sc);
#ifdef HAVE_AIRPCAP
airpcap_set_toolbar_stop_capture(airpcap_if_active);
airpcap_set_toolbar_stop_capture(airpcap_if_active);
#endif
}
@ -438,6 +385,7 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
if_addr_t *ip_addr;
GString *if_tool_str = g_string_new("");
gchar *tmp_str;
if_stat_cache_t *sc;
if (cap_if_w != NULL) {
/* There's already a "Capture Interfaces" dialog box; reactivate it. */
@ -567,6 +515,10 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
gtk_widget_size_request(stop_bt, &requisition);
height += requisition.height + 15;
/* Start gathering statistics (using dumpcap) */
sc = capture_stat_start(if_list);
/* List the interfaces */
for(ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
g_string_assign(if_tool_str, "");
if_info = curr->data;
@ -674,8 +626,6 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
gtk_table_attach_defaults(GTK_TABLE(if_tb), if_dlg_data->details_bt, 8, 9, row, row+1);
#endif
open_if(if_info->name, if_dlg_data);
if_data = g_list_append(if_data, if_dlg_data);
row++;
@ -713,7 +663,7 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
gtk_widget_grab_default(close_bt);
SIGNAL_CONNECT(cap_if_w, "delete_event", window_delete_event_cb, NULL);
SIGNAL_CONNECT(cap_if_w, "destroy", capture_if_destroy_cb, NULL);
SIGNAL_CONNECT(cap_if_w, "destroy", capture_if_destroy_cb, sc);
gtk_widget_show_all(cap_if_w);
window_present(cap_if_w);
@ -721,7 +671,7 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_)
set_capture_if_dialog_for_capture_in_progress(is_capture_in_progress());
/* update the interface list every 1000ms */
timer_id = gtk_timeout_add(1000, update_all, if_data);
timer_id = gtk_timeout_add(1000, update_all, sc);
}