Allow "capture info data" to not be a singleton.
[metze/wireshark/wip.git] / capchild / capture_sync.c
index f744b1a92d22df6de8c039e8eb47125b41fe4eb8..6f02219d60f7b13fa5bf6e272317f8451759a99c 100644 (file)
 #include <glib.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <string.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
 #include <signal.h>
 
 #ifdef _WIN32
@@ -98,6 +89,9 @@
 #include <wsutil/filesystem.h>
 #include <wsutil/file_util.h>
 #include <wsutil/report_err.h>
+#ifdef HAVE_EXTCAP
+#include "extcap.h"
+#endif
 #include "log.h"
 
 #ifdef _WIN32
@@ -116,19 +110,19 @@ static const char *sync_pipe_signame(int);
 
 
 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
-static int sync_pipe_wait_for_child(int fork_child, gchar **msgp);
+static int sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp);
 static void pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len);
 static ssize_t pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
                            char **err_msg);
 
-static void (*fetch_dumpcap_pid)(int) = NULL;
+static void (*fetch_dumpcap_pid)(ws_process_id) = NULL;
 
 
 void
-capture_session_init(capture_session *cap_session, void *cf)
+capture_session_init(capture_session *cap_session, struct _capture_file *cf)
 {
     cap_session->cf                              = cf;
-    cap_session->fork_child                      = -1;               /* invalid process handle */
+    cap_session->fork_child                      = WS_INVALID_PID;   /* invalid process handle */
 #ifdef _WIN32
     cap_session->signal_pipe_write_fd            = -1;
 #endif
@@ -137,6 +131,7 @@ capture_session_init(capture_session *cap_session, void *cf)
     cap_session->owner                           = getuid();
     cap_session->group                           = getgid();
 #endif
+    cap_session->count                           = 0;
     cap_session->session_started                 = FALSE;
 }
 
@@ -326,7 +321,11 @@ init_pipe_args(int *argc) {
     *argv = NULL;
 
     /* take Wireshark's absolute program path and replace "Wireshark" with "dumpcap" */
-    exename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "dumpcap", progfile_dir);
+#ifdef _WIN32
+    exename = g_strdup_printf("%s\\dumpcap.exe", progfile_dir);
+#else
+    exename = g_strdup_printf("%s/dumpcap", progfile_dir);
+#endif
 
     /* Make that the first argument in the argument list (argv[0]). */
     argv = sync_pipe_add_arg(argv, argc, exename);
@@ -340,7 +339,7 @@ init_pipe_args(int *argc) {
 #define ARGV_NUMBER_LEN 24
 /* a new capture run: start a new dumpcap task and hand over parameters through command line */
 gboolean
-sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, void (*update_cb)(void))
+sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, info_data_t* cap_data, void (*update_cb)(void))
 {
     char ssnap[ARGV_NUMBER_LEN];
     char scount[ARGV_NUMBER_LEN];
@@ -357,13 +356,14 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
     char ssampling[ARGV_NUMBER_LEN];
 #endif
 
-#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
     char buffer_size[ARGV_NUMBER_LEN];
 #endif
 
 #ifdef _WIN32
     HANDLE sync_pipe_read;                  /* pipe used to send messages from child to parent */
     HANDLE sync_pipe_write;                 /* pipe used to send messages from child to parent */
+    int signal_pipe_write_fd;
     HANDLE signal_pipe;                     /* named pipe used to send messages from parent to child (currently only stop) */
     GString *args = g_string_sized_new(200);
     gchar *quoted_arg;
@@ -389,7 +389,15 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_start");
     capture_opts_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, capture_opts);
 
-    cap_session->fork_child = -1;
+    cap_session->fork_child = WS_INVALID_PID;
+
+#ifdef HAVE_EXTCAP
+    if (!extcaps_init_initerfaces(capture_opts)) {
+        report_failure("Unable to init extcaps. (tmp fifo already exists?)");
+        return FALSE;
+    }
+
+#endif
 
     argv = init_pipe_args(&argc);
     if (!argv) {
@@ -463,7 +471,12 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         interface_opts = g_array_index(capture_opts->ifaces, interface_options, j);
 
         argv = sync_pipe_add_arg(argv, &argc, "-i");
-        argv = sync_pipe_add_arg(argv, &argc, interface_opts.name);
+#ifdef HAVE_EXTCAP
+        if (interface_opts.extcap_fifo != NULL)
+            argv = sync_pipe_add_arg(argv, &argc, interface_opts.extcap_fifo);
+        else
+#endif
+            argv = sync_pipe_add_arg(argv, &argc, interface_opts.name);
 
         if (interface_opts.cfilter != NULL && strlen(interface_opts.cfilter) != 0) {
             argv = sync_pipe_add_arg(argv, &argc, "-f");
@@ -476,17 +489,23 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         }
 
         if (interface_opts.linktype != -1) {
-            argv = sync_pipe_add_arg(argv, &argc, "-y");
-            argv = sync_pipe_add_arg(argv, &argc, linktype_val_to_name(interface_opts.linktype));
+            const char *linktype = linktype_val_to_name(interface_opts.linktype);
+            if ( linktype != NULL )
+            {
+                argv = sync_pipe_add_arg(argv, &argc, "-y");
+                argv = sync_pipe_add_arg(argv, &argc, linktype);
+            }
         }
 
         if (!interface_opts.promisc_mode) {
             argv = sync_pipe_add_arg(argv, &argc, "-p");
         }
 
-#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
         if (interface_opts.buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE) {
             argv = sync_pipe_add_arg(argv, &argc, "-B");
+            if(interface_opts.buffer_size == 0x00)
+                interface_opts.buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
             g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d", interface_opts.buffer_size);
             argv = sync_pipe_add_arg(argv, &argc, buffer_size);
         }
@@ -565,6 +584,26 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         return FALSE;
     }
 
+    /*
+     * Associate a C run-time file handle with the Windows HANDLE for the
+     * read side of the message pipe.
+     *
+     * (See http://www.flounder.com/handles.htm for information on various
+     * types of file handle in C/C++ on Windows.)
+     */
+    sync_pipe_read_fd = _open_osfhandle( (intptr_t) sync_pipe_read, _O_BINARY);
+    if (sync_pipe_read_fd == -1) {
+        /* Couldn't create the pipe between parent and child. */
+        report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+        CloseHandle(sync_pipe_read);
+        CloseHandle(sync_pipe_write);
+        for (i = 0; i < argc; i++) {
+            g_free( (gpointer) argv[i]);
+        }
+        g_free(argv);
+        return FALSE;
+    }
+
     /* Create the signal pipe */
     signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, control_id);
     signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
@@ -575,6 +614,8 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         /* Couldn't create the signal pipe between parent and child. */
         report_failure("Couldn't create signal pipe: %s",
                        win32strerror(GetLastError()));
+        ws_close(sync_pipe_read_fd);    /* Should close sync_pipe_read */
+        CloseHandle(sync_pipe_write);
         for (i = 0; i < argc; i++) {
             g_free( (gpointer) argv[i]);
         }
@@ -582,6 +623,27 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         return FALSE;
     }
 
+    /*
+     * Associate a C run-time file handle with the Windows HANDLE for the
+     * read side of the message pipe.
+     *
+     * (See http://www.flounder.com/handles.htm for information on various
+     * types of file handle in C/C++ on Windows.)
+     */
+    signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
+    if (sync_pipe_read_fd == -1) {
+        /* Couldn't create the pipe between parent and child. */
+        report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+        ws_close(sync_pipe_read_fd);    /* Should close sync_pipe_read */
+        CloseHandle(sync_pipe_write);
+        CloseHandle(signal_pipe);
+        for (i = 0; i < argc; i++) {
+            g_free( (gpointer) argv[i]);
+        }
+        g_free(argv);
+        return FALSE;
+    }
+
     /* init STARTUPINFO */
     memset(&si, 0, sizeof(si));
     si.cb           = sizeof(si);
@@ -591,7 +653,20 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
 #else
     si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
     si.wShowWindow  = SW_HIDE;  /* this hides the console window */
-    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+#if defined(_WIN32)
+    /* needs first a check if NULL *
+     * otherwise wouldn't work with non extcap interfaces */
+    if(interface_opts.extcap_fifo != NULL)
+    {
+       if(strncmp(interface_opts.extcap_fifo,"\\\\.\\pipe\\",9)== 0)
+       {
+         si.hStdInput = extcap_get_win32_handle();
+       }
+    }
+    else
+#endif
+       si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+
     si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     si.hStdError = sync_pipe_write;
     /*si.hStdError = (HANDLE) _get_osfhandle(2);*/
@@ -608,27 +683,25 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
     }
 
     /* call dumpcap */
-    if(!CreateProcess(NULL, utf_8to16(args->str), NULL, NULL, TRUE,
+    if(!CreateProcess(utf_8to16(argv[0]), utf_8to16(args->str), NULL, NULL, TRUE,
                       CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
         report_failure("Couldn't run %s in child process: %s",
                        args->str, win32strerror(GetLastError()));
-        CloseHandle(sync_pipe_read);
+        ws_close(sync_pipe_read_fd);    /* Should close sync_pipe_read */
         CloseHandle(sync_pipe_write);
+        CloseHandle(signal_pipe);
         for (i = 0; i < argc; i++) {
             g_free( (gpointer) argv[i]);
         }
         g_free( (gpointer) argv);
         return FALSE;
     }
-    cap_session->fork_child = (int) pi.hProcess;
+    cap_session->fork_child = pi.hProcess;
+    /* We may need to store this and close it later */
+    CloseHandle(pi.hThread);
     g_string_free(args, TRUE);
 
-    /* associate the operating system filehandle to a C run-time file handle */
-    /* (good file handle infos at: http://www.flounder.com/handles.htm) */
-    sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
-
-    /* associate the operating system filehandle to a C run-time file handle */
-    cap_session->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe, _O_BINARY);
+    cap_session->signal_pipe_write_fd = signal_pipe_write_fd;
 
 #else /* _WIN32 */
     if (pipe(sync_pipe) < 0) {
@@ -687,7 +760,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
     ws_close(sync_pipe[PIPE_WRITE]);
 #endif
 
-    if (cap_session->fork_child == -1) {
+    if (cap_session->fork_child == WS_INVALID_PID) {
         /* We couldn't even create the child process. */
         report_failure("Couldn't create child process: %s", g_strerror(errno));
         ws_close(sync_pipe_read_fd);
@@ -699,6 +772,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
 
     cap_session->fork_child_status = 0;
     cap_session->capture_opts = capture_opts;
+    cap_session->cap_data_info = cap_data;
 
     /* we might wait for a moment till child is ready, so update screen now */
     if (update_cb) update_cb();
@@ -720,7 +794,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
  * standard output and one for its standard error.
  *
  * On success, *msg is unchanged and 0 is returned; data_read_fd,
- * messsage_read_fd, and fork_child point to the standard output pipe's
+ * message_read_fd, and fork_child point to the standard output pipe's
  * file descriptor, the standard error pipe's file descriptor, and
  * the child's PID/handle, respectively.
  *
@@ -732,7 +806,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
 #define PIPE_BUF_SIZE 5120
 static int
 sync_pipe_open_command(char** argv, int *data_read_fd,
-                       int *message_read_fd, int *fork_child, gchar **msg, void(*update_cb)(void))
+                       int *message_read_fd, ws_process_id *fork_child, gchar **msg, void(*update_cb)(void))
 {
     enum PIPES { PIPE_READ, PIPE_WRITE };   /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
 #ifdef _WIN32
@@ -749,7 +823,7 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
     int data_pipe[2];                       /* pipe used to send data from child to parent */
 #endif
     int i;
-    *fork_child = -1;
+    *fork_child = WS_INVALID_PID;
     *data_read_fd = -1;
     *message_read_fd = -1;
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_open_command");
@@ -781,13 +855,53 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
         return -1;
     }
 
+    /*
+     * Associate a C run-time file handle with the Windows HANDLE for the
+     * read side of the message pipe.
+     *
+     * (See http://www.flounder.com/handles.htm for information on various
+     * types of file handle in C/C++ on Windows.)
+     */
+    *message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
+    if (*message_read_fd == -1) {
+        *msg = g_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno));
+        CloseHandle(sync_pipe[PIPE_READ]);
+        CloseHandle(sync_pipe[PIPE_WRITE]);
+        for (i = 0; argv[i] != NULL; i++) {
+            g_free( (gpointer) argv[i]);
+        }
+        g_free( (gpointer) argv);
+        return -1;
+    }
+
     /* Create a pipe for the child process to send us data */
     /* (increase this value if you have trouble while fast capture file switches) */
     if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
         /* Couldn't create the message pipe between parent and child. */
         *msg = g_strdup_printf("Couldn't create data pipe: %s",
                                win32strerror(GetLastError()));
-        CloseHandle(sync_pipe[PIPE_READ]);
+        ws_close(*message_read_fd);    /* Should close sync_pipe[PIPE_READ] */
+        CloseHandle(sync_pipe[PIPE_WRITE]);
+        for (i = 0; argv[i] != NULL; i++) {
+            g_free( (gpointer) argv[i]);
+        }
+        g_free( (gpointer) argv);
+        return -1;
+    }
+
+    /*
+     * Associate a C run-time file handle with the Windows HANDLE for the
+     * read side of the data pipe.
+     *
+     * (See http://www.flounder.com/handles.htm for information on various
+     * types of file handle in C/C++ on Windows.)
+     */
+    *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
+    if (*data_read_fd == -1) {
+        *msg = g_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno));
+        CloseHandle(data_pipe[PIPE_READ]);
+        CloseHandle(data_pipe[PIPE_WRITE]);
+        ws_close(*message_read_fd);    /* Should close sync_pipe[PIPE_READ] */
         CloseHandle(sync_pipe[PIPE_WRITE]);
         for (i = 0; argv[i] != NULL; i++) {
             g_free( (gpointer) argv[i]);
@@ -805,7 +919,8 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
 #else
     si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
     si.wShowWindow  = SW_HIDE;  /* this hides the console window */
-    si.hStdInput = NULL;
+    si.hStdInput = NULL; /* handle for named pipe*/
+
     si.hStdOutput = data_pipe[PIPE_WRITE];
     si.hStdError = sync_pipe[PIPE_WRITE];
 #endif
@@ -821,13 +936,13 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
     }
 
     /* call dumpcap */
-    if(!CreateProcess(NULL, utf_8to16(args->str), NULL, NULL, TRUE,
+    if(!CreateProcess(utf_8to16(argv[0]), utf_8to16(args->str), NULL, NULL, TRUE,
                       CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
         *msg = g_strdup_printf("Couldn't run %s in child process: %s",
                                args->str, win32strerror(GetLastError()));
-        CloseHandle(data_pipe[PIPE_READ]);
+        ws_close(*data_read_fd);       /* Should close data_pipe[PIPE_READ] */
         CloseHandle(data_pipe[PIPE_WRITE]);
-        CloseHandle(sync_pipe[PIPE_READ]);
+        ws_close(*message_read_fd);    /* Should close sync_pipe[PIPE_READ] */
         CloseHandle(sync_pipe[PIPE_WRITE]);
         for (i = 0; argv[i] != NULL; i++) {
             g_free( (gpointer) argv[i]);
@@ -835,13 +950,10 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
         g_free( (gpointer) argv);
         return -1;
     }
-    *fork_child = (int) pi.hProcess;
+    *fork_child = pi.hProcess;
+    /* We may need to store this and close it later */
+    CloseHandle(pi.hThread);
     g_string_free(args, TRUE);
-
-    /* associate the operating system filehandles to C run-time file handles */
-    /* (good file handle infos at: http://www.flounder.com/handles.htm) */
-    *data_read_fd = _open_osfhandle( (long) data_pipe[PIPE_READ], _O_BINARY);
-    *message_read_fd = _open_osfhandle( (long) sync_pipe[PIPE_READ], _O_BINARY);
 #else /* _WIN32 */
     /* Create a pipe for the child process to send us messages */
     if (pipe(sync_pipe) < 0) {
@@ -920,7 +1032,7 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
     ws_close(sync_pipe[PIPE_WRITE]);
 #endif
 
-    if (*fork_child == -1) {
+    if (*fork_child == WS_INVALID_PID) {
         /* We couldn't even create the child process. */
         *msg = g_strdup_printf("Couldn't create child process: %s", g_strerror(errno));
         ws_close(*data_read_fd);
@@ -943,7 +1055,7 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
  */
 static int
 sync_pipe_close_command(int *data_read_fd, int *message_read_fd,
-                        int *fork_child, gchar **msgp)
+       ws_process_id *fork_child, gchar **msgp)
 {
     ws_close(*data_read_fd);
     if (message_read_fd != NULL)
@@ -977,7 +1089,8 @@ sync_pipe_run_command_actual(char** argv, gchar **data, gchar **primary_msg,
                       gchar **secondary_msg,  void(*update_cb)(void))
 {
     gchar *msg;
-    int data_pipe_read_fd, sync_pipe_read_fd, fork_child, ret;
+    int data_pipe_read_fd, sync_pipe_read_fd, ret;
+    ws_process_id fork_child;
     char *wait_msg;
     gchar buffer[PIPE_BUF_SIZE+1] = {0};
     ssize_t nread;
@@ -1038,6 +1151,7 @@ sync_pipe_run_command_actual(char** argv, gchar **data, gchar **primary_msg,
             }
         }
         *secondary_msg = NULL;
+        *data = NULL;
 
         return -1;
     }
@@ -1112,8 +1226,7 @@ sync_pipe_run_command_actual(char** argv, gchar **data, gchar **primary_msg,
              */
             *primary_msg = NULL;
             *secondary_msg = NULL;
-            *data = data_buf->str;
-            g_string_free(data_buf, FALSE);
+            *data = g_string_free(data_buf, FALSE);
         }
         break;
 
@@ -1283,7 +1396,7 @@ sync_interface_list_open(gchar **data, gchar **primary_msg,
  * must be freed with g_free().
  */
 int
-sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
+sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gchar* auth,
                           gchar **data, gchar **primary_msg,
                           gchar **secondary_msg, void (*update_cb)(void))
 {
@@ -1307,6 +1420,10 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
     argv = sync_pipe_add_arg(argv, &argc, "-L");
     if (monitor_mode)
         argv = sync_pipe_add_arg(argv, &argc, "-I");
+    if (auth) {
+        argv = sync_pipe_add_arg(argv, &argc, "-A");
+        argv = sync_pipe_add_arg(argv, &argc, auth);
+    }
 
 #ifndef DEBUG_CHILD
     /* Run dumpcap in capture child mode */
@@ -1323,7 +1440,7 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
  * that must be g_free()d, and -1 will be returned.
  */
 int
-sync_interface_stats_open(int *data_read_fd, int *fork_child, gchar **msg, void (*update_cb)(void))
+sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **msg, void (*update_cb)(void))
 {
     int argc;
     char **argv;
@@ -1383,6 +1500,8 @@ sync_interface_stats_open(int *data_read_fd, int *fork_child, gchar **msg, void
            case, the child will get an error when writing to the broken pipe
            the next time, cleaning itself up then. */
         ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
+        ws_close(message_read_fd);
+        ws_close(*data_read_fd);
         if(nread == 0) {
             /* We got an EOF from the sync pipe.  That means that it exited
                before giving us any data to read.  If ret is -1, we report
@@ -1475,7 +1594,7 @@ sync_interface_stats_open(int *data_read_fd, int *fork_child, gchar **msg, void
 
 /* Close down the stats process */
 int
-sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg)
+sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, gchar **msg)
 {
 #ifndef _WIN32
     /*
@@ -1735,11 +1854,15 @@ sync_pipe_input_cb(gint source, gpointer user_data)
         }
 
         /* No more child process. */
-        cap_session->fork_child = -1;
+        cap_session->fork_child = WS_INVALID_PID;
         cap_session->fork_child_status = ret;
 
 #ifdef _WIN32
         ws_close(cap_session->signal_pipe_write_fd);
+#endif
+#ifdef HAVE_EXTCAP
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: cleaning extcap pipe");
+        extcap_cleanup(cap_session->capture_opts);
 #endif
         capture_input_closed(cap_session, primary_msg);
         g_free(primary_msg);
@@ -1776,6 +1899,7 @@ sync_pipe_input_cb(gint source, gpointer user_data)
     case SP_PACKET_COUNT:
         npackets = atoi(buffer);
         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", npackets);
+        cap_session->count += npackets;
         capture_input_new_packets(cap_session, npackets);
         break;
     case SP_ERROR_MSG:
@@ -1824,10 +1948,13 @@ sync_pipe_input_cb(gint source, gpointer user_data)
  * must be freed with g_free().
  */
 static int
-sync_pipe_wait_for_child(int fork_child, gchar **msgp)
+sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
 {
     int fork_child_status;
-    int ret;
+#ifndef _WIN32
+    int retry_waitpid = 3;
+#endif
+    int ret = -1;
     GTimeVal start_time;
     GTimeVal end_time;
     float elapsed;
@@ -1839,11 +1966,11 @@ sync_pipe_wait_for_child(int fork_child, gchar **msgp)
     g_get_current_time(&start_time);
 
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
-    g_assert(fork_child != -1);
+    g_assert(fork_child != WS_INVALID_PID);
 
     *msgp = NULL; /* assume no error */
 #ifdef _WIN32
-    if (_cwait(&fork_child_status, fork_child, _WAIT_CHILD) == -1) {
+    if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
         *msgp = g_strdup_printf("Error from cwait(): %s", g_strerror(errno));
         ret = -1;
     } else {
@@ -1860,37 +1987,69 @@ sync_pipe_wait_for_child(int fork_child, gchar **msgp)
         }
     }
 #else
-    if (waitpid(fork_child, &fork_child_status, 0) != -1) {
-        if (WIFEXITED(fork_child_status)) {
-            /*
-             * The child exited; return its exit status.  Do not treat this as
-             * an error.
-             */
-            ret = WEXITSTATUS(fork_child_status);
-        } else if (WIFSTOPPED(fork_child_status)) {
-            /* It stopped, rather than exiting.  "Should not happen." */
-            *msgp = g_strdup_printf("Child dumpcap process stopped: %s",
-                                    sync_pipe_signame(WSTOPSIG(fork_child_status)));
-            ret = -1;
-        } else if (WIFSIGNALED(fork_child_status)) {
-            /* It died with a signal. */
-            *msgp = g_strdup_printf("Child dumpcap process died: %s%s",
-                                    sync_pipe_signame(WTERMSIG(fork_child_status)),
-                                    WCOREDUMP(fork_child_status) ? " - core dumped" : "");
-            ret = -1;
+    while (--retry_waitpid >= 0) {
+        if (waitpid(fork_child, &fork_child_status, 0) != -1) {
+            /* waitpid() succeeded */
+            if (WIFEXITED(fork_child_status)) {
+                /*
+                 * The child exited; return its exit status.  Do not treat this as
+                 * an error.
+                 */
+                ret = WEXITSTATUS(fork_child_status);
+            } else if (WIFSTOPPED(fork_child_status)) {
+                /* It stopped, rather than exiting.  "Should not happen." */
+                *msgp = g_strdup_printf("Child dumpcap process stopped: %s",
+                                        sync_pipe_signame(WSTOPSIG(fork_child_status)));
+                ret = -1;
+            } else if (WIFSIGNALED(fork_child_status)) {
+                /* It died with a signal. */
+                *msgp = g_strdup_printf("Child dumpcap process died: %s%s",
+                                        sync_pipe_signame(WTERMSIG(fork_child_status)),
+                                        WCOREDUMP(fork_child_status) ? " - core dumped" : "");
+                ret = -1;
+            } else {
+                /* What?  It had to either have exited, or stopped, or died with
+                   a signal; what happened here? */
+                *msgp = g_strdup_printf("Bad status from waitpid(): %#o",
+                                        fork_child_status);
+                ret = -1;
+            }
         } else {
-            /* What?  It had to either have exited, or stopped, or died with
-               a signal; what happened here? */
-            *msgp = g_strdup_printf("Bad status from waitpid(): %#o",
-                                    fork_child_status);
-            ret = -1;
+            /* waitpid() failed */
+            if (errno == EINTR) {
+                /*
+                 * Signal interrupted waitpid().
+                 *
+                 * If it's SIGALRM, we just want to keep waiting, in case
+                 * there's some timer using it (e.g., in a GUI toolkit).
+                 *
+                 * If you ^C TShark (or Wireshark), that should deliver
+                 * SIGINT to dumpcap as well.  dumpcap catches SIGINT,
+                 * and should clean up and exit, so we should eventually
+                 * see that and clean up and terminate.
+                 *
+                 * If we're sent a SIGTERM, we should (and do) catch it,
+                 * and TShark, at least, calls sync_pipe_stop(). which
+                 * kills dumpcap, so we should eventually see that and
+                 * clean up and terminate.
+                 */
+                g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "sync_pipe_wait_for_child: waitpid returned EINTR. retrying.");
+                continue;
+            } else if (errno == ECHILD) {
+                /*
+                 * The process identified by fork_child either doesn't
+                 * exist any more or isn't our child process (anymore?).
+                 *
+                 * echld might have already reaped the child.
+                 */
+               ret = fetch_dumpcap_pid ? 0 : -1;
+            } else {
+                /* Unknown error. */
+                *msgp = g_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
+                ret = -1;
+            }
         }
-    } else if (errno != ECHILD) {
-        *msgp = g_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
-        ret = -1;
-    } else {
-        /* errno == ECHILD ; echld might have already reaped the child */
-        ret = fetch_dumpcap_pid ? 0 : -1;
+        break;
     }
 #endif
 
@@ -2047,8 +2206,7 @@ sync_pipe_stop(capture_session *cap_session)
     DWORD childstatus;
     gboolean terminate = TRUE;
 #endif
-
-    if (cap_session->fork_child != -1) {
+    if (cap_session->fork_child != WS_INVALID_PID) {
 #ifndef _WIN32
         /* send the SIGINT signal to close the capture child gracefully. */
         int sts = kill(cap_session->fork_child, SIGINT);
@@ -2087,9 +2245,9 @@ sync_pipe_stop(capture_session *cap_session)
 
 /* Wireshark has to exit, force the capture child to close */
 void
-sync_pipe_kill(int fork_child)
+sync_pipe_kill(ws_process_id fork_child)
 {
-    if (fork_child != -1) {
+    if (fork_child != WS_INVALID_PID) {
 #ifndef _WIN32
         int sts = kill(fork_child, SIGTERM);    /* SIGTERM so it can clean up if necessary */
         if (sts != 0) {
@@ -2116,11 +2274,12 @@ sync_pipe_kill(int fork_child)
          * And this also will require to have the process id.
          */
         TerminateProcess((HANDLE) (fork_child), 0);
+
 #endif
     }
 }
 
-void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(int pid)) {
+void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid)) {
     fetch_dumpcap_pid = cb;
 }