update asn2eth and all generated dissectors to new dissect_ber_boolean that takes...
[metze/wireshark/wip.git] / tethereal.c
index e03831d419f9dbf262e02953d2dfddf43f39340e..824c68880a1fcca30f38cf93a94363df5e9fe52b 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-/* With MSVC and a libethereal.dll this file needs to import some variables 
-   in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
-#define _NEED_VAR_IMPORT_
-
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 #ifdef HAVE_LIBPCAP
 #include <wiretap/wtap-capture.h>
 #include <wiretap/libpcap.h>
-#endif
-
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #endif
+#include "capture.h"
+#endif
+
 
 /*
  * This is the template for the decode as option; it is shared between the
@@ -122,7 +119,6 @@ static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 static GString *comp_info_str, *runtime_info_str;
-static gboolean quiet;
 
 static gboolean print_packet_info;     /* TRUE if we're to print packet information */
 /*
@@ -143,6 +139,11 @@ static print_format_e print_format = PR_FMT_TEXT;
 static print_stream_t *print_stream;
 
 #ifdef HAVE_LIBPCAP
+/*
+ * TRUE if we're to print packet counts to keep track of captured packets.
+ */
+static gboolean print_packet_counts;
+
 typedef struct _loop_data {
   gboolean       go;           /* TRUE as long as we're supposed to keep capturing */
   gint           linktype;
@@ -168,48 +169,8 @@ typedef struct _loop_data {
 static loop_data ld;
 
 #ifdef HAVE_LIBPCAP
-typedef struct {
-    gchar    *cfilter;              /* Capture filter string */
-    gchar    *iface;                /* the network interface to capture from */
-    int      snaplen;               /* Maximum captured packet length */
-    int      promisc_mode;          /* Capture in promiscuous mode */
-    int      autostop_count;        /* Maximum packet count */
-    gboolean has_autostop_duration; /* TRUE if maximum capture duration
-                                       is specified */
-    gint32   autostop_duration;     /* Maximum capture duration */
-    gboolean has_autostop_filesize; /* TRUE if maximum capture file size
-                                       is specified */
-    gint32   autostop_filesize;     /* Maximum capture file size */
-    gboolean ringbuffer_on;         /* TRUE if ring buffer in use */
-    guint32  ringbuffer_num_files;  /* Number of ring buffer files */
-    gboolean has_ring_duration;     /* TRUE if ring duration specified */
-    gint32   ringbuffer_duration;   /* Switch file after n seconds */
-    int      linktype;              /* Data link type to use, or -1 for
-                                       "use default" */
-} capture_options;
-
-static capture_options capture_opts = {
-    "",                             /* No capture filter string specified */
-    NULL,                           /* Default is "pick the first interface" */
-    WTAP_MAX_PACKET_SIZE,           /* snapshot length - default is
-                                       infinite, in effect */
-    TRUE,                           /* promiscuous mode is the default */
-    0,                              /* max packet count - default is 0,
-                                       meaning infinite */
-    FALSE,                          /* maximum capture duration not
-                                       specified by default */
-    0,                              /* maximum capture duration */
-    FALSE,                          /* maximum capture file size not
-                                       specified by default */
-    0,                              /* maximum capture file size */
-    FALSE,                          /* ring buffer off by default */
-    RINGBUFFER_MIN_NUM_FILES,       /* default number of ring buffer files */
-    FALSE,                          /* Switch ring file after some */
-    0,                              /* specified time is off by default */
-    -1                              /* Default to not change link type */
-};
+static capture_options capture_opts;
 
-static gboolean list_link_layer_types;
 
 #ifdef SIGINFO
 static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
@@ -306,145 +267,6 @@ print_usage(gboolean print_ver)
   fprintf(output, "\tdefault is libpcap\n");
 }
 
-#ifdef HAVE_LIBPCAP
-static int
-get_natural_int(const char *string, const char *name)
-{
-  long number;
-  char *p;
-
-  number = strtol(string, &p, 10);
-  if (p == string || *p != '\0') {
-    fprintf(stderr, "tethereal: The specified %s \"%s\" isn't a decimal number\n",
-           name, string);
-    exit(1);
-  }
-  if (number < 0) {
-    fprintf(stderr, "tethereal: The specified %s is a negative number\n",
-           name);
-    exit(1);
-  }
-  if (number > INT_MAX) {
-    fprintf(stderr, "tethereal: The specified %s is too large (greater than %d)\n",
-           name, INT_MAX);
-    exit(1);
-  }
-  return number;
-}
-
-static int
-get_positive_int(const char *string, const char *name)
-{
-  long number;
-
-  number = get_natural_int(string, name);
-
-  if (number == 0) {
-    fprintf(stderr, "tethereal: The specified %s is zero\n",
-           name);
-    exit(1);
-  }
-
-  return number;
-}
-
-/*
- * Given a string of the form "<autostop criterion>:<value>", as might appear
- * as an argument to a "-a" option, parse it and set the criterion in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-set_autostop_criterion(const char *autostoparg)
-{
-  guchar *p, *colonp;
-
-  colonp = strchr(autostoparg, ':');
-  if (colonp == NULL)
-    return FALSE;
-
-  p = colonp;
-  *p++ = '\0';
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace(*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-  if (strcmp(autostoparg,"duration") == 0) {
-    capture_opts.has_autostop_duration = TRUE;
-    capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
-  } else if (strcmp(autostoparg,"filesize") == 0) {
-    capture_opts.has_autostop_filesize = TRUE;
-    capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
-  } else {
-    return FALSE;
-  }
-  *colonp = ':';       /* put the colon back */
-  return TRUE;
-}
-
-/*
- * Given a string of the form "<ring buffer file>:<duration>", as might appear
- * as an argument to a "-b" option, parse it and set the arguments in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-get_ring_arguments(const char *arg)
-{
-  guchar *p = NULL, *colonp;
-
-  colonp = strchr(arg, ':');
-
-  if (colonp != NULL) {
-    p = colonp;
-    *p++ = '\0';
-  }
-
-  capture_opts.ringbuffer_num_files = 
-    get_natural_int(arg, "number of ring buffer files");
-
-  if (colonp == NULL)
-    return TRUE;
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace(*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-
-  capture_opts.has_ring_duration = TRUE;
-  capture_opts.ringbuffer_duration = get_positive_int(p,
-                                                     "ring buffer duration");
-
-  *colonp = ':';       /* put the colon back */
-  return TRUE;
-}
-#endif
-
 /* structure to keep track of what tap listeners have been registered.
  */
 typedef struct _ethereal_tap_list {
@@ -839,13 +661,16 @@ main(int argc, char *argv[])
   char                *p;
   gchar                err_str[PCAP_ERRBUF_SIZE];
   gchar               *cant_get_if_list_errstr;
+  gboolean             list_link_layer_types;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
+  gboolean             quiet = FALSE;
   gchar               *save_file = NULL;
   int                  out_file_type = WTAP_FILE_PCAP;
   gchar               *cf_name = NULL, *rfilter = NULL;
 #ifdef HAVE_LIBPCAP
+  gboolean             start_capture = FALSE;
   gchar               *if_text;
   GList               *lt_list, *lt_entry;
   data_link_info_t    *data_link_info;
@@ -856,11 +681,11 @@ main(int argc, char *argv[])
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
-  ethereal_tap_list *tli;
-
+  ethereal_tap_list *tli = NULL;
+  gboolean got_tap = FALSE;
+  
 #ifdef HAVE_LIBPCAP
-  /* XXX - better use capture_opts_init instead */
-  capture_opts.cfilter = g_strdup("");
+  capture_opts_init(&capture_opts, NULL /* cfile */);
 #endif
 
   set_timestamp_setting(TS_RELATIVE);
@@ -972,32 +797,14 @@ main(int argc, char *argv[])
   while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vw:Vxy:z:")) != -1) {
     switch (opt) {
       case 'a':        /* autostop criteria */
-#ifdef HAVE_LIBPCAP
-        if (set_autostop_criterion(optarg) == FALSE) {
-          fprintf(stderr, "tethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
-          exit(1);
-        }
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'b':        /* Ringbuffer option */
-#ifdef HAVE_LIBPCAP
-        capture_opts.ringbuffer_on = TRUE;
-       if (get_ring_arguments(optarg) == FALSE) {
-          fprintf(stderr, "tethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
-          exit(1);
-       }
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'c':        /* Capture xxx packets */
+      case 'f':        /* capture filter */
+      case 'p':        /* Don't capture in promiscuous mode */
+      case 's':        /* Set the snapshot (capture) length */
+      case 'y':        /* Set the pcap data link type */
 #ifdef HAVE_LIBPCAP
-        capture_opts.autostop_count =
-            get_positive_int(optarg, "packet count");
+        capture_opts_add_opt(&capture_opts, "tethereal", opt, optarg, &start_capture);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -1042,17 +849,6 @@ main(int argc, char *argv[])
         arg_error = TRUE;
 #endif
         break;
-      case 'f':
-#ifdef HAVE_LIBPCAP
-        capture_filter_specified = TRUE;
-       if (capture_opts.cfilter)
-               g_free(capture_opts.cfilter);
-       capture_opts.cfilter = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'F':
         out_file_type = wtap_short_string_to_file_type(optarg);
         if (out_file_type < 0) {
@@ -1176,32 +972,15 @@ main(int argc, char *argv[])
           break;
         }
         break;
-      case 'p':        /* Don't capture in promiscuous mode */
-#ifdef HAVE_LIBPCAP
-       capture_opts.promisc_mode = FALSE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'q':        /* Quiet */
         quiet = TRUE;
         break;
       case 'r':        /* Read capture file xxx */
         cf_name = g_strdup(optarg);
-        quiet = TRUE;  /* We're not capturing, so don't print packet counts */
         break;
       case 'R':        /* Read file filter */
         rfilter = optarg;
         break;
-      case 's':        /* Set the snapshot (capture) length */
-#ifdef HAVE_LIBPCAP
-        capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'S':        /* show packets in real time */
         print_packet_info = TRUE;
         break;
@@ -1259,28 +1038,14 @@ main(int argc, char *argv[])
       case 'x':        /* Print packet data in hex (and ASCII) */
         print_hex = TRUE;
         break;
-      case 'y':        /* Set the pcap data link type */
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
-        capture_opts.linktype = pcap_datalink_name_to_val(optarg);
-        if (capture_opts.linktype == -1) {
-          fprintf(stderr, "tethereal: The specified data link type \"%s\" isn't valid\n",
-                  optarg);
-          exit(1);
-        }
-#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-        /* XXX - just treat it as a number */
-        capture_opts.linktype = get_natural_int(optarg, "data link type");
-#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'z':
         for(tli=tap_list;tli;tli=tli->next){
           if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
-            (*tli->func)(optarg);
+              /* we won't call the init function for the tap this soon
+                as it would disallow mate's fields (which are registered
+                by the preferences set callback) from being used as
+                part of a tap filter */
+            got_tap = TRUE;
             break;
           }
         }
@@ -1412,7 +1177,7 @@ main(int argc, char *argv[])
       exit(1);
     }
     /* No - did they specify a ring buffer option? */
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       fprintf(stderr, "tethereal: Ring buffer requested, but a capture isn't being done.\n");
       exit(1);
     }
@@ -1425,7 +1190,7 @@ main(int argc, char *argv[])
       exit(1);
     }
 
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       /* Ring buffer works only under certain conditions:
         a) ring buffer does not work if you're not saving the capture to
            a file;
@@ -1467,6 +1232,12 @@ main(int argc, char *argv[])
      line that their preferences have changed. */
   prefs_apply_all();
 
+  /* At this point mate will have registered its field array so we can
+         have a filter with one of mate's late registered fields as part
+         of the tap's filter */
+  if (got_tap)
+         (*tli->func)(optarg);
+  
   /* disabled protocols as per configuration file */
   if (gdp_path == NULL && dp_path == NULL) {
     set_disabled_protos_list();
@@ -1509,12 +1280,12 @@ main(int argc, char *argv[])
   else if (capture_opts.snaplen < MIN_PACKET_SIZE)
     capture_opts.snaplen = MIN_PACKET_SIZE;
 
-  /* Check the value range of the ringbuffer_num_files parameter */
-  if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
-    capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
+  /* Check the value range of the ring_num_files parameter */
+  if (capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
+    capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
 #if RINGBUFFER_MIN_NUM_FILES > 0
-  else if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
-    capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
+  else if (capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
+    capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
 #endif
 #endif
 
@@ -1673,9 +1444,17 @@ main(int argc, char *argv[])
       exit(0);
     }
 
+    if (!quiet) {
+      /*
+       * The user didn't ask us not to print a count of packets as
+       * they arrive, so do so.
+       */
+      print_packet_counts = TRUE;
+    }
+
     capture(save_file, out_file_type);
 
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       ringbuf_free();
     }
 #else
@@ -1890,9 +1669,9 @@ capture(char *save_file, int out_file_type)
       goto error;
     }
     ld.save_file = save_file;
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       save_file_fd = ringbuf_init(save_file,
-        capture_opts.ringbuffer_num_files);
+        capture_opts.ring_num_files);
       if (save_file_fd != -1) {
         ld.pdh = ringbuf_init_wtap_dump_fdopen(out_file_type, ld.linktype,
           file_snaplen, &err);
@@ -1953,9 +1732,9 @@ capture(char *save_file, int out_file_type)
     cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
-  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+  if (capture_opts.multi_files_on && capture_opts.has_file_duration)
     cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, 
-                              capture_opts.ringbuffer_duration);
+                              capture_opts.file_duration);
 
   if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
@@ -2006,15 +1785,15 @@ capture(char *save_file, int out_file_type)
          reading the FIFO sees the packets immediately and doesn't get
          any partial packet, forcing it to block in the middle of reading
          that packet. */
-      if (capture_opts.autostop_count == 0)
+      if (capture_opts.autostop_packets == 0)
         pcap_cnt = -1;
       else {
-        if (ld.packet_count >= capture_opts.autostop_count) {
+        if (ld.packet_count >= capture_opts.autostop_packets) {
           /* XXX do we need this test here? */
           /* It appears there's nothing more to capture. */
           break;
         }
-        pcap_cnt = capture_opts.autostop_count - ld.packet_count;
+        pcap_cnt = capture_opts.autostop_packets - ld.packet_count;
       }
     } else {
       /* We need to check the capture file size or the timeout after
@@ -2036,8 +1815,8 @@ capture(char *save_file, int out_file_type)
       /* The specified capture time has elapsed; stop the capture. */
       ld.go = FALSE;
     } else if (inpkts > 0) {
-      if (capture_opts.autostop_count != 0 &&
-                 ld.packet_count >= capture_opts.autostop_count) {
+      if (capture_opts.autostop_packets != 0 &&
+                 ld.packet_count >= capture_opts.autostop_packets) {
         /* The specified number of packets have been captured and have
            passed both any capture filter in effect and any read filter
            in effect. */
@@ -2047,7 +1826,7 @@ capture(char *save_file, int out_file_type)
                               (guint32)wtap_get_bytes_dumped(ld.pdh))) {
         /* We're saving the capture to a file, and the capture file reached
            its maximum size. */
-        if (capture_opts.ringbuffer_on) {
+        if (capture_opts.multi_files_on) {
           /* Switch to the next ringbuffer file */
           if (ringbuf_switch_file(&ld.pdh, &save_file, &save_file_fd, &loop_err)) {
             /* File switch succeeded: reset the condition */
@@ -2085,9 +1864,8 @@ capture(char *save_file, int out_file_type)
   if (cnd_ring_timeout != NULL)
     cnd_delete(cnd_ring_timeout);
 
-  if ((save_file != NULL) && !quiet) {
-    /* We're saving to a file, which means we're printing packet counts
-       to stderr if we are not running silent and deep.
+  if (print_packet_counts) {
+    /* We're printing packet counts to stderr.
        Send a newline so that we move to the line after the packet count. */
     fprintf(stderr, "\n");
   }
@@ -2117,7 +1895,7 @@ capture(char *save_file, int out_file_type)
 
   if (save_file != NULL) {
     /* We're saving to a file or files; close all files. */
-    if (capture_opts.ringbuffer_on) {
+    if (capture_opts.multi_files_on) {
       dump_ok = ringbuf_wtap_dump_close(&save_file, &err);
     } else {
       dump_ok = wtap_dump_close(ld.pdh, &err);
@@ -2154,7 +1932,7 @@ capture(char *save_file, int out_file_type)
   return TRUE;
 
 error:
-  if (capture_opts.ringbuffer_on) {
+  if (capture_opts.multi_files_on) {
     ringbuf_error_cleanup();
   }
   g_free(save_file);
@@ -2221,9 +1999,9 @@ capture_pcap_cb(guchar *user, const struct pcap_pkthdr *phdr,
 
   if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) {
     /* Error writing to a capture file */
-    if (!quiet) {
-      /* We're capturing packets, so (if -q not specified) we're printing
-         a count of packets captured; move to the line after the count. */
+    if (print_packet_counts) {
+      /* We're printing counts of packets captured; move to the line after
+         the count. */
       fprintf(stderr, "\n");
     }
     show_capture_file_io_error(ldat->save_file, err, FALSE);
@@ -2297,7 +2075,7 @@ report_counts(void)
   signal(SIGINFO, report_counts_siginfo);
 #endif /* SIGINFO */
 
-  if (quiet || print_packet_info) {
+  if (!print_packet_counts) {
     /* Report the count only if we aren't printing a packet count
        as packets arrive. */
     fprintf(stderr, "%u packets captured\n", ld.packet_count);
@@ -2611,10 +2389,8 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
       if (!wtap_dump(pdh, whdr, pseudo_header, pd, err))
         return FALSE;
 #ifdef HAVE_LIBPCAP
-      /* Report packet capture count if not quiet */
-      if (!quiet && !print_packet_info) {
-       /* Don't print a packet count if we were asked not to with "-q"
-          or if we're also printing packet info. */
+      if (print_packet_counts) {
+       /* We're printing packet counts. */
         if (ld.packet_count != 0) {
           fprintf(stderr, "\r%u ", ld.packet_count);
           /* stderr could be line buffered */