Commit 89a2966c authored by Gerald Combs's avatar Gerald Combs

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
parent 98309a6c
......@@ -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);
......
......@@ -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 */
......@@ -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 */
......@@ -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)
{
......
......@@ -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);
......
This diff is collapsed.
......@@ -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 */
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.
1.3. Artwork.
Logo and icon artwork can be found in the "image" directory in the
distribution. This is available online at
http://anonsvn.wireshark.org/wireshark/trunk/image/
2. Licensing.
Wireshark is released under the GNU General Public License. Make sure
your package complies with this license, or we send in the marmots.
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.
2. The Wireshark web site URL is http://www.wireshark.org/ .
4.1. Source-level version detection.
3. Wireshark is released under the GNU General Public License. Make sure
your package complies with this license, or we send in the marmots.
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.
4. Wireshark and the "fin" logo are registered trademarks of Gerald
Combs.
5. Trademarks.
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.
Wireshark and the "fin" logo are registered trademarks of Gerald Combs.
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.
6. Spelling.
7. Wireshark icons, logos, and other artwork can be found in the
"image" directory of the Wireshark sources.
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.
......
......@@ -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);
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment