Get rid of some useless lines from the last patch
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38
39 #ifdef HAVE_IO_H
40 # include <io.h>
41 #endif
42
43 #include <signal.h>
44 #include <errno.h>
45
46 #include <pcap.h>
47
48 #include <glib.h>
49
50 #include <epan/packet.h>
51 #include <epan/dfilter/dfilter.h>
52 #include "file.h"
53 #include "capture.h"
54 #include "capture_sync.h"
55 #include "capture_ui_utils.h"
56 #include "util.h"
57 #include "pcap-util.h"
58 #include "alert_box.h"
59 #include "simple_dialog.h"
60 #include <epan/prefs.h>
61 #include "conditions.h"
62 #include "ringbuffer.h"
63
64 #ifdef _WIN32
65 #include "capture-wpcap.h"
66 #endif
67 #include "ui_util.h"
68
69
70 /* Win32 needs the O_BINARY flag for open() */
71 #ifndef O_BINARY
72 #define O_BINARY        0
73 #endif
74
75 static gboolean normal_do_capture(capture_options *capture_opts, gboolean is_tempfile);
76 static void stop_capture_signal_handler(int signo);
77
78
79 void
80 capture_opts_init(capture_options *capture_opts, void *cfile)
81 {
82   capture_opts->cf                      = cfile;
83   capture_opts->cfilter                     = g_strdup("");
84   capture_opts->iface                   = NULL;
85 #ifdef _WIN32
86   capture_opts->buffer_size             = 1;                /* 1 MB */
87 #endif
88   capture_opts->has_snaplen             = FALSE;
89   capture_opts->snaplen                 = MIN_PACKET_SIZE;
90   capture_opts->promisc_mode            = TRUE;
91   capture_opts->linktype                = -1;               /* the default linktype */
92   capture_opts->capture_child           = FALSE;
93   capture_opts->save_file               = NULL;
94   capture_opts->save_file_fd            = -1;
95   capture_opts->sync_mode               = TRUE;
96   capture_opts->show_info               = TRUE;
97   capture_opts->quit_after_cap          = FALSE;
98
99   capture_opts->multi_files_on          = FALSE;
100   capture_opts->has_file_duration       = FALSE;
101   capture_opts->file_duration           = 60;               /* 1 min */
102   capture_opts->has_ring_num_files      = TRUE;
103   capture_opts->ring_num_files          = 2;
104
105   capture_opts->has_autostop_files      = FALSE;
106   capture_opts->autostop_files          = 1;
107   capture_opts->has_autostop_packets    = FALSE;
108   capture_opts->autostop_packets        = 1;
109   capture_opts->has_autostop_filesize   = FALSE;
110   capture_opts->autostop_filesize       = 1024 * 1024;      /* 1 MB */
111   capture_opts->has_autostop_duration   = FALSE;
112   capture_opts->autostop_duration       = 60;               /* 1 min */
113
114 }
115
116 static int
117 get_natural_int(const char *string, const char *name)
118 {
119   long number;
120   char *p;
121
122   number = strtol(string, &p, 10);
123   if (p == string || *p != '\0') {
124     fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
125             name, string);
126     exit(1);
127   }
128   if (number < 0) {
129     fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
130             name, string);
131     exit(1);
132   }
133   if (number > INT_MAX) {
134     fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
135             name, string, INT_MAX);
136     exit(1);
137   }
138   return number;
139 }
140
141
142 static int
143 get_positive_int(const char *string, const char *name)
144 {
145   long number;
146
147   number = get_natural_int(string, name);
148
149   if (number == 0) {
150     fprintf(stderr, "ethereal: The specified %s is zero\n",
151             name);
152     exit(1);
153   }
154
155   return number;
156 }
157
158
159 /*
160  * Given a string of the form "<autostop criterion>:<value>", as might appear
161  * as an argument to a "-a" option, parse it and set the criterion in
162  * question.  Return an indication of whether it succeeded or failed
163  * in some fashion.
164  */
165 static gboolean
166 set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
167 {
168   gchar *p, *colonp;
169
170   colonp = strchr(autostoparg, ':');
171   if (colonp == NULL)
172     return FALSE;
173
174   p = colonp;
175   *p++ = '\0';
176
177   /*
178    * Skip over any white space (there probably won't be any, but
179    * as we allow it in the preferences file, we might as well
180    * allow it here).
181    */
182   while (isspace((guchar)*p))
183     p++;
184   if (*p == '\0') {
185     /*
186      * Put the colon back, so if our caller uses, in an
187      * error message, the string they passed us, the message
188      * looks correct.
189      */
190     *colonp = ':';
191     return FALSE;
192   }
193   if (strcmp(autostoparg,"duration") == 0) {
194     capture_opts->has_autostop_duration = TRUE;
195     capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
196   } else if (strcmp(autostoparg,"filesize") == 0) {
197     capture_opts->has_autostop_filesize = TRUE;
198     capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
199   } else {
200     return FALSE;
201   }
202   *colonp = ':'; /* put the colon back */
203   return TRUE;
204 }
205
206 /*
207  * Given a string of the form "<ring buffer file>:<duration>", as might appear
208  * as an argument to a "-b" option, parse it and set the arguments in
209  * question.  Return an indication of whether it succeeded or failed
210  * in some fashion.
211  */
212 static gboolean
213 get_ring_arguments(capture_options *capture_opts, const char *arg)
214 {
215   gchar *p = NULL, *colonp;
216
217   colonp = strchr(arg, ':');
218
219   if (colonp != NULL) {
220     p = colonp;
221     *p++ = '\0';
222   }
223
224   capture_opts->ring_num_files = 
225     get_natural_int(arg, "number of ring buffer files");
226
227   if (colonp == NULL)
228     return TRUE;
229
230   /*
231    * Skip over any white space (there probably won't be any, but
232    * as we allow it in the preferences file, we might as well
233    * allow it here).
234    */
235   while (isspace((guchar)*p))
236     p++;
237   if (*p == '\0') {
238     /*
239      * Put the colon back, so if our caller uses, in an
240      * error message, the string they passed us, the message
241      * looks correct.
242      */
243     *colonp = ':';
244     return FALSE;
245   }
246
247   capture_opts->has_file_duration = TRUE;
248   capture_opts->file_duration = get_positive_int(p,
249                                                       "ring buffer duration");
250
251   *colonp = ':';        /* put the colon back */
252   return TRUE;
253 }
254
255
256 void
257 capture_opt_add(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture)
258 {
259 #ifdef _WIN32
260     int i;
261 #endif
262
263     switch(opt) {
264     case 'a':        /* autostop criteria */
265         if (set_autostop_criterion(capture_opts, optarg) == FALSE) {
266           fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
267           exit(1);
268         }
269         break;
270     case 'b':        /* Ringbuffer option */
271         capture_opts->multi_files_on = TRUE;
272         capture_opts->has_ring_num_files = TRUE;
273         if (get_ring_arguments(capture_opts, optarg) == FALSE) {
274           fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
275           exit(1);
276         }
277         break;
278     case 'c':        /* Capture xxx packets */
279         capture_opts->has_autostop_packets = TRUE;
280         capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
281         break;
282     case 'f':        /* capture filter */
283         if (capture_opts->cfilter)
284             g_free(capture_opts->cfilter);
285         capture_opts->cfilter = g_strdup(optarg);
286         break;
287     case 'H':        /* Hide capture info dialog box */
288         capture_opts->show_info = FALSE;
289         break;
290     case 'i':        /* Use interface xxx */
291         capture_opts->iface = g_strdup(optarg);
292         break;
293     case 'k':        /* Start capture immediately */
294         *start_capture = TRUE;
295         break;
296     /*case 'l':*/    /* Automatic scrolling in live capture mode */
297     case 'p':        /* Don't capture in promiscuous mode */
298         capture_opts->promisc_mode = FALSE;
299         break;
300     case 'Q':        /* Quit after capture (just capture to file) */
301         capture_opts->quit_after_cap  = TRUE;
302         *start_capture   = TRUE;  /*** -Q implies -k !! ***/
303         break;
304     case 's':        /* Set the snapshot (capture) length */
305         capture_opts->has_snaplen = TRUE;
306         capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
307         break;
308     case 'S':        /* "Sync" mode: used for following file ala tail -f */
309         capture_opts->sync_mode = TRUE;
310         break;
311     case 'w':        /* Write to capture file xxx */
312         capture_opts->save_file = g_strdup(optarg);
313             break;
314     case 'W':        /* Write to capture file FD xxx */
315         capture_opts->save_file_fd = atoi(optarg);
316         break;
317     case 'y':        /* Set the pcap data link type */
318 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
319         capture_opts->linktype = pcap_datalink_name_to_val(optarg);
320         if (capture_opts->linktype == -1) {
321           fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
322                   optarg);
323           exit(1);
324         }
325 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
326         /* XXX - just treat it as a number */
327         capture_opts->linktype = get_natural_int(optarg, "data link type");
328 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
329         break;
330 #ifdef _WIN32
331       /* Hidden option supporting Sync mode */
332     case 'Z':        /* Write to pipe FD XXX */
333         /* associate stdout with pipe */
334         i = atoi(optarg);
335         if (dup2(i, 1) < 0) {
336           fprintf(stderr, "Unable to dup pipe handle\n");
337           exit(1);
338         }
339         break;
340 #endif /* _WIN32 */
341     default:
342         /* the caller is responsible to send us only the right opt's */
343         g_assert_not_reached();
344     }
345 }
346
347 /* open the output file (temporary/specified name/ringbuffer) and close the old one */
348 /* Returns TRUE if the file opened successfully, FALSE otherwise. */
349 static gboolean
350 capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
351   char tmpname[128+1];
352   gchar *capfile_name;
353
354
355   if (capture_opts->save_file != NULL) {
356     /* If the Sync option is set, we return to the caller while the capture
357      * is in progress.  Therefore we need to take a copy of save_file in
358      * case the caller destroys it after we return.
359      */
360     capfile_name = g_strdup(capture_opts->save_file);
361     if (capture_opts->multi_files_on) {
362       /* ringbuffer is enabled */
363       capture_opts->save_file_fd = ringbuf_init(capfile_name,
364           (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0);
365     } else {
366       /* Try to open/create the specified file for use as a capture buffer. */
367       capture_opts->save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
368                                 0600);
369     }
370     *is_tempfile = FALSE;
371   } else {
372     /* Choose a random name for the temporary capture buffer */
373     capture_opts->save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
374     capfile_name = g_strdup(tmpname);
375     *is_tempfile = TRUE;
376   }
377
378   /* did we fail to open the output file? */
379   if (capture_opts->save_file_fd == -1) {
380     if (is_tempfile) {
381       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
382         "The temporary file to which the capture would be saved (\"%s\")"
383         "could not be opened: %s.", capfile_name, strerror(errno));
384     } else {
385       if (capture_opts->multi_files_on) {
386         ringbuf_error_cleanup();
387       }
388       open_failure_alert_box(capfile_name, errno, TRUE);
389     }
390     g_free(capfile_name);
391     return FALSE;
392   }
393
394   /* close the old file */
395   cf_close(capture_opts->cf);
396   if(capture_opts->save_file != NULL) {
397     g_free(capture_opts->save_file);
398   }
399   capture_opts->save_file = capfile_name;
400   /* capture_opts.save_file is "g_free"ed later, which is equivalent to
401      "g_free(capfile_name)". */
402
403   return TRUE;
404 }
405
406
407 /* Open a specified file, or create a temporary file, and start a capture
408    to the file in question.  */
409 /* Returns TRUE if the capture starts successfully, FALSE otherwise. */
410 gboolean
411 do_capture(capture_options *capture_opts)
412 {
413   gboolean is_tempfile;
414   gboolean ret;
415
416   /* open the output file (temporary/specified name/ringbuffer) and close the old one */
417   if(!capture_open_output(capture_opts, &is_tempfile)) {
418     return FALSE;
419   }
420
421   if (capture_opts->sync_mode) {        
422     /* sync mode: do the capture in a child process */
423     ret = sync_pipe_do_capture(capture_opts, is_tempfile);
424     /* capture is still running */
425     cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
426   } else {
427     /* normal mode: do the capture synchronously */
428     cf_callback_invoke(cf_cb_live_capture_prepare, capture_opts);
429     ret = normal_do_capture(capture_opts, is_tempfile);
430     /* capture is finished here */
431   }
432
433   return ret;
434 }
435
436
437 /* start a normal capture session */
438 static gboolean
439 normal_do_capture(capture_options *capture_opts, gboolean is_tempfile)
440 {
441     int capture_succeeded;
442     gboolean stats_known;
443     struct pcap_stat stats;
444     int err;
445
446     /* Not sync mode. */
447     capture_succeeded = capture_start(capture_opts, &stats_known, &stats);
448     if (capture_opts->quit_after_cap) {
449       /* DON'T unlink the save file.  Presumably someone wants it. */
450         main_window_exit();
451     }
452     if (!capture_succeeded) {
453       /* We didn't succeed in doing the capture, so we don't have a save
454          file. */
455       if (capture_opts->multi_files_on) {
456         ringbuf_free();
457       } else {
458         g_free(capture_opts->save_file);
459       }
460       capture_opts->save_file = NULL;
461       return FALSE;
462     }
463     /* Capture succeeded; attempt to read in the capture file. */
464     if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
465       /* We're not doing a capture any more, so we don't have a save
466          file. */
467       if (capture_opts->multi_files_on) {
468         ringbuf_free();
469       } else {
470         g_free(capture_opts->save_file);
471       }
472       capture_opts->save_file = NULL;
473       return FALSE;
474     }
475
476     /* Set the read filter to NULL. */
477     cf_set_rfcode(capture_opts->cf, NULL);
478
479     /* Get the packet-drop statistics.
480
481        XXX - there are currently no packet-drop statistics stored
482        in libpcap captures, and that's what we're reading.
483
484        At some point, we will add support in Wiretap to return
485        packet-drop statistics for capture file formats that store it,
486        and will make "cf_read()" get those statistics from Wiretap.
487        We clear the statistics (marking them as "not known") in
488        "cf_open()", and "cf_read()" will only fetch them and mark
489        them as known if Wiretap supplies them, so if we get the
490        statistics now, after calling "cf_open()" but before calling
491        "cf_read()", the values we store will be used by "cf_read()".
492
493        If a future libpcap capture file format stores the statistics,
494        we'll put them into the capture file that we write, and will
495        thus not have to set them here - "cf_read()" will get them from
496        the file and use them. */
497     if (stats_known) {
498       cf_set_drops_known(capture_opts->cf, TRUE);
499
500       /* XXX - on some systems, libpcap doesn't bother filling in
501          "ps_ifdrop" - it doesn't even set it to zero - so we don't
502          bother looking at it.
503
504          Ideally, libpcap would have an interface that gave us
505          several statistics - perhaps including various interface
506          error statistics - and would tell us which of them it
507          supplies, allowing us to display only the ones it does. */
508       cf_set_drops(capture_opts->cf, stats.ps_drop);
509     }
510     switch (cf_read(capture_opts->cf)) {
511
512     case CF_READ_OK:
513     case CF_READ_ERROR:
514       /* Just because we got an error, that doesn't mean we were unable
515          to read any of the file; we handle what we could get from the
516          file. */
517       break;
518
519     case CF_READ_ABORTED:
520       /* Exit by leaving the main loop, so that any quit functions
521          we registered get called. */
522       main_window_nested_quit();
523       return FALSE;
524     }
525
526     /* We're not doing a capture any more, so we don't have a save
527        file. */
528     if (capture_opts->multi_files_on) {
529       ringbuf_free();
530     } else {
531       g_free(capture_opts->save_file);
532     }
533     capture_opts->save_file = NULL;
534
535     /* if we didn't captured even a single packet, close the file again */
536     if(cf_packet_count(capture_opts->cf) == 0) {
537       simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
538       "%sNo packets captured!%s\n\n"
539       "As no data was captured, closing the %scapture file!",
540       simple_dialog_primary_start(), simple_dialog_primary_end(),
541       (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
542       cf_close(capture_opts->cf);
543     }
544   return TRUE;
545 }
546
547
548 static void
549 stop_capture_signal_handler(int signo _U_)
550 {
551   capture_loop_stop();
552 }
553
554
555 int  
556 capture_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
557 {
558 #ifndef _WIN32
559   /*
560    * Catch SIGUSR1, so that we exit cleanly if the parent process
561    * kills us with it due to the user selecting "Capture->Stop".
562    */
563   if (capture_opts->capture_child)
564     signal(SIGUSR1, stop_capture_signal_handler);
565 #endif
566
567   return capture_loop_start(capture_opts, stats_known, stats);
568 }
569
570 void
571 capture_stop(capture_options *capture_opts)
572 {
573
574   if (capture_opts->sync_mode) {        
575     sync_pipe_stop(capture_opts);
576   }
577     
578   capture_loop_stop();
579 }
580
581 void
582 capture_kill_child(capture_options *capture_opts)
583 {
584   if (capture_opts->sync_mode) {        
585     sync_pipe_kill(capture_opts);
586   }
587 }
588
589
590 #endif /* HAVE_LIBPCAP */