H.245 update to version 12 (10/2005)
[obnox/wireshark/wip.git] / capture_loop.c
index 16d32bb3507d64627a4153e4c0a687e1c3b42598..92b626353b8f1d73b8d0a1d3464307ce36868098 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -91,7 +91,7 @@
  * Standard secondary message for unexpected errors.
  */
 static const char please_report[] =
-    "Please report this to the Ethereal developers";
+    "Please report this to the Wireshark developers";
 
 /*
  * This needs to be static, so that the SIGUSR1 handler can clear the "go"
@@ -165,7 +165,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
 
   /*
-   * XXX (T)Ethereal blocks until we return
+   * XXX (T)Wireshark blocks until we return
    */
   if (strcmp(pipename, "-") == 0)
     fd = 0; /* read from stdin */
@@ -458,7 +458,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface);
 
 
-/* XXX - opening Winsock on tethereal? */
+/* XXX - opening Winsock on twireshark? */
 
   /* Initialize Windows Socket if we are in a WIN32 OS
      This needs to be done before querying the interface for network/netmask */
@@ -567,7 +567,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 "\n"
 "Help can be found at:\n"
 "\n"
-"       http://wiki.ethereal.com/CaptureSetup\n"
+"       http://wiki.wireshark.org/CaptureSetup\n"
 "\n"
 "64-bit Windows:\n"
 "WinPcap does not support 64-bit Windows; you will have to use some other\n"
@@ -592,16 +592,16 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
        /* Pipe doesn't exist, so output message for interface */
 
        /* If we got a "can't find PPA for X" message, warn the user (who
-          is running (T)Ethereal on HP-UX) that they don't have a version
+          is running (T)Wireshark on HP-UX) that they don't have a version
           of libpcap that properly handles HP-UX (libpcap 0.6.x and later
           versions, which properly handle HP-UX, say "can't find /dev/dlpi
           PPA for X" rather than "can't find PPA for X"). */
        if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
          libpcap_warn =
            "\n\n"
-           "You are running (T)Ethereal with a version of the libpcap library\n"
+           "You are running (T)Wireshark with a version of the libpcap library\n"
            "that doesn't handle HP-UX network devices well; this means that\n"
-           "(T)Ethereal may not be able to capture packets.\n"
+           "(T)Wireshark may not be able to capture packets.\n"
            "\n"
            "To fix this, you should install libpcap 0.6.2, or a later version\n"
            "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
@@ -628,7 +628,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 #endif
   }
 
-/* XXX - will this work for tethereal? */
+/* XXX - will this work for twireshark? */
 #ifdef MUST_DO_SELECT
   if (!ld->from_cap_pipe) {
 #ifdef HAVE_PCAP_GET_SELECTABLE_FD
@@ -753,7 +753,7 @@ gboolean capture_loop_init_output(capture_options *capture_opts, int save_file_f
 
   if (ld->pdh == NULL) {
     /* We couldn't set up to write to the capture file. */
-    /* XXX - use cf_open_error_message from tethereal instead? */
+    /* XXX - use cf_open_error_message from twireshark instead? */
     switch (err) {
 
     case WTAP_ERR_CANT_OPEN:
@@ -811,154 +811,154 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
 #endif
 
 #ifndef _WIN32
-    if (ld->from_cap_pipe) {
-      /* dispatch from capture pipe */
+  if (ld->from_cap_pipe) {
+    /* dispatch from capture pipe */
 #ifdef LOG_CAPTURE_VERBOSE
-      g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe");
 #endif
+    FD_ZERO(&set1);
+    FD_SET(ld->cap_pipe_fd, &set1);
+    timeout.tv_sec = 0;
+    timeout.tv_usec = CAP_READ_TIMEOUT*1000;
+    sel_ret = select(ld->cap_pipe_fd+1, &set1, NULL, NULL, &timeout);
+    if (sel_ret <= 0) {
+      inpkts = 0;
+      if (sel_ret < 0 && errno != EINTR) {
+        g_snprintf(errmsg, errmsg_len,
+          "Unexpected error from select: %s", strerror(errno));
+        report_capture_error(errmsg, please_report);
+        ld->go = FALSE;
+      }
+    } else {
+      /*
+       * "select()" says we can read from the pipe without blocking
+       */
+      inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
+      if (inpkts < 0) {
+        ld->go = FALSE;
+      }
+    }
+  }
+  else
+#endif /* _WIN32 */
+  {
+    /* dispatch from pcap */
+#ifdef MUST_DO_SELECT
+    /*
+     * If we have "pcap_get_selectable_fd()", we use it to get the
+     * descriptor on which to select; if that's -1, it means there
+     * is no descriptor on which you can do a "select()" (perhaps
+     * because you're capturing on a special device, and that device's
+     * driver unfortunately doesn't support "select()", in which case
+     * we don't do the select - which means it might not be possible
+     * to stop a capture until a packet arrives.  If that's unacceptable,
+     * plead with whoever supplies the software for that device to add
+     * "select()" support, or upgrade to libpcap 0.8.1 or later, and
+     * rebuild Wireshark or get a version built with libpcap 0.8.1 or
+     * later, so it can use pcap_breakloop().
+     */
+#ifdef LOG_CAPTURE_VERBOSE
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select");
+#endif
+    if (ld->pcap_fd != -1) {
       FD_ZERO(&set1);
-      FD_SET(ld->cap_pipe_fd, &set1);
-      timeout.tv_sec = 0;
-      timeout.tv_usec = CAP_READ_TIMEOUT*1000;
-      sel_ret = select(ld->cap_pipe_fd+1, &set1, NULL, NULL, &timeout);
-      if (sel_ret <= 0) {
-       inpkts = 0;
+      FD_SET(ld->pcap_fd, &set1);
+      sel_ret = select(ld->pcap_fd+1, &set1, NULL, NULL, NULL);
+      if (sel_ret > 0) {
+        /*
+         * "select()" says we can read from it without blocking; go for
+         * it.
+         *
+         * We don't have pcap_breakloop(), so we only process one packet
+         * per pcap_dispatch() call, to allow a signal to stop the
+         * processing immediately, rather than processing all packets
+         * in a batch before quitting.
+         */
+        inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld);
+        if (inpkts < 0) {
+          ld->pcap_err = TRUE;
+          ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
+        }
+      } else {
+        inpkts = 0;
         if (sel_ret < 0 && errno != EINTR) {
           g_snprintf(errmsg, errmsg_len,
             "Unexpected error from select: %s", strerror(errno));
           report_capture_error(errmsg, please_report);
           ld->go = FALSE;
         }
-      } else {
-       /*
-        * "select()" says we can read from the pipe without blocking
-        */
-       inpkts = cap_pipe_dispatch(ld, pcap_data, errmsg, errmsg_len);
-       if (inpkts < 0) {
-         ld->go = FALSE;
-        }
       }
     }
     else
-#endif /* _WIN32 */
-    {
-      /* dispatch from pcap */
-#ifdef MUST_DO_SELECT
-      /*
-       * Sigh.  The semantics of the read timeout argument to
-       * "pcap_open_live()" aren't particularly well specified by
-       * the "pcap" man page - at least with the BSD BPF code, the
-       * intent appears to be, at least in part, a way of cutting
-       * down the number of reads done on a capture, by blocking
-       * until the buffer fills or a timer expires - and the Linux
-       * libpcap doesn't actually support it, so we can't use it
-       * to break out of the "pcap_dispatch()" every 1/4 of a second
-       * or so.  Linux's libpcap is not the only libpcap that doesn't
-       * support the read timeout.
-       *
-       * Furthermore, at least on Solaris, the bufmod STREAMS module's
-       * read timeout won't go off if no data has arrived, i.e. it cannot
-       * be used to guarantee that a read from a DLPI stream will return
-       * within a specified amount of time regardless of whether any
-       * data arrives or not.
-       *
-       * Thus, on all platforms other than BSD, we do a "select()" on the
-       * file descriptor for the capture, with a timeout of CAP_READ_TIMEOUT
-       * milliseconds, or CAP_READ_TIMEOUT*1000 microseconds.
-       *
-       * "select()", on BPF devices, doesn't work as you might expect;
-       * at least on some versions of some flavors of BSD, the timer
-       * doesn't start until a read is done, so it won't expire if
-       * only a "select()" or "poll()" is posted.
-       *
-       * If we have "pcap_get_selectable_fd()", we use it to get the
-       * descriptor on which to select; if that's -1, it means there
-       * is no descriptor on which you can do a "select()" (perhaps
-       * because you're capturing on a special device, and that device's
-       * driver unfortunately doesn't support "select()", in which case
-       * we don't do the select - which means Ethereal might block,
-       * unable to accept user input, until a packet arrives.  If
-       * that's unacceptable, plead with whoever supplies the software
-       * for that device to add "select()" support.
-       */
-#ifdef LOG_CAPTURE_VERBOSE
-      g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select");
-#endif
-      if (ld->pcap_fd != -1) {
-        FD_ZERO(&set1);
-        FD_SET(ld->pcap_fd, &set1);
-        timeout.tv_sec = 0;
-        timeout.tv_usec = CAP_READ_TIMEOUT*1000;
-        sel_ret = select(ld->pcap_fd+1, &set1, NULL, NULL, &timeout);
-        if (sel_ret > 0) {
-          /*
-           * "select()" says we can read from it without blocking; go for
-           * it.
-           */
-          inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld);
-          if (inpkts < 0) {
-            ld->pcap_err = TRUE;
-            ld->go = FALSE;
-          }
-        } else {
-          inpkts = 0;
-          if (sel_ret < 0 && errno != EINTR) {
-            g_snprintf(errmsg, errmsg_len,
-              "Unexpected error from select: %s", strerror(errno));
-            report_capture_error(errmsg, please_report);
-            ld->go = FALSE;
-          }
-        }
-      }
-      else
 #endif /* MUST_DO_SELECT */
-      {
-        /* dispatch from pcap without select */
+    {
+      /* dispatch from pcap without select */
 #if 1
 #ifdef LOG_CAPTURE_VERBOSE
-        g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch");
+      g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch");
 #endif
-        inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld);
-        if (inpkts < 0) {
+#ifdef _WIN32
+      /*
+       * On Windows, we don't support asynchronously telling a process to
+       * stop capturing; instead, we check for an indication on a pipe
+       * after processing packets.  We therefore process only one packet
+       * at a time, so that we can check the pipe after every packet.
+       */
+      inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld);
+#else
+      inpkts = pcap_dispatch(ld->pcap_h, -1, ld->packet_cb, (u_char *) ld);
+#endif
+      if (inpkts < 0) {
+        if (inpkts == -1) {
+          /* Error, rather than pcap_breakloop(). */
           ld->pcap_err = TRUE;
-          ld->go = FALSE;
         }
-#else
-        {
+        ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
+      }
+#else /* pcap_next_ex */
 #ifdef LOG_CAPTURE_VERBOSE
-            g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_next_ex");
+      g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_next_ex");
 #endif
-            /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */
-
-            /* WinPcap's remote capturing feature doesn't work, see http://wiki.ethereal.com/CaptureSetup_2fWinPcapRemote */
-            /* for reference, an example remote interface: rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C} */
+      /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */
 
-            /* emulate dispatch from pcap */
-            int in;
-            struct pcap_pkthdr *pkt_header;
-                   u_char *pkt_data;
+      /*
+       * WinPcap's remote capturing feature doesn't work with pcap_dispatch(),
+       * see http://wiki.wireshark.org/CaptureSetup_2fWinPcapRemote
+       * This should be fixed in the WinPcap 4.0 alpha release.
+       *
+       * For reference, an example remote interface:
+       * rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C}
+       */
 
-            inpkts = 0;
-            while( (in = pcap_next_ex(ld->pcap_h, &pkt_header, &pkt_data)) == 1) {
-                ld->packet_cb( (u_char *) ld, pkt_header, pkt_data);
-                inpkts++;
-            }
+      /* emulate dispatch from pcap */
+      {
+        int in;
+        struct pcap_pkthdr *pkt_header;
+        u_char *pkt_data;
+
+        inpkts = 0;
+        in = 0;
+        while(ld->go &&
+              (in = pcap_next_ex(ld->pcap_h, &pkt_header, &pkt_data)) == 1) {
+          ld->packet_cb( (u_char *) ld, pkt_header, pkt_data);
+          inpkts++;
+        }
 
-            if(in < 0) {
-              ld->pcap_err = TRUE;
-              ld->go = FALSE;
-              inpkts = in;
-            }
+        if(in < 0) {
+          ld->pcap_err = TRUE;
+          ld->go = FALSE;
+          inpkts = in;
         }
-#endif
       }
+#endif /* pcap_next_ex */
     }
+  }
 
 #ifdef LOG_CAPTURE_VERBOSE
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
+  g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s"));
 #endif
 
-    return inpkts;
+  return inpkts;
 }
 
 
@@ -1069,6 +1069,9 @@ capture_loop_stop_signal_handler(int signo _U_)
 int
 capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats)
 {
+#ifndef _WIN32
+  struct sigaction act;
+#endif
   time_t      upd_time, cur_time;
   time_t      start_time;
   int         err_close;
@@ -1116,8 +1119,16 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
    * Catch SIGUSR1, so that we exit cleanly if the parent process
    * kills us with it due to the user selecting "Capture->Stop".
    */
-  signal(SIGUSR1, capture_loop_stop_signal_handler);
-#endif
+  act.sa_handler = capture_loop_stop_signal_handler;
+  /*
+   * Arrange that system calls not get restarted, because when
+   * our signal handler returns we don't want to restart
+   * a call that was waiting for packets to arrive.
+   */
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaction(SIGUSR1, &act, NULL);
+#endif /* _WIN32 */
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop starting ...");
   capture_opts_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, capture_opts);
@@ -1452,7 +1463,11 @@ error:
 
 void capture_loop_stop(void)
 {
-    ld.go = FALSE;
+#ifdef HAVE_PCAP_BREAKLOOP
+  pcap_breakloop(ld.pcap_h);
+#else
+  ld.go = FALSE;
+#endif
 }
  
 
@@ -1542,4 +1557,3 @@ capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
 }
 
 #endif /* HAVE_LIBPCAP */
-