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:
Guy Harris 2004-05-31 07:52:27 +00:00
parent d6d7816485
commit 8a429808e7
1 changed files with 371 additions and 374 deletions

View File

@ -1,6 +1,6 @@
/* tethereal.c /* 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 * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -120,7 +120,7 @@ static guint32 firstsec, firstusec;
static guint32 prevsec, prevusec; static guint32 prevsec, prevusec;
static GString *comp_info_str, *runtime_info_str; static GString *comp_info_str, *runtime_info_str;
static gboolean quiet; static gboolean quiet;
static gboolean decode; static gboolean print_packet_info; /* TRUE if we're to print packet information */
static gboolean verbose; static gboolean verbose;
static gboolean print_hex; static gboolean print_hex;
static gboolean line_buffered; static gboolean line_buffered;
@ -166,18 +166,16 @@ static void report_counts_siginfo(int);
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
typedef struct {
capture_file *cf;
wtap_dumper *pdh;
} cb_args_t;
static int load_cap_file(capture_file *, int); static int load_cap_file(capture_file *, int);
static void wtap_dispatch_cb_write(guchar *, const struct wtap_pkthdr *, long, static void process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
union wtap_pseudo_header *, const guchar *); 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 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 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, static char *cf_open_error_message(int err, gchar *err_info,
gboolean for_writing, int file_type); gboolean for_writing, int file_type);
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
@ -1117,12 +1115,11 @@ main(int argc, char *argv[])
is probably actually better for "-V", as it does fewer is probably actually better for "-V", as it does fewer
writes). writes).
See the comment in "wtap_dispatch_cb_print()" for an See the comment in "print_packet()" for an explanation of
explanation of why we do that, and why we don't just why we do that, and why we don't just use "setvbuf()" to
use "setvbuf()" to make the standard output line-buffered make the standard output line-buffered (short version: in
(short version: in Windows, "line-buffered" is the same Windows, "line-buffered" is the same as "fully-buffered",
as "fully-buffered", and the output buffer is only flushed and the output buffer is only flushed when it fills up). */
when it fills up). */
line_buffered = TRUE; line_buffered = TRUE;
break; break;
case 'L': /* Print list of link-layer types and exit */ case 'L': /* Print list of link-layer types and exit */
@ -1189,7 +1186,7 @@ main(int argc, char *argv[])
#endif #endif
break; break;
case 'S': /* show packets in real time */ case 'S': /* show packets in real time */
decode = TRUE; print_packet_info = TRUE;
break; break;
case 't': /* Time stamp type */ case 't': /* Time stamp type */
if (strcmp(optarg, "r") == 0) if (strcmp(optarg, "r") == 0)
@ -1345,6 +1342,9 @@ main(int argc, char *argv[])
} }
} }
#endif #endif
} else {
/* We're not writing to a file, so we should print packet information. */
print_packet_info = TRUE;
} }
#ifndef HAVE_LIBPCAP #ifndef HAVE_LIBPCAP
@ -1618,7 +1618,7 @@ main(int argc, char *argv[])
/* Do the low-level work of a capture. /* Do the low-level work of a capture.
Returns TRUE if it succeeds, FALSE otherwise. */ 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 static int
capture(int out_file_type) capture(int out_file_type)
@ -2098,7 +2098,6 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
struct wtap_pkthdr whdr; struct wtap_pkthdr whdr;
union wtap_pseudo_header pseudo_header; union wtap_pseudo_header pseudo_header;
loop_data *ld = (loop_data *) user; loop_data *ld = (loop_data *) user;
cb_args_t args;
int err; int err;
/* Convert from libpcap to Wiretap format. /* Convert from libpcap to Wiretap format.
@ -2106,30 +2105,32 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
written an error message). */ written an error message). */
pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header, pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header,
&whdr, &err); &whdr, &err);
if (pd == NULL) { if (pd == NULL)
return; return;
}
args.cf = &cfile; #ifdef SIGINFO
args.pdh = ld->pdh; /*
if (ld->pdh) { * Prevent a SIGINFO handler from writing to stdout while we're
wtap_dispatch_cb_write((guchar *)&args, &whdr, 0, &pseudo_header, pd); * doing so; instead, have it just set a flag telling us to print
/* Report packet capture count if not quiet */ * that information when we're done.
if (!quiet) { */
if (!decode) { infodelay = TRUE;
if (ld->packet_count != 0) { #endif /* SIGINFO */
fprintf(stderr, "\r%u ", ld->packet_count);
/* stderr could be line buffered */ process_packet(&cfile, ld->pdh, 0, &whdr, &pseudo_header, pd);
fflush(stderr);
} #ifdef SIGINFO
} else { /*
wtap_dispatch_cb_print((guchar *)&args, &whdr, 0, * Allow SIGINFO handlers to write.
&pseudo_header, pd); */
} infodelay = FALSE;
}
} else { /*
wtap_dispatch_cb_print((guchar *)&args, &whdr, 0, &pseudo_header, pd); * If a SIGINFO handler asked us to write out capture counts, do so.
} */
if (infoprint)
report_counts();
#endif /* SIGINFO */
} }
#ifdef _WIN32 #ifdef _WIN32
@ -2183,10 +2184,9 @@ report_counts(void)
signal(SIGINFO, report_counts_siginfo); signal(SIGINFO, report_counts_siginfo);
#endif /* SIGINFO */ #endif /* SIGINFO */
if (cfile.save_file != NULL && quiet) { if (quiet || print_packet_info) {
/* Report the count only if we're capturing to a file (rather /* Report the count only if we aren't printing a packet count
than printing captured packet information out) and aren't as packets arrive. */
updating a count as packets arrive. */
fprintf(stderr, "%u packets captured\n", ld.packet_count); fprintf(stderr, "%u packets captured\n", ld.packet_count);
} }
#ifdef SIGINFO #ifdef SIGINFO
@ -2219,8 +2219,7 @@ load_cap_file(capture_file *cf, int out_file_type)
wtap_dumper *pdh; wtap_dumper *pdh;
int err; int err;
gchar *err_info; gchar *err_info;
int success; long data_offset;
cb_args_t args;
linktype = wtap_file_encap(cf->wth); linktype = wtap_file_encap(cf->wth);
if (cf->save_file != NULL) { if (cf->save_file != NULL) {
@ -2271,10 +2270,6 @@ load_cap_file(capture_file *cf, int out_file_type)
} }
goto out; goto out;
} }
args.cf = cf;
args.pdh = pdh;
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (guchar *) &args,
&err, &err_info);
} else { } else {
print_preamble(stdout, print_format, cf->filename); print_preamble(stdout, print_format, cf->filename);
if (ferror(stdout)) { if (ferror(stdout)) {
@ -2282,24 +2277,13 @@ load_cap_file(capture_file *cf, int out_file_type)
show_print_file_io_error(err); show_print_file_io_error(err);
goto out; goto out;
} }
args.cf = cf; pdh = NULL;
args.pdh = NULL;
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (guchar *) &args,
&err, &err_info);
} }
if (success) { while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
if (cf->save_file != NULL) { process_packet(cf, pdh, data_offset, wtap_phdr(cf->wth),
/* Now close the capture file. */ wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth));
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);
} }
} if (err != 0) {
} else {
/* Print a message noting that the read failed somewhere along the line. */ /* Print a message noting that the read failed somewhere along the line. */
switch (err) { switch (err) {
@ -2335,9 +2319,21 @@ load_cap_file(capture_file *cf, int out_file_type)
} }
if (cf->save_file != NULL) { if (cf->save_file != NULL) {
/* Now close the capture file. */ /* 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); 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: out:
@ -2416,53 +2412,122 @@ clear_fdata(frame_data *fdata)
} }
static void static void
wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr, process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf) 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; frame_data fdata;
int err; gboolean create_proto_tree;
gboolean passed;
epan_dissect_t *edt; epan_dissect_t *edt;
gboolean passed;
#ifdef HAVE_LIBPCAP /* Count this packet. */
#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 */
cf->count++; cf->count++;
if (cf->rfcode) {
fill_in_fdata(&fdata, cf, phdr, offset); /* If we're going to print packet information, or we're going to
edt = epan_dissect_new(TRUE, FALSE); run a read filter, set up to do a dissection and do so. */
epan_dissect_prime_dfilter(edt, cf->rfcode); if (print_packet_info || cf->rfcode) {
epan_dissect_run(edt, pseudo_header, buf, &fdata, NULL); fill_in_fdata(&fdata, cf, whdr, offset);
passed = dfilter_apply_edt(cf->rfcode, edt);
} else { if (print_packet_info) {
passed = TRUE; /* Grab any resolved addresses */
edt = NULL;
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) { 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 #ifdef HAVE_LIBPCAP
int loop_err; int loop_err;
#endif
ld.packet_count++; #ifdef HAVE_LIBPCAP
/* The current packet may have arrived after a very long silence, /* The current packet may have arrived after a very long silence,
* way past the time to switch files. In order not to have * way past the time to switch files. In order not to have
* the first packet of a new series of events as the last * the first packet of a new series of events as the last
* [or only] packet in the file, switch before writing! * [or only] packet in the file, switch before writing!
*/ */
if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) { 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)) { if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
/* File switch succeeded: reset the condition */ /* File switch succeeded: reset the condition */
cnd_reset(cnd_ring_timeout); cnd_reset(cnd_ring_timeout);
@ -2489,26 +2554,6 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
wtap_dump_close(pdh, &err); wtap_dump_close(pdh, &err);
exit(2); 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 static void
@ -2562,55 +2607,11 @@ show_capture_file_io_error(const char *fname, int err, gboolean is_close)
} }
static void static void
wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr, print_packet(capture_file *cf, epan_dissect_t *edt)
long offset, union wtap_pseudo_header *pseudo_header, const guchar *buf)
{ {
cb_args_t *args = (cb_args_t *) user;
capture_file *cf = args->cf;
frame_data fdata;
gboolean passed;
print_args_t print_args; print_args_t print_args;
epan_dissect_t *edt;
gboolean create_proto_tree;
int i; 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.to_file = TRUE;
print_args.format = print_format; print_args.format = print_format;
print_args.print_summary = !verbose; 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); print_hex_data(stdout, print_args.format, edt);
putchar('\n'); putchar('\n');
} }
}
/* The ANSI C standard does not appear to *require* that a line-buffered /* The ANSI C standard does not appear to *require* that a line-buffered
stream be flushed to the host environment whenever a newline is 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); show_print_file_io_error(errno);
exit(2); exit(2);
} }
epan_dissect_free(edt);
clear_fdata(&fdata);
} }
static void static void