More shuffling of GTK-related files to gtk subdirectory.
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.65 1999/09/09 02:42:22 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 #include <gtk/gtk.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #include <time.h>
51
52 #ifdef HAVE_SYS_SOCKET_H
53 #include <sys/socket.h>
54 #endif
55
56 #ifdef HAVE_SYS_IOCTL_H
57 #include <sys/ioctl.h>
58 #endif
59
60 #ifdef HAVE_NET_IF_H
61 #include <net/if.h>
62 #endif
63
64 #include <signal.h>
65 #include <errno.h>
66
67 #ifdef NEED_SNPRINTF_H
68 # ifdef HAVE_STDARG_H
69 #  include <stdarg.h>
70 # else
71 #  include <varargs.h>
72 # endif
73 # include "snprintf.h"
74 #endif
75
76 #ifdef HAVE_SYS_SOCKIO_H
77 # include <sys/sockio.h>
78 #endif
79
80 #include "gtk/main.h"
81 #include "packet.h"
82 #include "file.h"
83 #include "gtk/menu.h"
84 #include "capture.h"
85 #include "util.h"
86 #include "prefs.h"
87
88 extern capture_file  cf;
89 extern GtkWidget    *info_bar;
90 extern guint         file_ctx;
91
92 extern gchar *ethereal_path;
93 extern gchar *medium_font;
94 extern gchar *bold_font;
95 extern int fork_mode;
96 extern int sync_pipe[];
97 extern int sync_mode;
98 extern int sigusr2_received;
99 extern int quit_after_cap;
100
101 /* Capture callback data keys */
102 #define E_CAP_IFACE_KEY "cap_iface"
103 #define E_CAP_FILT_KEY  "cap_filter"
104 #define E_CAP_COUNT_KEY "cap_count"
105 #define E_CAP_OPEN_KEY  "cap_open"
106 #define E_CAP_SNAP_KEY  "cap_snap"
107
108 /* Capture filter key */
109 #define E_CAP_FILT_TE_KEY "cap_filt_te"
110
111 static void search_for_if_cb(gpointer data, gpointer user_data);
112 static void free_if_cb(gpointer data, gpointer user_data);
113 static void capture_prep_ok_cb(GtkWidget *, gpointer);
114 static void capture_prep_close_cb(GtkWidget *, gpointer);
115 static float pct(gint, gint);
116 static void capture_stop_cb(GtkWidget *, gpointer);
117 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
118   const u_char *);
119
120 struct search_user_data {
121         char    *name;
122         int     found;
123 };
124
125 static GList *
126 get_interface_list() {
127   GList  *il = NULL;
128   gint    nonloopback_pos = 0;
129   struct  ifreq *ifr, *last;
130   struct  ifconf ifc;
131   struct  ifreq ifrflags;
132   int     sock = socket(AF_INET, SOCK_DGRAM, 0);
133   struct search_user_data user_data;
134   pcap_t *pch;
135   gchar   err_str[PCAP_ERRBUF_SIZE];
136
137   if (sock < 0)
138   {
139     simple_dialog(ESD_TYPE_WARN, NULL,
140       "Can't list interfaces: error opening socket.");
141     return NULL;
142   }
143
144   /* Since we have to grab the interface list all at once, we'll make
145      plenty of room */
146   ifc.ifc_len = 1024 * sizeof(struct ifreq);
147   ifc.ifc_buf = malloc(ifc.ifc_len);
148
149   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
150     ifc.ifc_len < sizeof(struct ifreq))
151   {
152     simple_dialog(ESD_TYPE_WARN, NULL,
153       "Can't list interfaces: SIOCGIFCONF error: %s", strerror(errno));
154     goto fail;
155   }
156
157   ifr  = (struct ifreq *) ifc.ifc_req;
158   last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
159   while (ifr < last)
160   {
161     /*
162      * Skip addresses that begin with "dummy", or that include a ":"
163      * (the latter are Solaris virtuals).
164      */
165     if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
166         strchr(ifr->ifr_name, ':') != NULL)
167       goto next;
168
169     /*
170      * If we already have this interface name on the list, don't add
171      * it (SIOCGIFCONF returns, at least on BSD-flavored systems, one
172      * entry per interface *address*; if an interface has multiple
173      * addresses, we get multiple entries for it).
174      */
175     user_data.name = ifr->ifr_name;
176     user_data.found = FALSE;
177     g_list_foreach(il, search_for_if_cb, &user_data);
178     if (user_data.found)
179       goto next;
180
181     /*
182      * Get the interface flags.
183      */
184     memset(&ifrflags, 0, sizeof ifrflags);
185     strncpy(ifrflags.ifr_name, ifr->ifr_name, sizeof ifrflags.ifr_name);
186     if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
187       if (errno == ENXIO)
188         goto next;
189       simple_dialog(ESD_TYPE_WARN, NULL,
190         "Can't list interfaces: SIOCGIFFLAGS error on %s: %s",
191         ifr->ifr_name, strerror(errno));
192       goto fail;
193     }
194
195     /*
196      * Skip interfaces that aren't up.
197      */
198     if (!(ifrflags.ifr_flags & IFF_UP))
199       goto next;
200
201     /*
202      * Skip interfaces that we can't open with "libpcap".
203      */
204     pch = pcap_open_live(ifr->ifr_name, WTAP_MAX_PACKET_SIZE, 0, 0, err_str);
205     if (pch == NULL)
206       goto next;
207     pcap_close(pch);
208
209     /*
210      * If it's a loopback interface, add it at the end of the list,
211      * otherwise add it after the last non-loopback interface,
212      * so all loopback interfaces go at the end - we don't want a
213      * loopback interface to be the default capture device unless there
214      * are no non-loopback devices.
215      */
216     if ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
217         strncmp(ifr->ifr_name, "lo", 2) == 0)
218       il = g_list_insert(il, g_strdup(ifr->ifr_name), -1);
219     else {
220       il = g_list_insert(il, g_strdup(ifr->ifr_name), nonloopback_pos);
221       /* Insert the next non-loopback interface after this one. */
222       nonloopback_pos++;
223     }
224
225 next:
226 #ifdef HAVE_SA_LEN
227     ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
228 #else
229     ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
230 #endif
231   }
232
233   free(ifc.ifc_buf);
234   close(sock);
235
236   if (il == NULL) {
237     simple_dialog(ESD_TYPE_WARN, NULL,
238       "There are no network interfaces that can be opened.\n"
239       "Please check to make sure you have sufficient permission\n"
240       "to capture packets.");
241     return NULL;
242   }
243
244   return il;
245
246 fail:
247   if (il != NULL) {
248     g_list_foreach(il, free_if_cb, NULL);
249     g_list_free(il);
250   }
251   free(ifc.ifc_buf);
252   close(sock);
253   return NULL;
254 }
255
256 static void
257 search_for_if_cb(gpointer data, gpointer user_data)
258 {
259         struct search_user_data *search_user_data = user_data;
260
261         if (strcmp((char *)data, search_user_data->name) == 0)
262                 search_user_data->found = TRUE;
263 }
264
265 static void
266 free_if_cb(gpointer data, gpointer user_data)
267 {
268         g_free(data);
269 }
270
271 void
272 capture_prep_cb(GtkWidget *w, gpointer d) {
273   GtkWidget     *cap_open_w, *if_cb, *if_lb,
274                 *count_lb, *count_cb, *main_vb, *if_hb, *count_hb,
275                 *filter_hb, *filter_bt, *filter_te, *caplen_hb,
276                 *bbox, *ok_bt, *cancel_bt, *snap_lb,
277                 *snap_sb;
278   GtkAdjustment *adj;
279   GList         *if_list, *count_list = NULL;
280   gchar         *count_item1 = "0 (Infinite)", count_item2[16];
281
282   if_list = get_interface_list();
283   if (if_list == NULL)
284     return;
285   
286   cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
287   gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences");
288   
289   /* Container for each row of widgets */
290   main_vb = gtk_vbox_new(FALSE, 3);
291   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
292   gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
293   gtk_widget_show(main_vb);
294   
295   /* Interface row */
296   if_hb = gtk_hbox_new(FALSE, 3);
297   gtk_container_add(GTK_CONTAINER(main_vb), if_hb);
298   gtk_widget_show(if_hb);
299   
300   if_lb = gtk_label_new("Interface:");
301   gtk_box_pack_start(GTK_BOX(if_hb), if_lb, FALSE, FALSE, 0);
302   gtk_widget_show(if_lb);
303   
304   if_cb = gtk_combo_new();
305   gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
306   if (cf.iface)
307     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cf.iface);
308   else if (if_list)
309     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data);
310   gtk_box_pack_start(GTK_BOX(if_hb), if_cb, FALSE, FALSE, 0);
311   gtk_widget_show(if_cb);
312   
313   while (if_list) {
314     g_free(if_list->data);
315     if_list = g_list_remove_link(if_list, if_list);
316   }
317
318   /* Count row */
319   count_hb = gtk_hbox_new(FALSE, 3);
320   gtk_container_add(GTK_CONTAINER(main_vb), count_hb);
321   gtk_widget_show(count_hb);
322   
323   count_lb = gtk_label_new("Count:");
324   gtk_box_pack_start(GTK_BOX(count_hb), count_lb, FALSE, FALSE, 0);
325   gtk_widget_show(count_lb);
326   
327   count_list = g_list_append(count_list, count_item1);
328   if (cf.count) {
329     snprintf(count_item2, 15, "%d", cf.count);
330     count_list = g_list_append(count_list, count_item2);
331   }
332
333   count_cb = gtk_combo_new();
334   gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list);
335   gtk_box_pack_start(GTK_BOX(count_hb), count_cb, FALSE, FALSE, 0);
336   gtk_widget_show(count_cb);
337
338   while (count_list)
339     count_list = g_list_remove_link(count_list, count_list);
340
341   /* Filter row */
342   filter_hb = gtk_hbox_new(FALSE, 3);
343   gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
344   gtk_widget_show(filter_hb);
345   
346   filter_bt = gtk_button_new_with_label("Filter:");
347   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
348     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
349   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
350   gtk_widget_show(filter_bt);
351   
352   filter_te = gtk_entry_new();
353   if (cf.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.cfilter);
354   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
355   gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
356   gtk_widget_show(filter_te);
357
358   /* Misc row: Capture file checkbox and snap spinbutton */
359   caplen_hb = gtk_hbox_new(FALSE, 3);
360   gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
361   gtk_widget_show(caplen_hb);
362
363   snap_lb = gtk_label_new("Capture length");
364   gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5);
365   gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
366   gtk_widget_show(snap_lb);
367
368   adj = (GtkAdjustment *) gtk_adjustment_new((float) cf.snap,
369     MIN_PACKET_SIZE, WTAP_MAX_PACKET_SIZE, 1.0, 10.0, 0.0);
370   snap_sb = gtk_spin_button_new (adj, 0, 0);
371   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
372   gtk_widget_set_usize (snap_sb, 80, 0);
373   gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3); 
374   gtk_widget_show(snap_sb);
375   
376   /* Button row: OK and cancel buttons */
377   bbox = gtk_hbutton_box_new();
378   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
379   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
380   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
381   gtk_widget_show(bbox);
382
383   ok_bt = gtk_button_new_with_label ("OK");
384   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
385     GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w));
386   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
387   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
388   gtk_widget_grab_default(ok_bt);
389   gtk_widget_show(ok_bt);
390
391   cancel_bt = gtk_button_new_with_label ("Cancel");
392   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
393     GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w));
394   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
395   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
396   gtk_widget_show(cancel_bt);
397
398   /* Attach pointers to needed widgets to the capture prefs window/object */
399   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_IFACE_KEY, if_cb);
400   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILT_KEY,  filter_te);
401   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_COUNT_KEY, count_cb);
402   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SNAP_KEY,  snap_sb);
403
404   gtk_widget_show(cap_open_w);
405 }
406
407 static void
408 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
409   GtkWidget *if_cb, *filter_te, *count_cb, *snap_sb;
410   gchar *filter_text;
411   char tmpname[128+1];
412
413   if_cb     = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY);
414   filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY);
415   count_cb  = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_COUNT_KEY);
416   snap_sb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SNAP_KEY);
417
418   if (cf.iface) g_free(cf.iface);
419   cf.iface =
420     g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
421
422   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
423   if (cf.cfilter) g_free(cf.cfilter);
424   cf.cfilter = NULL; /* ead 06/16/99 */
425   if (filter_text && filter_text[0]) {
426           cf.cfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); 
427   }
428   cf.count = atoi(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)));
429   cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
430   if (cf.snap < 1)
431     cf.snap = WTAP_MAX_PACKET_SIZE;
432   else if (cf.snap < MIN_PACKET_SIZE)
433     cf.snap = MIN_PACKET_SIZE;
434
435   gtk_widget_destroy(GTK_WIDGET(parent_w));
436
437   /* Choose a random name for the capture buffer */
438   if (cf.save_file && !cf.user_saved) {
439         unlink(cf.save_file); /* silently ignore error */
440         g_free(cf.save_file);
441   }
442   cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
443   cf.save_file = g_strdup(tmpname);
444   cf.user_saved = 0;
445   
446   if( fork_mode ){      /*  use fork() for capture */
447     int  fork_child;
448     char ssnap[24];
449     char scount[24];    /* need a constant for len of numbers */
450     char save_file_fd[24];
451     int err;
452
453     sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
454     sprintf(scount,"%d",cf.count);
455     sprintf(save_file_fd,"%d",cf.save_file_fd);
456     signal(SIGCHLD, SIG_IGN);
457     if (sync_mode) pipe(sync_pipe);
458     if((fork_child = fork()) == 0){
459       /* args: -k -- capture
460        * -i interface specification
461        * -w file to write
462        * -W file descriptor to write
463        * -c count to capture
464        * -Q quit after capture (forces -k)
465        * -s snaplen
466        * -S sync mode
467        * -m / -b fonts
468        * -f "filter expression"
469        */
470        if (sync_mode) {
471          close(1);
472          dup(sync_pipe[1]);
473          close(sync_pipe[0]);
474          execlp(ethereal_path, "ethereal", "-k", "-Q", "-i", cf.iface,
475                 "-w", cf.save_file, "-W", save_file_fd,
476                 "-c", scount, "-s", ssnap, "-S", 
477                 "-m", medium_font, "-b", bold_font,
478                 (cf.cfilter == NULL)? 0 : "-f",
479                 (cf.cfilter == NULL)? 0 : cf.cfilter,
480                 (const char *)NULL);    
481        }
482        else {
483          execlp(ethereal_path, "ethereal", "-k", "-Q", "-i", cf.iface,
484                 "-w", cf.save_file, "-W", save_file_fd,
485                 "-c", scount, "-s", ssnap,
486                 "-m", medium_font, "-b", bold_font,
487                 (cf.cfilter == NULL)? 0 : "-f",
488                 (cf.cfilter == NULL)? 0 : cf.cfilter,
489                 (const char *)NULL);
490        }
491     }
492     else {
493        cf.filename = cf.save_file;
494        if (sync_mode) {
495          close(sync_pipe[1]);
496          while (!sigusr2_received) {
497            struct timeval timeout = {1,0};
498            select(0, NULL, NULL, NULL, &timeout);
499            if (kill(fork_child, 0) == -1 && errno == ESRCH) 
500              break;
501          }
502          if (sigusr2_received) {
503            err = tail_cap_file(cf.save_file, &cf);
504            if (err != 0) {
505              simple_dialog(ESD_TYPE_WARN, NULL,
506                         file_open_error_message(err, FALSE), cf.save_file);
507            }
508          }
509          sigusr2_received = FALSE;
510        }
511     }
512   }
513   else
514     capture();
515 }
516
517 static void
518 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w)
519 {
520   gtk_grab_remove(GTK_WIDGET(parent_w));
521   gtk_widget_destroy(GTK_WIDGET(parent_w));
522 }
523
524 typedef struct _loop_data {
525   gint           go;
526   gint           max;
527   gint           linktype;
528   gint           sync_packets;
529   packet_counts  counts;
530   wtap_dumper   *pdh;
531 } loop_data;
532
533 void
534 capture(void) {
535   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
536              *ospf_lb, *gre_lb, *netbios_lb, *other_lb, *stop_bt;
537   pcap_t     *pch;
538   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
539   loop_data   ld;
540   bpf_u_int32 netnum, netmask;
541   time_t      upd_time, cur_time;
542   int         err, inpkts;
543   char       *errmsg;
544   char        errmsg_errno[1024+1];
545
546   ld.go             = TRUE;
547   ld.counts.total   = 0;
548   ld.max            = cf.count;
549   ld.linktype       = WTAP_ENCAP_UNKNOWN;
550   ld.sync_packets   = 0;
551   ld.counts.tcp     = 0;
552   ld.counts.udp     = 0;
553   ld.counts.icmp    = 0;
554   ld.counts.ospf    = 0;
555   ld.counts.gre     = 0;
556   ld.counts.netbios = 0;
557   ld.counts.other   = 0;
558   ld.pdh            = NULL;
559
560   close_cap_file(&cf, info_bar, file_ctx);
561
562   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
563
564   if (pch) {
565     ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
566     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
567       errmsg = "The network you're capturing from is of a type"
568                " that Ethereal doesn't support.";
569       goto fail;
570     }
571     ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
572                 ld.linktype, pcap_snapshot(pch), &err);
573
574     if (ld.pdh == NULL) {  /* We have an error */
575       switch (err) {
576
577       case WTAP_ERR_CANT_OPEN:
578         errmsg = "The file to which the capture would be saved"
579                  " couldn't be created for some unknown reason.";
580         break;
581
582       case WTAP_ERR_SHORT_WRITE:
583         errmsg = "A full header couldn't be written to the file"
584                  " to which the capture would be saved.";
585         break;
586
587       default:
588         if (err < 0) {
589           sprintf(errmsg_errno, "The file to which the capture would be"
590                               " saved (\"%%s\") could not be opened: Error %d.",
591                                 err);
592         } else {
593           sprintf(errmsg_errno, "The file to which the capture would be"
594                               " saved (\"%%s\") could not be opened: %s.",
595                                 strerror(err));
596         }
597         errmsg = errmsg_errno;
598         break;
599       }
600 fail:
601       snprintf(err_str, PCAP_ERRBUF_SIZE, errmsg, cf.save_file);
602       simple_dialog(ESD_TYPE_WARN, NULL, err_str);
603       pcap_close(pch);
604       return;
605     }
606
607     if (cf.cfilter) {
608       if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
609         simple_dialog(ESD_TYPE_WARN, NULL,
610           "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
611         wtap_dump_close(ld.pdh, NULL);
612         unlink(cf.save_file); /* silently ignore error */
613         pcap_close(pch);
614         return;
615       } else if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
616         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string (%s).",
617                         pcap_geterr(pch));
618         wtap_dump_close(ld.pdh, NULL);
619         unlink(cf.save_file); /* silently ignore error */
620         pcap_close(pch);
621         return;
622       } else if (pcap_setfilter(pch, &cf.fcode) < 0) {
623         simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter (%s).",
624                         pcap_geterr(pch));
625         wtap_dump_close(ld.pdh, NULL);
626         unlink(cf.save_file); /* silently ignore error */
627         pcap_close(pch);
628         return;
629       }
630     }
631
632     if (sync_mode) {
633       /* Sync out the capture file, so the header makes it to the file
634          system, and signal our parent so that they'll open the capture
635          file and update its windows to indicate that we have a live
636          capture in progress. */
637       fflush(wtap_dump_file(ld.pdh));
638       kill(getppid(), SIGUSR2);
639     }
640
641     cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
642     gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
643
644     /* Container for capture display widgets */
645     main_vb = gtk_vbox_new(FALSE, 1);
646     gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
647     gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
648     gtk_widget_show(main_vb);
649
650     count_lb = gtk_label_new("Count: 0");
651     gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
652     gtk_widget_show(count_lb);
653
654     tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
655     gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
656     gtk_widget_show(tcp_lb);
657
658     udp_lb = gtk_label_new("UDP: 0 (0.0%)");
659     gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
660     gtk_widget_show(udp_lb);
661
662     icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
663     gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
664     gtk_widget_show(icmp_lb);
665
666     ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
667     gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
668     gtk_widget_show(ospf_lb);
669
670     gre_lb = gtk_label_new("GRE: 0 (0.0%)");
671     gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
672     gtk_widget_show(gre_lb);
673
674     netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
675     gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
676     gtk_widget_show(netbios_lb);
677
678     other_lb = gtk_label_new("Other: 0 (0.0%)");
679     gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
680     gtk_widget_show(other_lb);
681
682     stop_bt = gtk_button_new_with_label ("Stop");
683     gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
684       GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
685     gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
686     GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
687     gtk_widget_grab_default(stop_bt);
688     GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
689     gtk_widget_grab_default(stop_bt);
690     gtk_widget_show(stop_bt);
691
692     gtk_widget_show(cap_w);
693     gtk_grab_add(cap_w);
694
695     upd_time = time(NULL);
696     while (ld.go) {
697       while (gtk_events_pending()) gtk_main_iteration();
698       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
699       if (inpkts > 0)
700         ld.sync_packets += inpkts;
701       /* Only update once a second so as not to overload slow displays */
702       cur_time = time(NULL);
703       if (cur_time > upd_time) {
704
705         upd_time = cur_time;
706
707         sprintf(label_str, "Count: %d", ld.counts.total);
708         gtk_label_set(GTK_LABEL(count_lb), label_str);
709
710         sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
711            pct(ld.counts.tcp, ld.counts.total));
712         gtk_label_set(GTK_LABEL(tcp_lb), label_str);
713
714         sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
715           pct(ld.counts.udp, ld.counts.total));
716         gtk_label_set(GTK_LABEL(udp_lb), label_str);
717
718         sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
719           pct(ld.counts.icmp, ld.counts.total));
720         gtk_label_set(GTK_LABEL(icmp_lb), label_str);
721
722         sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
723           pct(ld.counts.ospf, ld.counts.total));
724         gtk_label_set(GTK_LABEL(ospf_lb), label_str);
725
726         sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
727           pct(ld.counts.gre, ld.counts.total));
728         gtk_label_set(GTK_LABEL(gre_lb), label_str);
729
730         sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
731           pct(ld.counts.netbios, ld.counts.total));
732         gtk_label_set(GTK_LABEL(netbios_lb), label_str);
733
734         sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
735           pct(ld.counts.other, ld.counts.total));
736         gtk_label_set(GTK_LABEL(other_lb), label_str);
737
738         /* do sync here, too */
739         fflush(wtap_dump_file(ld.pdh));
740         if (sync_mode && ld.sync_packets) {
741           char tmp[20];
742           sprintf(tmp, "%d*", ld.sync_packets);
743           write(1, tmp, strlen(tmp));
744           ld.sync_packets = 0;
745         }
746       }
747     }
748     
749     if (ld.pdh) {
750       if (!wtap_dump_close(ld.pdh, &err)) {
751         switch (err) {
752
753         case WTAP_ERR_CANT_CLOSE:
754           errmsg = "The file to which the capture was being saved"
755                  " couldn't be closed for some unknown reason.";
756           break;
757
758         case WTAP_ERR_SHORT_WRITE:
759           errmsg = "Not all the data could be written to the file"
760                    " to which the capture was being saved.";
761           break;
762
763         default:
764           if (err < 0) {
765             sprintf(errmsg_errno, "The file to which the capture was being"
766                               " saved (\"%%s\") could not be closed: Error %d.",
767                                 err);
768           } else {
769             sprintf(errmsg_errno, "The file to which the capture was being"
770                               " saved (\"%%s\") could not be closed: %s.",
771                                 strerror(err));
772           }
773           errmsg = errmsg_errno;
774           break;
775         }
776         snprintf(err_str, PCAP_ERRBUF_SIZE, errmsg, cf.save_file);
777         simple_dialog(ESD_TYPE_WARN, NULL, err_str);
778       }
779     }
780     pcap_close(pch);
781
782     gtk_grab_remove(GTK_WIDGET(cap_w));
783     gtk_widget_destroy(GTK_WIDGET(cap_w));
784   } else {
785     while (gtk_events_pending()) gtk_main_iteration();
786     simple_dialog(ESD_TYPE_WARN, NULL,
787       "The capture session could not be initiated (%s).\n"
788       "Please check to make sure you have sufficient permissions, and that\n"
789       "you have the proper interface specified.", err_str);
790   }
791
792   if( quit_after_cap ){
793     /* DON'T unlink the save file.  Presumably someone wants it. */
794     gtk_exit(0);
795   }
796
797   if (pch) {
798     /* "pch" is non-NULL only if we successfully started a capture.
799        If we haven't, there's no capture file to load. */
800     if ((err = open_cap_file(cf.save_file, &cf)) == 0) {
801       /* Set the read filter to NULL. */
802       cf.rfcode = NULL;
803       err = read_cap_file(&cf);
804       set_menu_sensitivity("/File/Save", TRUE);
805       set_menu_sensitivity("/File/Save As...", FALSE);
806     }
807   }
808 }
809
810 static float
811 pct(gint num, gint denom) {
812   if (denom) {
813     return (float) num * 100.0 / (float) denom;
814   } else {
815     return 0.0;
816   }
817 }
818
819 static void
820 capture_stop_cb(GtkWidget *w, gpointer data) {
821   loop_data *ld = (loop_data *) data;
822   
823   ld->go = FALSE;
824 }
825
826 static void
827 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
828   const u_char *pd) {
829   struct wtap_pkthdr whdr;
830   loop_data *ld = (loop_data *) user;
831   int err;
832
833   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
834   {
835      ld->go = FALSE;
836   }
837   if (ld->pdh) {
838      whdr.ts = phdr->ts;
839      whdr.caplen = phdr->caplen;
840      whdr.len = phdr->len;
841      whdr.pkt_encap = ld->linktype;
842
843      /* XXX - do something if this fails */
844      wtap_dump(ld->pdh, &whdr, pd, &err);
845   }
846     
847   switch (ld->linktype) {
848     case WTAP_ENCAP_ETHERNET:
849       capture_eth(pd, phdr->caplen, &ld->counts);
850       break;
851     case WTAP_ENCAP_FDDI:
852     case WTAP_ENCAP_FDDI_BITSWAPPED:
853       capture_fddi(pd, phdr->caplen, &ld->counts);
854       break;
855     case WTAP_ENCAP_TR:
856       capture_tr(pd, phdr->caplen, &ld->counts);
857       break;
858     case WTAP_ENCAP_NULL:
859       capture_null(pd, phdr->caplen, &ld->counts);
860       break;
861     case WTAP_ENCAP_PPP:
862       capture_ppp(pd, phdr->caplen, &ld->counts);
863       break;
864     case WTAP_ENCAP_RAW_IP:
865       capture_raw(pd, phdr->caplen, &ld->counts);
866       break;
867     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
868        with LLC header following; we should implement it at some
869        point. */
870   }
871 }
872
873 #endif /* HAVE_LIBPCAP */