Move the packet counting, dissecting, and filtering out of the "write
packet" and "print packet" callbacks into a common routine, so that we don't count packets twice if we're counting and dissecting. Print the packet count with ^T iff we're not updating a displayed packet count as packets arrive, regardless of whether we're printing packet information, saving packets to a file, or both (tcpdump prints it regardless of whether it's printing packet information or saving packets to a file). svn path=/trunk/; revision=11037
This commit is contained in:
parent
d6d7816485
commit
8a429808e7
335
tethereal.c
335
tethereal.c
|
@ -1,6 +1,6 @@
|
|||
/* tethereal.c
|
||||
*
|
||||
* $Id: tethereal.c,v 1.239 2004/05/09 10:03:39 guy Exp $
|
||||
* $Id: tethereal.c,v 1.240 2004/05/31 07:52:27 guy Exp $
|
||||
*
|
||||
* Ethereal - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@ethereal.com>
|
||||
|
@ -120,7 +120,7 @@ static guint32 firstsec, firstusec;
|
|||
static guint32 prevsec, prevusec;
|
||||
static GString *comp_info_str, *runtime_info_str;
|
||||
static gboolean quiet;
|
||||
static gboolean decode;
|
||||
static gboolean print_packet_info; /* TRUE if we're to print packet information */
|
||||
static gboolean verbose;
|
||||
static gboolean print_hex;
|
||||
static gboolean line_buffered;
|
||||
|
@ -166,18 +166,16 @@ static void report_counts_siginfo(int);
|
|||
#endif /* _WIN32 */
|
||||
#endif /* HAVE_LIBPCAP */
|
||||
|
||||
typedef struct {
|
||||
capture_file *cf;
|
||||
wtap_dumper *pdh;
|
||||
} cb_args_t;
|
||||
|
||||
static int load_cap_file(capture_file *, int);
|
||||
static void wtap_dispatch_cb_write(guchar *, const struct wtap_pkthdr *, long,
|
||||
union wtap_pseudo_header *, const guchar *);
|
||||
static void process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
|
||||
const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
|
||||
const guchar *pd);
|
||||
static void write_packet(capture_file *cf, wtap_dumper *pdh,
|
||||
const struct wtap_pkthdr *phdr, union wtap_pseudo_header *pseudo_header,
|
||||
const guchar *buf);
|
||||
static void show_capture_file_io_error(const char *, int, gboolean);
|
||||
static void wtap_dispatch_cb_print(guchar *, const struct wtap_pkthdr *, long,
|
||||
union wtap_pseudo_header *, const guchar *);
|
||||
static void show_print_file_io_error(int err);
|
||||
static void print_packet(capture_file *cf, epan_dissect_t *edt);
|
||||
static char *cf_open_error_message(int err, gchar *err_info,
|
||||
gboolean for_writing, int file_type);
|
||||
#ifdef HAVE_LIBPCAP
|
||||
|
@ -1117,12 +1115,11 @@ main(int argc, char *argv[])
|
|||
is probably actually better for "-V", as it does fewer
|
||||
writes).
|
||||
|
||||
See the comment in "wtap_dispatch_cb_print()" for an
|
||||
explanation of why we do that, and why we don't just
|
||||
use "setvbuf()" to make the standard output line-buffered
|
||||
(short version: in Windows, "line-buffered" is the same
|
||||
as "fully-buffered", and the output buffer is only flushed
|
||||
when it fills up). */
|
||||
See the comment in "print_packet()" for an explanation of
|
||||
why we do that, and why we don't just use "setvbuf()" to
|
||||
make the standard output line-buffered (short version: in
|
||||
Windows, "line-buffered" is the same as "fully-buffered",
|
||||
and the output buffer is only flushed when it fills up). */
|
||||
line_buffered = TRUE;
|
||||
break;
|
||||
case 'L': /* Print list of link-layer types and exit */
|
||||
|
@ -1189,7 +1186,7 @@ main(int argc, char *argv[])
|
|||
#endif
|
||||
break;
|
||||
case 'S': /* show packets in real time */
|
||||
decode = TRUE;
|
||||
print_packet_info = TRUE;
|
||||
break;
|
||||
case 't': /* Time stamp type */
|
||||
if (strcmp(optarg, "r") == 0)
|
||||
|
@ -1345,6 +1342,9 @@ main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* We're not writing to a file, so we should print packet information. */
|
||||
print_packet_info = TRUE;
|
||||
}
|
||||
|
||||
#ifndef HAVE_LIBPCAP
|
||||
|
@ -1618,7 +1618,7 @@ main(int argc, char *argv[])
|
|||
/* Do the low-level work of a capture.
|
||||
Returns TRUE if it succeeds, FALSE otherwise. */
|
||||
|
||||
static condition *volatile cnd_ring_timeout = NULL; /* this must be visible in wtap_dispatch_cb_write */
|
||||
static condition *volatile cnd_ring_timeout = NULL; /* this must be visible in write_packet */
|
||||
|
||||
static int
|
||||
capture(int out_file_type)
|
||||
|
@ -2098,7 +2098,6 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
|
|||
struct wtap_pkthdr whdr;
|
||||
union wtap_pseudo_header pseudo_header;
|
||||
loop_data *ld = (loop_data *) user;
|
||||
cb_args_t args;
|
||||
int err;
|
||||
|
||||
/* Convert from libpcap to Wiretap format.
|
||||
|
@ -2106,30 +2105,32 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
|
|||
written an error message). */
|
||||
pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header,
|
||||
&whdr, &err);
|
||||
if (pd == NULL) {
|
||||
if (pd == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
args.cf = &cfile;
|
||||
args.pdh = ld->pdh;
|
||||
if (ld->pdh) {
|
||||
wtap_dispatch_cb_write((guchar *)&args, &whdr, 0, &pseudo_header, pd);
|
||||
/* Report packet capture count if not quiet */
|
||||
if (!quiet) {
|
||||
if (!decode) {
|
||||
if (ld->packet_count != 0) {
|
||||
fprintf(stderr, "\r%u ", ld->packet_count);
|
||||
/* stderr could be line buffered */
|
||||
fflush(stderr);
|
||||
}
|
||||
} else {
|
||||
wtap_dispatch_cb_print((guchar *)&args, &whdr, 0,
|
||||
&pseudo_header, pd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wtap_dispatch_cb_print((guchar *)&args, &whdr, 0, &pseudo_header, pd);
|
||||
}
|
||||
#ifdef SIGINFO
|
||||
/*
|
||||
* Prevent a SIGINFO handler from writing to stdout while we're
|
||||
* doing so; instead, have it just set a flag telling us to print
|
||||
* that information when we're done.
|
||||
*/
|
||||
infodelay = TRUE;
|
||||
#endif /* SIGINFO */
|
||||
|
||||
process_packet(&cfile, ld->pdh, 0, &whdr, &pseudo_header, pd);
|
||||
|
||||
#ifdef SIGINFO
|
||||
/*
|
||||
* Allow SIGINFO handlers to write.
|
||||
*/
|
||||
infodelay = FALSE;
|
||||
|
||||
/*
|
||||
* If a SIGINFO handler asked us to write out capture counts, do so.
|
||||
*/
|
||||
if (infoprint)
|
||||
report_counts();
|
||||
#endif /* SIGINFO */
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -2183,10 +2184,9 @@ report_counts(void)
|
|||
signal(SIGINFO, report_counts_siginfo);
|
||||
#endif /* SIGINFO */
|
||||
|
||||
if (cfile.save_file != NULL && quiet) {
|
||||
/* Report the count only if we're capturing to a file (rather
|
||||
than printing captured packet information out) and aren't
|
||||
updating a count as packets arrive. */
|
||||
if (quiet || print_packet_info) {
|
||||
/* Report the count only if we aren't printing a packet count
|
||||
as packets arrive. */
|
||||
fprintf(stderr, "%u packets captured\n", ld.packet_count);
|
||||
}
|
||||
#ifdef SIGINFO
|
||||
|
@ -2219,8 +2219,7 @@ load_cap_file(capture_file *cf, int out_file_type)
|
|||
wtap_dumper *pdh;
|
||||
int err;
|
||||
gchar *err_info;
|
||||
int success;
|
||||
cb_args_t args;
|
||||
long data_offset;
|
||||
|
||||
linktype = wtap_file_encap(cf->wth);
|
||||
if (cf->save_file != NULL) {
|
||||
|
@ -2271,10 +2270,6 @@ load_cap_file(capture_file *cf, int out_file_type)
|
|||
}
|
||||
goto out;
|
||||
}
|
||||
args.cf = cf;
|
||||
args.pdh = pdh;
|
||||
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (guchar *) &args,
|
||||
&err, &err_info);
|
||||
} else {
|
||||
print_preamble(stdout, print_format, cf->filename);
|
||||
if (ferror(stdout)) {
|
||||
|
@ -2282,24 +2277,13 @@ load_cap_file(capture_file *cf, int out_file_type)
|
|||
show_print_file_io_error(err);
|
||||
goto out;
|
||||
}
|
||||
args.cf = cf;
|
||||
args.pdh = NULL;
|
||||
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (guchar *) &args,
|
||||
&err, &err_info);
|
||||
pdh = NULL;
|
||||
}
|
||||
if (success) {
|
||||
if (cf->save_file != NULL) {
|
||||
/* Now close the capture file. */
|
||||
if (!wtap_dump_close(args.pdh, &err))
|
||||
show_capture_file_io_error(cfile.save_file, err, TRUE);
|
||||
} else {
|
||||
print_finale(stdout, print_format);
|
||||
if (ferror(stdout)) {
|
||||
err = errno;
|
||||
show_print_file_io_error(err);
|
||||
while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
|
||||
process_packet(cf, pdh, data_offset, wtap_phdr(cf->wth),
|
||||
wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (err != 0) {
|
||||
/* Print a message noting that the read failed somewhere along the line. */
|
||||
switch (err) {
|
||||
|
||||
|
@ -2335,9 +2319,21 @@ load_cap_file(capture_file *cf, int out_file_type)
|
|||
}
|
||||
if (cf->save_file != NULL) {
|
||||
/* Now close the capture file. */
|
||||
if (!wtap_dump_close(args.pdh, &err))
|
||||
if (!wtap_dump_close(pdh, &err))
|
||||
show_capture_file_io_error(cfile.save_file, err, TRUE);
|
||||
}
|
||||
} else {
|
||||
if (cf->save_file != NULL) {
|
||||
/* Now close the capture file. */
|
||||
if (!wtap_dump_close(pdh, &err))
|
||||
show_capture_file_io_error(cfile.save_file, err, TRUE);
|
||||
} else {
|
||||
print_finale(stdout, print_format);
|
||||
if (ferror(stdout)) {
|
||||
err = errno;
|
||||
show_print_file_io_error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -2416,53 +2412,122 @@ clear_fdata(frame_data *fdata)
|
|||
}
|
||||
|
||||
static void
|
||||
wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
|
||||
long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf)
|
||||
process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
|
||||
const struct wtap_pkthdr *whdr,
|
||||
union wtap_pseudo_header *pseudo_header, const guchar *pd)
|
||||
{
|
||||
cb_args_t *args = (cb_args_t *) user;
|
||||
capture_file *cf = args->cf;
|
||||
wtap_dumper *pdh = args->pdh;
|
||||
frame_data fdata;
|
||||
int err;
|
||||
gboolean passed;
|
||||
gboolean create_proto_tree;
|
||||
epan_dissect_t *edt;
|
||||
gboolean passed;
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
#ifdef SIGINFO
|
||||
/*
|
||||
* Prevent a SIGINFO handler from writing to stdout while we're
|
||||
* doing so; instead, have it just set a flag telling us to print
|
||||
* that information when we're done.
|
||||
*/
|
||||
infodelay = TRUE;
|
||||
#endif /* SIGINFO */
|
||||
#endif /* HAVE_LIBPCAP */
|
||||
|
||||
/* Count this packet. */
|
||||
cf->count++;
|
||||
if (cf->rfcode) {
|
||||
fill_in_fdata(&fdata, cf, phdr, offset);
|
||||
edt = epan_dissect_new(TRUE, FALSE);
|
||||
epan_dissect_prime_dfilter(edt, cf->rfcode);
|
||||
epan_dissect_run(edt, pseudo_header, buf, &fdata, NULL);
|
||||
passed = dfilter_apply_edt(cf->rfcode, edt);
|
||||
} else {
|
||||
passed = TRUE;
|
||||
edt = NULL;
|
||||
|
||||
/* If we're going to print packet information, or we're going to
|
||||
run a read filter, set up to do a dissection and do so. */
|
||||
if (print_packet_info || cf->rfcode) {
|
||||
fill_in_fdata(&fdata, cf, whdr, offset);
|
||||
|
||||
if (print_packet_info) {
|
||||
/* Grab any resolved addresses */
|
||||
|
||||
if (g_resolv_flags) {
|
||||
host_name_lookup_process(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
passed = TRUE;
|
||||
if (cf->rfcode || verbose || num_tap_filters!=0)
|
||||
create_proto_tree = TRUE;
|
||||
else
|
||||
create_proto_tree = FALSE;
|
||||
/* The protocol tree will be "visible", i.e., printed, only if we're
|
||||
printing packet details, which is true if we're printing stuff
|
||||
("print_packet_info" is true) and we're in verbose mode ("verbose"
|
||||
is true). */
|
||||
edt = epan_dissect_new(create_proto_tree, print_packet_info && verbose);
|
||||
|
||||
/* If we're running a read filter, prime the epan_dissect_t with that
|
||||
filter. */
|
||||
if (cf->rfcode)
|
||||
epan_dissect_prime_dfilter(edt, cf->rfcode);
|
||||
|
||||
tap_queue_init(edt);
|
||||
|
||||
/* We only need the columns if we're printing packet info but we're
|
||||
*not* verbose; in verbose mode, we print the protocol tree, not
|
||||
the protocol summary. */
|
||||
epan_dissect_run(edt, pseudo_header, pd, &fdata,
|
||||
(print_packet_info && !verbose) ? &cf->cinfo : NULL);
|
||||
|
||||
tap_push_tapped_queue(edt);
|
||||
|
||||
/* Run the read filter if we have one. */
|
||||
if (cf->rfcode)
|
||||
passed = dfilter_apply_edt(cf->rfcode, edt);
|
||||
else
|
||||
passed = TRUE;
|
||||
} else {
|
||||
/* We're not running a display filter and we're not printing any
|
||||
packet information, so we don't need to do a dissection, and all
|
||||
packets are processed. */
|
||||
edt = NULL;
|
||||
passed = TRUE;
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
/* The packet passed the read filter. */
|
||||
/* Count this packet. */
|
||||
#ifdef HAVE_LIBPCAP
|
||||
ld.packet_count++;
|
||||
#endif
|
||||
|
||||
/* Process this packet. */
|
||||
if (pdh != NULL) {
|
||||
/* We're writing to a capture file; write this packet. */
|
||||
write_packet(cf, pdh, whdr, pseudo_header, pd);
|
||||
/* Report packet capture count if not quiet */
|
||||
if (!quiet && !print_packet_info) {
|
||||
/* Don't print a packet count if we were asked not to with "-q"
|
||||
or if we're also printing packet info. */
|
||||
if (ld.packet_count != 0) {
|
||||
fprintf(stderr, "\r%u ", ld.packet_count);
|
||||
/* stderr could be line buffered */
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (print_packet_info) {
|
||||
/* We're printing packet information; print the information for
|
||||
this packet. */
|
||||
print_packet(cf, edt);
|
||||
}
|
||||
}
|
||||
|
||||
if (edt != NULL)
|
||||
epan_dissect_free(edt);
|
||||
|
||||
if (print_packet_info || cf->rfcode)
|
||||
clear_fdata(&fdata);
|
||||
}
|
||||
|
||||
static void
|
||||
write_packet(capture_file *cf, wtap_dumper *pdh, const struct wtap_pkthdr *phdr,
|
||||
union wtap_pseudo_header *pseudo_header, const guchar *buf)
|
||||
{
|
||||
int err;
|
||||
#ifdef HAVE_LIBPCAP
|
||||
int loop_err;
|
||||
#endif
|
||||
|
||||
ld.packet_count++;
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
/* The current packet may have arrived after a very long silence,
|
||||
* way past the time to switch files. In order not to have
|
||||
* the first packet of a new series of events as the last
|
||||
* [or only] packet in the file, switch before writing!
|
||||
*/
|
||||
if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
|
||||
/* time elasped for this ring file, switch to the next */
|
||||
/* time elapsed for this ring file, switch to the next */
|
||||
if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
|
||||
/* File switch succeeded: reset the condition */
|
||||
cnd_reset(cnd_ring_timeout);
|
||||
|
@ -2490,26 +2555,6 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
|
|||
exit(2);
|
||||
}
|
||||
}
|
||||
if (edt != NULL)
|
||||
epan_dissect_free(edt);
|
||||
if (cf->rfcode)
|
||||
clear_fdata(&fdata);
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
#ifdef SIGINFO
|
||||
/*
|
||||
* Allow SIGINFO handlers to write.
|
||||
*/
|
||||
infodelay = FALSE;
|
||||
|
||||
/*
|
||||
* If a SIGINFO handler asked us to write out capture counts, do so.
|
||||
*/
|
||||
if (infoprint)
|
||||
report_counts();
|
||||
#endif /* SIGINFO */
|
||||
#endif /* HAVE_LIBPCAP */
|
||||
}
|
||||
|
||||
static void
|
||||
show_capture_file_io_error(const char *fname, int err, gboolean is_close)
|
||||
|
@ -2562,55 +2607,11 @@ show_capture_file_io_error(const char *fname, int err, gboolean is_close)
|
|||
}
|
||||
|
||||
static void
|
||||
wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
|
||||
long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf)
|
||||
print_packet(capture_file *cf, epan_dissect_t *edt)
|
||||
{
|
||||
cb_args_t *args = (cb_args_t *) user;
|
||||
capture_file *cf = args->cf;
|
||||
frame_data fdata;
|
||||
gboolean passed;
|
||||
print_args_t print_args;
|
||||
epan_dissect_t *edt;
|
||||
gboolean create_proto_tree;
|
||||
int i;
|
||||
|
||||
cf->count++;
|
||||
|
||||
fill_in_fdata(&fdata, cf, phdr, offset);
|
||||
|
||||
/* Grab any resolved addresses */
|
||||
if (g_resolv_flags) {
|
||||
host_name_lookup_process(NULL);
|
||||
}
|
||||
|
||||
passed = TRUE;
|
||||
if (cf->rfcode || verbose || num_tap_filters!=0)
|
||||
create_proto_tree = TRUE;
|
||||
else
|
||||
create_proto_tree = FALSE;
|
||||
/* The protocol tree will be "visible", i.e., printed, only if we're
|
||||
not printing a summary.
|
||||
|
||||
We only need the columns if we're *not* verbose; in verbose mode,
|
||||
we print the protocol tree, not the protocol summary. */
|
||||
|
||||
edt = epan_dissect_new(create_proto_tree, verbose);
|
||||
if (cf->rfcode) {
|
||||
epan_dissect_prime_dfilter(edt, cf->rfcode);
|
||||
}
|
||||
|
||||
tap_queue_init(edt);
|
||||
epan_dissect_run(edt, pseudo_header, buf, &fdata, verbose ? NULL : &cf->cinfo);
|
||||
tap_push_tapped_queue(edt);
|
||||
|
||||
if (cf->rfcode) {
|
||||
passed = dfilter_apply_edt(cf->rfcode, edt);
|
||||
}
|
||||
if (passed) {
|
||||
/* The packet passed the read filter. */
|
||||
#ifdef HAVE_LIBPCAP
|
||||
ld.packet_count++;
|
||||
#endif
|
||||
print_args.to_file = TRUE;
|
||||
print_args.format = print_format;
|
||||
print_args.print_summary = !verbose;
|
||||
|
@ -2817,7 +2818,6 @@ wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
|
|||
print_hex_data(stdout, print_args.format, edt);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/* The ANSI C standard does not appear to *require* that a line-buffered
|
||||
stream be flushed to the host environment whenever a newline is
|
||||
|
@ -2846,9 +2846,6 @@ wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
|
|||
show_print_file_io_error(errno);
|
||||
exit(2);
|
||||
}
|
||||
epan_dissect_free(edt);
|
||||
|
||||
clear_fdata(&fdata);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue