Add description of TCP stream prefs.
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.85 1999/11/30 23:56:34 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_LIBPCAP
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40
41 #ifdef HAVE_SYS_WAIT_H
42 # include <sys/wait.h>
43 #endif
44
45 #include <gtk/gtk.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <string.h>
50 #include <fcntl.h>
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #include <time.h>
57
58 #ifdef HAVE_SYS_SOCKET_H
59 #include <sys/socket.h>
60 #endif
61
62 #ifdef HAVE_SYS_IOCTL_H
63 #include <sys/ioctl.h>
64 #endif
65
66 #ifdef HAVE_NET_IF_H
67 #include <net/if.h>
68 #endif
69
70 #include <signal.h>
71 #include <errno.h>
72
73 #ifdef NEED_SNPRINTF_H
74 # ifdef HAVE_STDARG_H
75 #  include <stdarg.h>
76 # else
77 #  include <varargs.h>
78 # endif
79 # include "snprintf.h"
80 #endif
81
82 #ifndef lib_pcap_h
83 #include <pcap.h>
84 #endif
85
86 #include "gtk/main.h"
87 #include "gtk/gtkglobals.h"
88 #include "packet.h"
89 #include "file.h"
90 #include "gtk/menu.h"
91 #include "capture.h"
92 #include "util.h"
93 #include "prefs.h"
94 #include "globals.h"
95
96 int sync_mode;  /* fork a child to do the capture, and sync between them */
97 static int sync_pipe[2]; /* used to sync father */
98 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
99 gboolean capture_child; /* if this is the child for "-S" */
100 static guint cap_input_id;
101
102 static void cap_file_input_cb(gpointer, gint, GdkInputCondition);
103 static void capture_stop_cb(GtkWidget *, gpointer);
104 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
105   const u_char *);
106 static float pct(gint, gint);
107
108 typedef struct _loop_data {
109   gint           go;
110   gint           max;
111   gint           linktype;
112   gint           sync_packets;
113   packet_counts  counts;
114   wtap_dumper   *pdh;
115 } loop_data;
116
117 /* Open a specified file, or create a temporary file, and start a capture
118    to the file in question. */
119 void
120 do_capture(char *capfile_name)
121 {
122   char tmpname[128+1];
123   gboolean is_tempfile;
124   u_char c;
125   int i;
126   guint byte_count;
127   char *msg;
128   int err;
129   int capture_succeeded;
130
131   if (capfile_name != NULL) {
132     /* Try to open/create the specified file for use as a capture buffer. */
133     cf.save_file_fd = open(capfile_name, O_RDWR|O_TRUNC|O_CREAT, 0600);
134     is_tempfile = FALSE;
135   } else {
136     /* Choose a random name for the capture buffer */
137     cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
138     capfile_name = g_strdup(tmpname);
139     is_tempfile = TRUE;
140   }
141   if (cf.save_file_fd == -1) {
142     simple_dialog(ESD_TYPE_WARN, NULL,
143         "The file to which the capture would be saved (\"%s\")"
144         "could not be opened: %s.", capfile_name, strerror(errno));
145     return;
146   }
147   close_cap_file(&cf, info_bar);
148   g_assert(cf.save_file == NULL);
149   cf.save_file = capfile_name;
150
151   if (sync_mode) {      /*  use fork() for capture */
152     int  fork_child;
153     char ssnap[24];
154     char scount[24];    /* need a constant for len of numbers */
155     char save_file_fd[24];
156
157     sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
158     sprintf(scount,"%d",cf.count);
159     sprintf(save_file_fd,"%d",cf.save_file_fd);
160     signal(SIGCHLD, SIG_IGN);
161     pipe(sync_pipe);
162     if ((fork_child = fork()) == 0) {
163       /*
164        * Child process - run Ethereal with the right arguments to make
165        * it just pop up the live capture dialog box and capture with
166        * the specified capture parameters, writing to the specified file.
167        *
168        * args: -i interface specification
169        * -w file to write
170        * -W file descriptor to write
171        * -c count to capture
172        * -s snaplen
173        * -m / -b fonts
174        * -f "filter expression"
175        */
176       close(1);
177       dup(sync_pipe[1]);
178       close(sync_pipe[0]);
179       execlp(ethereal_path, CHILD_NAME, "-i", cf.iface,
180                 "-w", cf.save_file, "-W", save_file_fd,
181                 "-c", scount, "-s", ssnap, 
182                 "-m", medium_font, "-b", bold_font,
183                 (cf.cfilter == NULL)? 0 : "-f",
184                 (cf.cfilter == NULL)? 0 : cf.cfilter,
185                 (const char *)NULL);    
186     } else {
187       /* Parent process - read messages from the child process over the
188          sync pipe. */
189       close(sync_pipe[1]);
190
191       /* Read a byte count from "sync_pipe[0]", terminated with a
192          colon; if the count is 0, the child process created the
193          capture file and we should start reading from it, otherwise
194          the capture couldn't start and the count is a count of bytes
195          of error message, and we should display the message. */
196       byte_count = 0;
197       for (;;) {
198         i = read(sync_pipe[0], &c, 1);
199         if (i == 0) {
200           /* EOF - the child process died.
201              Close the read side of the sync pipe, remove the capture file,
202              and report the failure.
203              XXX - reap the child process and report the status in detail. */
204           close(sync_pipe[0]);
205           unlink(cf.save_file);
206           g_free(cf.save_file);
207           cf.save_file = NULL;
208           simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
209           return;
210         }
211         if (c == ';')
212           break;
213         if (!isdigit(c)) {
214           /* Child process handed us crap.
215              Close the read side of the sync pipe, remove the capture file,
216              and report the failure. */
217           close(sync_pipe[0]);
218           unlink(cf.save_file);
219           g_free(cf.save_file);
220           cf.save_file = NULL;
221           simple_dialog(ESD_TYPE_WARN, NULL,
222              "Capture child process sent us a bad message");
223           return;
224         }
225         byte_count = byte_count*10 + c - '0';
226       }
227       if (byte_count == 0) {
228         /* Success.  Open the capture file, and set up to read it. */
229         err = start_tail_cap_file(cf.save_file, is_tempfile, &cf);
230         if (err == 0) {
231           /* We were able to open and set up to read the capture file;
232              arrange that our callback be called whenever it's possible
233              to read from the sync pipe, so that it's called when
234              the child process wants to tell us something. */
235           cap_input_id = gtk_input_add_full(sync_pipe[0],
236                                        GDK_INPUT_READ,
237                                        cap_file_input_cb,
238                                        NULL,
239                                        (gpointer) &cf,
240                                        NULL);
241         } else {
242           /* We weren't able to open the capture file; complain, and
243              close the sync pipe. */
244           simple_dialog(ESD_TYPE_WARN, NULL,
245                         file_open_error_message(err, FALSE), cf.save_file);
246
247           /* Close the sync pipe. */
248           close(sync_pipe[0]);
249
250           /* Don't unlink the save file - leave it around, for debugging
251              purposes. */
252           g_free(cf.save_file);
253           cf.save_file = NULL;
254         }
255       } else {
256         /* Failure - the child process sent us a message indicating
257            what the problem was. */
258         msg = g_malloc(byte_count + 1);
259         if (msg == NULL) {
260           simple_dialog(ESD_TYPE_WARN, NULL,
261                 "Capture child process failed, but its error message was too big.");
262         } else {
263           i = read(sync_pipe[0], msg, byte_count);
264           if (i < 0) {
265             simple_dialog(ESD_TYPE_WARN, NULL,
266                   "Capture child process failed: Error %s reading its error message.",
267                   strerror(errno));
268           } else if (i == 0) {
269             simple_dialog(ESD_TYPE_WARN, NULL,
270                   "Capture child process failed: EOF reading its error message.");
271           } else
272             simple_dialog(ESD_TYPE_WARN, NULL, msg);
273           g_free(msg);
274
275           /* Close the sync pipe. */
276           close(sync_pipe[0]);
277
278           /* Get rid of the save file - the capture never started. */
279           unlink(cf.save_file);
280           g_free(cf.save_file);
281           cf.save_file = NULL;
282         }
283       }
284     }
285   } else {
286     /* Not sync mode. */
287     capture_succeeded = capture();
288     if (quit_after_cap) {
289       /* DON'T unlink the save file.  Presumably someone wants it. */
290       gtk_exit(0);
291     }
292     if (capture_succeeded) {
293       /* Capture succeeded; read in the capture file. */
294       if ((err = open_cap_file(cf.save_file, is_tempfile, &cf)) == 0) {
295         /* Set the read filter to NULL. */
296         cf.rfcode = NULL;
297         err = read_cap_file(&cf);
298       }
299     }
300     /* We're not doing a capture any more, so we don't have a save
301        file. */
302     g_free(cf.save_file);
303     cf.save_file = NULL;
304   }
305 }
306
307 /* There's stuff to read from the sync pipe, meaning the child has sent
308    us a message, or the sync pipe has closed, meaning the child has
309    closed it (perhaps because it exited). */
310 static void 
311 cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition)
312 {
313   capture_file *cf = (capture_file *)data;
314   char buffer[256+1], *p = buffer, *q = buffer;
315   int  nread;
316   int  to_read = 0;
317   gboolean exit_loop = FALSE;
318   int  err;
319   int  wstatus;
320   int  wsignal;
321   char *msg;
322   char *sigmsg;
323   char sigmsg_buf[6+1+3+1];
324   char *coredumped;
325
326   /* avoid reentrancy problems and stack overflow */
327   gtk_input_remove(cap_input_id);
328
329   if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
330     /* The child has closed the sync pipe, meaning it's not going to be
331        capturing any more packets.  Pick up its exit status, and
332        complain if it died of a signal. */
333     if (wait(&wstatus) != -1) {
334       /* XXX - are there any platforms on which we can run that *don't*
335          support POSIX.1's <sys/wait.h> and macros therein? */
336       wsignal = wstatus & 0177;
337       coredumped = "";
338       if (wstatus == 0177) {
339         /* It stopped, rather than exiting.  "Should not happen." */
340         msg = "stopped";
341         wsignal = (wstatus >> 8) & 0xFF;
342       } else {
343         msg = "terminated";
344         if (wstatus & 0200)
345           coredumped = " - core dumped";
346       }
347       if (wsignal != 0) {
348         switch (wsignal) {
349
350         case SIGHUP:
351           sigmsg = "Hangup";
352           break;
353
354         case SIGINT:
355           sigmsg = "Interrupted";
356           break;
357
358         case SIGQUIT:
359           sigmsg = "Quit";
360           break;
361
362         case SIGILL:
363           sigmsg = "Illegal instruction";
364           break;
365
366         case SIGTRAP:
367           sigmsg = "Trace trap";
368           break;
369
370         case SIGABRT:
371           sigmsg = "Abort";
372           break;
373
374         case SIGFPE:
375           sigmsg = "Arithmetic exception";
376           break;
377
378         case SIGKILL:
379           sigmsg = "Killed";
380           break;
381
382         case SIGBUS:
383           sigmsg = "Bus error";
384           break;
385
386         case SIGSEGV:
387           sigmsg = "Segmentation violation";
388           break;
389
390         /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO 
391                 Linux is POSIX compliant.  These are not POSIX-defined signals ---
392                   ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
393
394                ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
395                 were omitted from POSIX.1 because their behavior is
396                 implementation dependent and could not be adequately catego-
397                 rized.  Conforming implementations may deliver these sig-
398                 nals, but must document the circumstances under which they
399                 are delivered and note any restrictions concerning their
400                 delivery.''
401         */
402
403         #ifdef SIGSYS
404         case SIGSYS:
405           sigmsg = "Bad system call";
406           break;
407         #endif
408
409         case SIGPIPE:
410           sigmsg = "Broken pipe";
411           break;
412
413         case SIGALRM:
414           sigmsg = "Alarm clock";
415           break;
416
417         case SIGTERM:
418           sigmsg = "Terminated";
419           break;
420
421         default:
422           sprintf(sigmsg_buf, "Signal %d", wsignal);
423           sigmsg = sigmsg_buf;
424           break;
425         }
426         simple_dialog(ESD_TYPE_WARN, NULL,
427                 "Child capture process %s: %s%s", msg, sigmsg, coredumped);
428       }
429     }
430       
431     /* Read what remains of the capture file, and finish the capture.
432        XXX - do something if this fails? */
433     err = finish_tail_cap_file(cf);
434
435     /* We're not doing a capture any more, so we don't have a save
436        file. */
437     g_free(cf->save_file);
438     cf->save_file = NULL;
439
440     return;
441   }
442
443   buffer[nread] = '\0';
444
445   while(!exit_loop) {
446     /* look for (possibly multiple) '*' */
447     switch (*q) {
448     case '*' :
449       to_read += atoi(p);
450       p = q + 1; 
451       q++;
452       break;
453     case '\0' :
454       /* XXX should handle the case of a pipe full (i.e. no star found) */
455       exit_loop = TRUE;
456       break;
457     default :
458       q++;
459       break;
460     } 
461   }
462
463   /* Read from the capture file the number of records the child told us
464      it added.
465      XXX - do something if this fails? */
466   err = continue_tail_cap_file(cf, to_read);
467
468   /* restore pipe handler */
469   cap_input_id = gtk_input_add_full (sync_pipe[0],
470                                      GDK_INPUT_READ,
471                                      cap_file_input_cb,
472                                      NULL,
473                                      (gpointer) cf,
474                                      NULL);
475 }
476
477 /* Do the low-level work of a capture.
478    Returns TRUE if it succeeds, FALSE otherwise. */
479 int
480 capture(void)
481 {
482   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
483              *ospf_lb, *gre_lb, *netbios_lb, *ipx_lb, *other_lb, *stop_bt;
484   pcap_t     *pch;
485   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
486   loop_data   ld;
487   bpf_u_int32 netnum, netmask;
488   time_t      upd_time, cur_time;
489   int         err, inpkts;
490   char        errmsg[1024+1];
491
492   ld.go             = TRUE;
493   ld.counts.total   = 0;
494   ld.max            = cf.count;
495   ld.linktype       = WTAP_ENCAP_UNKNOWN;
496   ld.sync_packets   = 0;
497   ld.counts.tcp     = 0;
498   ld.counts.udp     = 0;
499   ld.counts.icmp    = 0;
500   ld.counts.ospf    = 0;
501   ld.counts.gre     = 0;
502   ld.counts.ipx     = 0;
503   ld.counts.netbios = 0;
504   ld.counts.other   = 0;
505   ld.pdh            = NULL;
506
507   /* Open the network interface to capture from it. */
508   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
509
510   if (pch == NULL) {
511     /* Well, we couldn't start the capture.
512        If this is a child process that does the capturing in sync
513        mode or fork mode, it shouldn't do any UI stuff until we pop up the
514        capture-progress window, and, since we couldn't start the
515        capture, we haven't popped it up. */
516     if (!capture_child) {
517       while (gtk_events_pending()) gtk_main_iteration();
518     }
519     snprintf(errmsg, sizeof errmsg,
520       "The capture session could not be initiated (%s).\n"
521       "Please check to make sure you have sufficient permissions, and that\n"
522       "you have the proper interface specified.", err_str);
523     goto error;
524   }
525
526   if (cf.cfilter) {
527     /* A capture filter was specified; set it up. */
528     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
529       snprintf(errmsg, sizeof errmsg,
530         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
531       goto error;
532     }
533     if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
534       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
535         pcap_geterr(pch));
536       goto error;
537     }
538     if (pcap_setfilter(pch, &cf.fcode) < 0) {
539       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
540         pcap_geterr(pch));
541       goto error;
542     }
543   }
544
545   /* Set up to write to the capture file. */
546   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
547   if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
548     strcpy(errmsg, "The network you're capturing from is of a type"
549              " that Ethereal doesn't support.");
550     goto error;
551   }
552   ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
553                 ld.linktype, pcap_snapshot(pch), &err);
554
555   if (ld.pdh == NULL) {
556     /* We couldn't set up to write to the capture file. */
557     switch (err) {
558
559     case WTAP_ERR_CANT_OPEN:
560       strcpy(errmsg, "The file to which the capture would be saved"
561                " couldn't be created for some unknown reason.");
562       break;
563
564     case WTAP_ERR_SHORT_WRITE:
565       strcpy(errmsg, "A full header couldn't be written to the file"
566                " to which the capture would be saved.");
567       break;
568
569     default:
570       if (err < 0) {
571         sprintf(errmsg, "The file to which the capture would be"
572                      " saved (\"%s\") could not be opened: Error %d.",
573                         cf.save_file, err);
574       } else {
575         sprintf(errmsg, "The file to which the capture would be"
576                      " saved (\"%s\") could not be opened: %s.",
577                         cf.save_file, strerror(err));
578       }
579       break;
580     }
581     goto error;
582   }
583
584   if (capture_child) {
585     /* Well, we should be able to start capturing.
586
587        This is the child process for a sync mode capture, so sync out
588        the capture file, so the header makes it to the file system,
589        and send a "capture started successfully and capture file created"
590        message to our parent so that they'll open the capture file and
591        update its windows to indicate that we have a live capture in
592        progress. */
593     fflush(wtap_dump_file(ld.pdh));
594     write(1, "0;", 2);
595   }
596
597   cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
598   gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
599
600   /* Container for capture display widgets */
601   main_vb = gtk_vbox_new(FALSE, 1);
602   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
603   gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
604   gtk_widget_show(main_vb);
605
606   count_lb = gtk_label_new("Count: 0");
607   gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
608   gtk_widget_show(count_lb);
609
610   tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
611   gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
612   gtk_widget_show(tcp_lb);
613
614   udp_lb = gtk_label_new("UDP: 0 (0.0%)");
615   gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
616   gtk_widget_show(udp_lb);
617
618   icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
619   gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
620   gtk_widget_show(icmp_lb);
621
622   ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
623   gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
624   gtk_widget_show(ospf_lb);
625
626   gre_lb = gtk_label_new("GRE: 0 (0.0%)");
627   gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
628   gtk_widget_show(gre_lb);
629
630   netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
631   gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
632   gtk_widget_show(netbios_lb);
633
634   ipx_lb = gtk_label_new("IPX: 0 (0.0%)");
635   gtk_box_pack_start(GTK_BOX(main_vb), ipx_lb, FALSE, FALSE, 3);
636   gtk_widget_show(ipx_lb);
637
638   other_lb = gtk_label_new("Other: 0 (0.0%)");
639   gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
640   gtk_widget_show(other_lb);
641
642   stop_bt = gtk_button_new_with_label ("Stop");
643   gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
644     GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
645   gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
646   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
647   gtk_widget_grab_default(stop_bt);
648   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
649   gtk_widget_grab_default(stop_bt);
650   gtk_widget_show(stop_bt);
651
652   gtk_widget_show(cap_w);
653   gtk_grab_add(cap_w);
654
655   upd_time = time(NULL);
656   while (ld.go) {
657     while (gtk_events_pending()) gtk_main_iteration();
658     inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
659     if (inpkts > 0)
660       ld.sync_packets += inpkts;
661     /* Only update once a second so as not to overload slow displays */
662     cur_time = time(NULL);
663     if (cur_time > upd_time) {
664       upd_time = cur_time;
665
666       sprintf(label_str, "Count: %d", ld.counts.total);
667       gtk_label_set(GTK_LABEL(count_lb), label_str);
668
669       sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
670                 pct(ld.counts.tcp, ld.counts.total));
671       gtk_label_set(GTK_LABEL(tcp_lb), label_str);
672
673       sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
674                 pct(ld.counts.udp, ld.counts.total));
675       gtk_label_set(GTK_LABEL(udp_lb), label_str);
676
677       sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
678                 pct(ld.counts.icmp, ld.counts.total));
679       gtk_label_set(GTK_LABEL(icmp_lb), label_str);
680
681       sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
682                 pct(ld.counts.ospf, ld.counts.total));
683       gtk_label_set(GTK_LABEL(ospf_lb), label_str);
684
685       sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
686                 pct(ld.counts.gre, ld.counts.total));
687       gtk_label_set(GTK_LABEL(gre_lb), label_str);
688
689       sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
690                 pct(ld.counts.netbios, ld.counts.total));
691       gtk_label_set(GTK_LABEL(netbios_lb), label_str);
692
693       sprintf(label_str, "IPX: %d (%.1f%%)", ld.counts.ipx,
694                 pct(ld.counts.ipx, ld.counts.total));
695       gtk_label_set(GTK_LABEL(ipx_lb), label_str);
696
697       sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
698                 pct(ld.counts.other, ld.counts.total));
699       gtk_label_set(GTK_LABEL(other_lb), label_str);
700
701       /* do sync here, too */
702       fflush(wtap_dump_file(ld.pdh));
703       if (capture_child && ld.sync_packets) {
704         /* This is the child process for a sync mode capture, so send
705            our parent a message saying we've written out "ld.sync_packets"
706            packets to the capture file. */
707         char tmp[20];
708         sprintf(tmp, "%d*", ld.sync_packets);
709         write(1, tmp, strlen(tmp));
710         ld.sync_packets = 0;
711       }
712     }
713   }
714     
715   if (!wtap_dump_close(ld.pdh, &err)) {
716     /* XXX - in fork mode, this may not pop up, or, if it does,
717        it may disappear as soon as we exit.
718
719        We should have the parent process, while it's reading
720        the packet count update messages, catch error messages
721        and pop up a message box if it sees one. */
722     switch (err) {
723
724     case WTAP_ERR_CANT_CLOSE:
725       simple_dialog(ESD_TYPE_WARN, NULL,
726                 "The file to which the capture was being saved"
727                 " couldn't be closed for some unknown reason.");
728       break;
729
730     case WTAP_ERR_SHORT_WRITE:
731       simple_dialog(ESD_TYPE_WARN, NULL,
732                 "Not all the data could be written to the file"
733                 " to which the capture was being saved.");
734       break;
735
736     default:
737       simple_dialog(ESD_TYPE_WARN, NULL,
738                 "The file to which the capture was being"
739                 " saved (\"%s\") could not be closed: %s.",
740                 cf.save_file, wtap_strerror(err));
741       break;
742     }
743   }
744   pcap_close(pch);
745
746   gtk_grab_remove(GTK_WIDGET(cap_w));
747   gtk_widget_destroy(GTK_WIDGET(cap_w));
748
749   return TRUE;
750
751 error:
752   /* We couldn't even start the capture, so get rid of the capture
753      file. */
754   unlink(cf.save_file); /* silently ignore error */
755   g_free(cf.save_file);
756   cf.save_file = NULL;
757   if (capture_child) {
758     /* This is the child process for a sync mode capture.
759        Send the error message to our parent, so they can display a
760        dialog box containing it. */
761     int msglen = strlen(errmsg);
762     char lenbuf[10+1+1];
763     sprintf(lenbuf, "%u;", msglen);
764     write(1, lenbuf, strlen(lenbuf));
765     write(1, errmsg, msglen);
766   } else {
767     /* Display the dialog box ourselves; there's no parent. */
768     simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
769   }
770   if (pch != NULL)
771     pcap_close(pch);
772
773   return FALSE;
774 }
775
776 static float
777 pct(gint num, gint denom) {
778   if (denom) {
779     return (float) num * 100.0 / (float) denom;
780   } else {
781     return 0.0;
782   }
783 }
784
785 static void
786 capture_stop_cb(GtkWidget *w, gpointer data) {
787   loop_data *ld = (loop_data *) data;
788   
789   ld->go = FALSE;
790 }
791
792 static void
793 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
794   const u_char *pd) {
795   struct wtap_pkthdr whdr;
796   loop_data *ld = (loop_data *) user;
797   int err;
798
799   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
800   {
801      ld->go = FALSE;
802   }
803   if (ld->pdh) {
804      whdr.ts = phdr->ts;
805      whdr.caplen = phdr->caplen;
806      whdr.len = phdr->len;
807      whdr.pkt_encap = ld->linktype;
808
809      /* XXX - do something if this fails */
810      wtap_dump(ld->pdh, &whdr, pd, &err);
811   }
812     
813   switch (ld->linktype) {
814     case WTAP_ENCAP_ETHERNET:
815       capture_eth(pd, phdr->caplen, &ld->counts);
816       break;
817     case WTAP_ENCAP_FDDI:
818     case WTAP_ENCAP_FDDI_BITSWAPPED:
819       capture_fddi(pd, phdr->caplen, &ld->counts);
820       break;
821     case WTAP_ENCAP_TR:
822       capture_tr(pd, phdr->caplen, &ld->counts);
823       break;
824     case WTAP_ENCAP_NULL:
825       capture_null(pd, phdr->caplen, &ld->counts);
826       break;
827     case WTAP_ENCAP_PPP:
828       capture_ppp(pd, phdr->caplen, &ld->counts);
829       break;
830     case WTAP_ENCAP_RAW_IP:
831       capture_raw(pd, phdr->caplen, &ld->counts);
832       break;
833     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
834        with LLC header following; we should implement it at some
835        point. */
836   }
837 }
838
839 #endif /* HAVE_LIBPCAP */