Windows: Remove the need for _CRT_NONSTDC_NO_DEPRECATE.
[gd/wireshark/.git] / capchild / capture_sync.c
index 8efe26408a43e96f67003b9d069ca9db97ca6dda..edd0c5de7a559917020c5293752f8c63eb7a8c09 100644 (file)
 #include <stdlib.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
@@ -130,7 +122,7 @@ void
 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
@@ -347,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];
@@ -371,6 +363,7 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
 #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;
@@ -396,10 +389,10 @@ 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)) {
+    if (!extcap_init_interfaces(capture_opts)) {
         report_failure("Unable to init extcaps. (tmp fifo already exists?)");
         return FALSE;
     }
@@ -591,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),
@@ -601,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]);
         }
@@ -608,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);
@@ -651,8 +687,9 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
                       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]);
         }
@@ -660,14 +697,11 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
         return FALSE;
     }
     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( (intptr_t) 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( (intptr_t) signal_pipe, _O_BINARY);
+    cap_session->signal_pipe_write_fd = signal_pipe_write_fd;
 
 #else /* _WIN32 */
     if (pipe(sync_pipe) < 0) {
@@ -726,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);
@@ -738,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();
@@ -759,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.
  *
@@ -788,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");
@@ -820,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]);
@@ -865,9 +940,9 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
                       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]);
@@ -876,12 +951,9 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
         return -1;
     }
     *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( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
-    *message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
 #else /* _WIN32 */
     /* Create a pipe for the child process to send us messages */
     if (pipe(sync_pipe) < 0) {
@@ -960,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);
@@ -1079,6 +1151,7 @@ sync_pipe_run_command_actual(char** argv, gchar **data, gchar **primary_msg,
             }
         }
         *secondary_msg = NULL;
+        *data = NULL;
 
         return -1;
     }
@@ -1224,6 +1297,7 @@ sync_pipe_run_command(char** argv, gchar **data, gchar **primary_msg,
 
 int
 sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
+                              const gchar *center_freq1, const gchar *center_freq2,
                               gchar **data, gchar **primary_msg,
                               gchar **secondary_msg, void (*update_cb)(void))
 {
@@ -1244,7 +1318,7 @@ sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar
     argv = sync_pipe_add_arg(argv, &argc, iface);
 
     if (type)
-        opt = g_strdup_printf("%s,%s", freq, type);
+        opt = g_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2);
     else
         opt = g_strdup_printf("%s", freq);
 
@@ -1323,7 +1397,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))
 {
@@ -1347,6 +1421,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 */
@@ -1423,6 +1501,8 @@ sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **
            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
@@ -1537,7 +1617,7 @@ pipe_read_bytes(int pipe_fd, char *bytes, int required, char **msg)
     int error;
 
     while(required) {
-        newly = read(pipe_fd, &bytes[offset], required);
+        newly = ws_read(pipe_fd, &bytes[offset], required);
         if (newly == 0) {
             /* EOF */
             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
@@ -1604,7 +1684,7 @@ sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
         offset++;
         if (! pipe_data_available(pipe_fd))
             break;
-        newly = read(pipe_fd, &bytes[offset], 1);
+        newly = ws_read(pipe_fd, &bytes[offset], 1);
         if (newly == 0) {
             /* EOF - not necessarily an error */
             break;
@@ -1691,7 +1771,7 @@ pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
 
         /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
         memcpy(msg, header, sizeof(header));
-        newly = read(pipe_fd, &msg[sizeof(header)], len-sizeof(header));
+        newly = ws_read(pipe_fd, &msg[sizeof(header)], len-sizeof(header));
         if (newly < 0) { /* error */
             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
                   "read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno));
@@ -1775,7 +1855,7 @@ 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
@@ -1887,11 +1967,11 @@ sync_pipe_wait_for_child(ws_process_id 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 {
@@ -1910,6 +1990,7 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
 #else
     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
@@ -1934,15 +2015,40 @@ sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
                                         fork_child_status);
                 ret = -1;
             }
-        } else if (errno != ECHILD) {
-            *msgp = g_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
-            ret = -1;
-        } else if (errno == EINTR) {
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "sync_pipe_wait_for_child: waitpid returned EINTR. retrying.");
-            continue;
         } else {
-            /* errno == ECHILD ; echld might have already reaped the child */
-            ret = fetch_dumpcap_pid ? 0 : -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;
+            }
         }
         break;
     }
@@ -2083,7 +2189,7 @@ signal_pipe_capquit_to_child(capture_session *cap_session)
     /* it doesn't matter *what* we send here, the first byte will stop the capture */
     /* simply sending a "QUIT" string */
     /*pipe_write_block(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
-    ret = write(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
+    ret = ws_write(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
     if(ret == -1) {
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
               "signal_pipe_capquit_to_child: %d header: error %s", cap_session->signal_pipe_write_fd, g_strerror(errno));
@@ -2101,7 +2207,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);
@@ -2142,7 +2248,7 @@ sync_pipe_stop(capture_session *cap_session)
 void
 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) {