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