Fix the -S option timeout handling:
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.43 1999/08/10 11:08:38 deniel 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 "ethereal.h"
81 #include "packet.h"
82 #include "file.h"
83 #include "menu.h"
84 #include "capture.h"
85 #include "etypes.h"
86 #include "util.h"
87 #include "prefs.h"
88
89 extern capture_file  cf;
90 extern GtkWidget    *info_bar;
91 extern guint         file_ctx;
92
93 extern gchar *ethereal_path;
94 extern gchar *medium_font;
95 extern gchar *bold_font;
96 extern int fork_mode;
97 extern int sync_pipe[];
98 extern int sync_mode;
99 extern int sigusr2_received;
100 extern int quit_after_cap;
101
102 /* Capture callback data keys */
103 #define E_CAP_IFACE_KEY "cap_iface"
104 #define E_CAP_FILT_KEY  "cap_filter"
105 #define E_CAP_COUNT_KEY "cap_count"
106 #define E_CAP_OPEN_KEY  "cap_open"
107 #define E_CAP_SNAP_KEY  "cap_snap"
108
109 /* Capture filter key */
110 #define E_CAP_FILT_TE_KEY "cap_filt_te"
111
112 static void capture_prep_ok_cb(GtkWidget *, gpointer);
113 static void capture_prep_close_cb(GtkWidget *, gpointer);
114 static float pct(gint, gint);
115 static void capture_stop_cb(GtkWidget *, gpointer);
116 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
117   const u_char *);
118
119 static GList *
120 get_interface_list() {
121   GList  *il = NULL;
122   struct  ifreq *ifr, *last;
123   struct  ifconf ifc;
124   int     sock = socket(AF_INET, SOCK_DGRAM, 0);
125
126   if (sock < 0)
127   {
128     simple_dialog(ESD_TYPE_WARN, NULL,
129       "Can't list interfaces: error opening socket.");
130     return NULL;
131   }
132
133   /* Since we have to grab the interface list all at once, we'll make
134      plenty of room */
135   ifc.ifc_len = 1024 * sizeof(struct ifreq);
136   ifc.ifc_buf = malloc(ifc.ifc_len);
137
138   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ||
139     ifc.ifc_len < sizeof(struct ifreq))
140   {
141     simple_dialog(ESD_TYPE_WARN, NULL,
142       "Can't list interfaces: ioctl error.");
143     return NULL;
144   }
145
146   ifr  = (struct ifreq *) ifc.ifc_req;
147   last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
148   while (ifr < last)
149   {
150     /*
151      * What we want:
152      * - Interfaces that are up, and not loopback
153      * - IP interfaces (do we really need this?)
154      * - Anything that doesn't begin with "lo" (loopback again) or "dummy"
155      * - Anything that doesn't include a ":" (Solaris virtuals)
156      */
157     if (! (ifr->ifr_flags & (IFF_UP | IFF_LOOPBACK)) &&
158         (ifr->ifr_addr.sa_family == AF_INET) &&
159         strncmp(ifr->ifr_name, "lo", 2) &&
160         strncmp(ifr->ifr_name, "dummy", 5) &&
161         ! strchr(ifr->ifr_name, ':')) {
162       il = g_list_append(il, g_strdup(ifr->ifr_name));
163     }
164 #ifdef HAVE_SA_LEN
165     ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
166 #else
167     ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
168 #endif
169   }
170
171   free(ifc.ifc_buf);
172   return il;
173 }
174
175 void
176 capture_prep_cb(GtkWidget *w, gpointer d) {
177   GtkWidget     *cap_open_w, *if_cb, *if_lb,
178                 *count_lb, *count_cb, *main_vb, *if_hb, *count_hb,
179                 *filter_hb, *filter_bt, *filter_te, *caplen_hb,
180                 *bbox, *ok_bt, *cancel_bt, *snap_lb,
181                 *snap_sb;
182   GtkAdjustment *adj;
183   GList         *if_list, *count_list = NULL;
184   gchar         *count_item1 = "0 (Infinite)", count_item2[16];
185
186   cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
187   gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences");
188   
189   /* Container for each row of widgets */
190   main_vb = gtk_vbox_new(FALSE, 3);
191   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
192   gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb);
193   gtk_widget_show(main_vb);
194   
195   /* Interface row */
196   if_hb = gtk_hbox_new(FALSE, 3);
197   gtk_container_add(GTK_CONTAINER(main_vb), if_hb);
198   gtk_widget_show(if_hb);
199   
200   if_lb = gtk_label_new("Interface:");
201   gtk_box_pack_start(GTK_BOX(if_hb), if_lb, FALSE, FALSE, 0);
202   gtk_widget_show(if_lb);
203   
204   if_list = get_interface_list();
205   
206   if_cb = gtk_combo_new();
207   gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
208   if (cf.iface)
209     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cf.iface);
210   else if (if_list)
211     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data);
212   gtk_box_pack_start(GTK_BOX(if_hb), if_cb, FALSE, FALSE, 0);
213   gtk_widget_show(if_cb);
214   
215   while (if_list) {
216     g_free(if_list->data);
217     if_list = g_list_remove_link(if_list, if_list);
218   }
219
220   /* Count row */
221   count_hb = gtk_hbox_new(FALSE, 3);
222   gtk_container_add(GTK_CONTAINER(main_vb), count_hb);
223   gtk_widget_show(count_hb);
224   
225   count_lb = gtk_label_new("Count:");
226   gtk_box_pack_start(GTK_BOX(count_hb), count_lb, FALSE, FALSE, 0);
227   gtk_widget_show(count_lb);
228   
229   count_list = g_list_append(count_list, count_item1);
230   if (cf.count) {
231     snprintf(count_item2, 15, "%d", cf.count);
232     count_list = g_list_append(count_list, count_item2);
233   }
234
235   count_cb = gtk_combo_new();
236   gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list);
237   gtk_box_pack_start(GTK_BOX(count_hb), count_cb, FALSE, FALSE, 0);
238   gtk_widget_show(count_cb);
239
240   while (count_list)
241     count_list = g_list_remove_link(count_list, count_list);
242
243   /* Filter row */
244   filter_hb = gtk_hbox_new(FALSE, 3);
245   gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
246   gtk_widget_show(filter_hb);
247   
248   filter_bt = gtk_button_new_with_label("Filter:");
249   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
250     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
251   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
252   gtk_widget_show(filter_bt);
253   
254   filter_te = gtk_entry_new();
255   if (cf.cfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.cfilter);
256   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
257   gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
258   gtk_widget_show(filter_te);
259
260   /* Misc row: Capture file checkbox and snap spinbutton */
261   caplen_hb = gtk_hbox_new(FALSE, 3);
262   gtk_container_add(GTK_CONTAINER(main_vb), caplen_hb);
263   gtk_widget_show(caplen_hb);
264
265   snap_lb = gtk_label_new("Capture length");
266   gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5);
267   gtk_box_pack_start(GTK_BOX(caplen_hb), snap_lb, FALSE, FALSE, 6);
268   gtk_widget_show(snap_lb);
269
270   adj = (GtkAdjustment *) gtk_adjustment_new((float) cf.snap,
271     MIN_PACKET_SIZE, MAX_PACKET_SIZE, 1.0, 10.0, 0.0);
272   snap_sb = gtk_spin_button_new (adj, 0, 0);
273   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE);
274   gtk_widget_set_usize (snap_sb, 80, 0);
275   gtk_box_pack_start (GTK_BOX(caplen_hb), snap_sb, FALSE, FALSE, 3); 
276   gtk_widget_show(snap_sb);
277   
278   /* Button row: OK and cancel buttons */
279   bbox = gtk_hbutton_box_new();
280   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
281   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
282   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
283   gtk_widget_show(bbox);
284
285   ok_bt = gtk_button_new_with_label ("OK");
286   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
287     GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w));
288   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
289   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
290   gtk_widget_grab_default(ok_bt);
291   gtk_widget_show(ok_bt);
292
293   cancel_bt = gtk_button_new_with_label ("Cancel");
294   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
295     GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w));
296   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
297   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
298   gtk_widget_show(cancel_bt);
299
300   /* Attach pointers to needed widgets to the capture prefs window/object */
301   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_IFACE_KEY, if_cb);
302   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_FILT_KEY,  filter_te);
303   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_COUNT_KEY, count_cb);
304   gtk_object_set_data(GTK_OBJECT(cap_open_w), E_CAP_SNAP_KEY,  snap_sb);
305
306   gtk_widget_show(cap_open_w);
307 }
308
309 static void
310 capture_prep_ok_cb(GtkWidget *ok_bt, gpointer parent_w) {
311   GtkWidget *if_cb, *filter_te, *count_cb, *snap_sb;
312
313   gchar *filter_text;
314
315   if_cb     = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_IFACE_KEY);
316   filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_FILT_KEY);
317   count_cb  = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_COUNT_KEY);
318   snap_sb   = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_CAP_SNAP_KEY);
319
320   if (cf.iface) g_free(cf.iface);
321   cf.iface =
322     g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
323
324   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
325   if (cf.cfilter) g_free(cf.cfilter);
326   cf.cfilter = NULL; /* ead 06/16/99 */
327   if (filter_text && filter_text[0]) {
328           cf.cfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); 
329   }
330   cf.count = atoi(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)));
331   cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb));
332   if (cf.snap < 1)
333     cf.snap = MAX_PACKET_SIZE;
334   else if (cf.snap < MIN_PACKET_SIZE)
335     cf.snap = MIN_PACKET_SIZE;
336
337   gtk_widget_destroy(GTK_WIDGET(parent_w));
338
339   /* Choose a random name for the capture buffer */
340   if (cf.save_file && !cf.user_saved) {
341         unlink(cf.save_file); /* silently ignore error */
342         g_free(cf.save_file);
343   }
344   cf.save_file = tempnam(NULL, "ether");
345   cf.user_saved = 0;
346   
347   if( fork_mode ){      /*  use fork() for capture */
348     int  fork_child;
349     char ssnap[24];
350     char scount[24];    /* need a constant for len of numbers */
351     int err;
352
353     sprintf(ssnap,"%d",cf.snap); /* in liu of itoa */
354     sprintf(scount,"%d",cf.count);
355     signal(SIGCHLD, SIG_IGN);
356     if (sync_mode) pipe(sync_pipe);
357     if((fork_child = fork()) == 0){
358       /* args: -k -- capture
359        * -i interface specification
360        * -w file to write
361        * -c count to capture
362        * -Q quit after capture (forces -k)
363        * -s snaplen
364        * -S sync mode
365        * -m / -b fonts
366        * -f "filter expression"
367        */
368        if (sync_mode) {
369          close(1);
370          dup(sync_pipe[1]);
371          close(sync_pipe[0]);
372          execlp(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
373                 "-c", scount, "-s", ssnap, "-S", 
374                 "-m", medium_font, "-b", bold_font,
375                 (cf.cfilter == NULL)? 0 : "-f", (cf.cfilter == NULL)? 0 : cf.cfilter, 
376                 0);     
377        }
378        else {
379          execlp(ethereal_path,"ethereal","-k","-Q","-i",cf.iface,"-w",cf.save_file,
380                 "-c", scount, "-s", ssnap,
381                 "-m", medium_font, "-b", bold_font,
382                 (cf.cfilter == NULL)? 0 : "-f", (cf.cfilter == NULL)? 0 : cf.cfilter,
383                 0);
384        }
385     }
386     else {
387        cf.filename = cf.save_file;
388        if (sync_mode) {
389          close(sync_pipe[1]);
390          while (!sigusr2_received) {
391            struct timeval timeout = {1,0};
392            select(0, NULL, NULL, NULL, &timeout);
393            if (kill(fork_child, 0) == -1 && errno == ESRCH) 
394              break;
395          }
396          if (sigusr2_received) {
397            err = tail_cap_file(cf.save_file, &cf);
398            if (err != 0) {
399              simple_dialog(ESD_TYPE_WARN, NULL,
400                         file_open_error_message(err, FALSE), cf.save_file);
401            }
402          }
403          sigusr2_received = FALSE;
404        }
405     }
406   }
407   else
408     capture();
409 }
410
411 static void
412 capture_prep_close_cb(GtkWidget *close_bt, gpointer parent_w)
413 {
414   gtk_grab_remove(GTK_WIDGET(parent_w));
415   gtk_widget_destroy(GTK_WIDGET(parent_w));
416 }
417
418 void
419 capture(void) {
420   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, 
421              *ospf_lb, *gre_lb, *other_lb, *stop_bt;
422   pcap_t     *pch;
423   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
424   loop_data   ld;
425   bpf_u_int32 netnum, netmask;
426   time_t      upd_time, cur_time;
427   int         err, inpkts;
428   
429   ld.go           = TRUE;
430   ld.counts.total = 0;
431   ld.max          = cf.count;
432   ld.linktype     = DLT_NULL;
433   ld.sync_packets = 0;
434   ld.counts.tcp   = 0;
435   ld.counts.udp   = 0;
436   ld.counts.ospf  = 0;
437   ld.counts.gre   = 0;
438   ld.counts.other = 0;
439   ld.pdh          = NULL;
440
441   close_cap_file(&cf, info_bar, file_ctx);
442
443   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
444
445   if (pch) {
446     /* save the old new umask and set the new one to readable only by the user */
447     mode_t old_umask = umask(0066);
448
449     /* Have libpcap create the empty dumpfile */
450     ld.pdh = pcap_dump_open(pch, cf.save_file);
451
452     /* reset the umask to the original value */
453     (void) umask(old_umask); 
454
455     if (ld.pdh == NULL) {  /* We have an error */
456       snprintf(err_str, PCAP_ERRBUF_SIZE, "Error trying to save capture to "
457         "file:\n%s", pcap_geterr(pch));
458       simple_dialog(ESD_TYPE_WARN, NULL, err_str);
459       pcap_close(pch);
460       return;
461     }
462
463     ld.linktype = pcap_datalink(pch);
464
465     if (cf.cfilter) {
466       if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
467         simple_dialog(ESD_TYPE_WARN, NULL,
468           "Can't use filter:  Couldn't obtain netmask info.");
469         pcap_dump_close(ld.pdh);
470         unlink(cf.save_file); /* silently ignore error */
471         pcap_close(pch);
472         return;
473       } else if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
474         simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string.");
475         pcap_dump_close(ld.pdh);
476         unlink(cf.save_file); /* silently ignore error */
477         pcap_close(pch);
478         return;
479       } else if (pcap_setfilter(pch, &cf.fcode) < 0) {
480         simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter.");
481         pcap_dump_close(ld.pdh);
482         unlink(cf.save_file); /* silently ignore error */
483         pcap_close(pch);
484         return;
485       }
486     }
487
488     if (sync_mode) {
489       /* Sync out the capture file, so the header makes it to the file
490          system, and signal our parent so that they'll open the capture
491          file and update its windows to indicate that we have a live
492          capture in progress. */
493       fflush((FILE *)ld.pdh);
494       kill(getppid(), SIGUSR2);
495     }
496
497     cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
498     gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
499
500     /* Container for capture display widgets */
501     main_vb = gtk_vbox_new(FALSE, 1);
502     gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
503     gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
504     gtk_widget_show(main_vb);
505
506     count_lb = gtk_label_new("Count: 0");
507     gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
508     gtk_widget_show(count_lb);
509
510     tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
511     gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
512     gtk_widget_show(tcp_lb);
513
514     udp_lb = gtk_label_new("UDP: 0 (0.0%)");
515     gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
516     gtk_widget_show(udp_lb);
517
518     ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
519     gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
520     gtk_widget_show(ospf_lb);
521
522     gre_lb = gtk_label_new("GRE: 0 (0.0%)");
523     gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
524     gtk_widget_show(gre_lb);
525
526     other_lb = gtk_label_new("Other: 0 (0.0%)");
527     gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
528     gtk_widget_show(other_lb);
529
530     stop_bt = gtk_button_new_with_label ("Stop");
531     gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
532       GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
533     gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
534     GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
535     gtk_widget_grab_default(stop_bt);
536     GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
537     gtk_widget_grab_default(stop_bt);
538     gtk_widget_show(stop_bt);
539
540     gtk_widget_show(cap_w);
541     gtk_grab_add(cap_w);
542
543     upd_time = time(NULL);
544     while (ld.go) {
545       while (gtk_events_pending()) gtk_main_iteration();
546       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
547       if (inpkts)
548         ld.sync_packets++;
549       /* Only update once a second so as not to overload slow displays */
550       cur_time = time(NULL);
551       if (cur_time > upd_time) {
552
553         upd_time = cur_time;
554
555         sprintf(label_str, "Count: %d", ld.counts.total);
556         gtk_label_set(GTK_LABEL(count_lb), label_str);
557
558         sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
559            pct(ld.counts.tcp, ld.counts.total));
560         gtk_label_set(GTK_LABEL(tcp_lb), label_str);
561
562         sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
563           pct(ld.counts.udp, ld.counts.total));
564         gtk_label_set(GTK_LABEL(udp_lb), label_str);
565
566         sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
567           pct(ld.counts.ospf, ld.counts.total));
568         gtk_label_set(GTK_LABEL(ospf_lb), label_str);
569
570         sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
571           pct(ld.counts.gre, ld.counts.total));
572         gtk_label_set(GTK_LABEL(gre_lb), label_str);
573
574         sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
575           pct(ld.counts.other, ld.counts.total));
576         gtk_label_set(GTK_LABEL(other_lb), label_str);
577
578         /* do sync here, too */
579         fflush((FILE *)ld.pdh);
580         if (sync_mode && ld.sync_packets) {
581           char tmp[20];
582           sprintf(tmp, "%d*", ld.sync_packets);
583           write(1, tmp, strlen(tmp));
584           ld.sync_packets = 0;
585         }
586       }
587     }
588     
589     if (ld.pdh) pcap_dump_close(ld.pdh);
590     pcap_close(pch);
591
592     gtk_grab_remove(GTK_WIDGET(cap_w));
593     gtk_widget_destroy(GTK_WIDGET(cap_w));
594   } else {
595     while (gtk_events_pending()) gtk_main_iteration();
596     simple_dialog(ESD_TYPE_WARN, NULL,
597       "The capture session could not be initiated.  Please\n"
598       "check to make sure you have sufficient permissions, and\n"
599       "that you have the proper interface specified.");
600   }
601
602   if( quit_after_cap ){
603     /* DON'T unlink the save file.  Presumably someone wants it. */
604     gtk_exit(0);
605   }
606
607   if (pch) {
608     /* "pch" is non-NULL only if we successfully started a capture.
609        If we haven't, there's no capture file to load. */
610     err = load_cap_file(cf.save_file, NULL, &cf);
611     if (err == 0) {
612       set_menu_sensitivity("/File/Save", TRUE);
613       set_menu_sensitivity("/File/Save As...", FALSE);
614     }
615   }
616 }
617
618 static float
619 pct(gint num, gint denom) {
620   if (denom) {
621     return (float) num * 100.0 / (float) denom;
622   } else {
623     return 0.0;
624   }
625 }
626
627 static void
628 capture_stop_cb(GtkWidget *w, gpointer data) {
629   loop_data *ld = (loop_data *) data;
630   
631   ld->go = FALSE;
632 }
633
634 static void
635 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
636   const u_char *pd) {
637   
638   loop_data *ld = (loop_data *) user;
639   
640   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
641   {
642      ld->go = FALSE;
643   }
644   /* Currently, pcap_dumper_t is a FILE *.  Let's hope that doesn't change. */
645   if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd);
646     
647   switch (ld->linktype) {
648     case DLT_EN10MB :
649       capture_eth(pd, phdr->caplen, &ld->counts);
650       break;
651     case DLT_FDDI :
652       capture_fddi(pd, phdr->caplen, &ld->counts);
653       break;
654     case DLT_IEEE802 :
655       capture_tr(pd, phdr->caplen, &ld->counts);
656       break;
657     case DLT_NULL :
658       capture_null(pd, phdr->caplen, &ld->counts);
659       break;
660     case DLT_PPP :
661       capture_ppp(pd, phdr->caplen, &ld->counts);
662       break;
663     case DLT_RAW :
664       capture_raw(pd, phdr->caplen, &ld->counts);
665       break;
666   }
667 }
668
669 #endif /* HAVE_LIBPCAP */