-GArik: fix typo
[oweals/gnunet.git] / src / util / os_priority.c
index d27642a58bc1c23e40eea616f8f5b177868e2881..b1cf2fbff0c1794466c25b6e7174b71d1e685ca1 100644 (file)
 #include "gnunet_common.h"
 #include "gnunet_os_lib.h"
 #include "gnunet_scheduler_lib.h"
+#include "gnunet_strings_lib.h"
 #include "disk.h"
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
 
+#define DEBUG_OS GNUNET_EXTRA_LOGGING
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
@@ -60,13 +69,12 @@ parent_control_handler (void *cls,
   int sig;
 
 #if DEBUG_OS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n",
-              __FUNCTION__, tc->reason);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__,
+       tc->reason);
 #endif
-  if (tc->
-      reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN |
-                GNUNET_SCHEDULER_REASON_TIMEOUT |
-                GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  if (tc->reason &
+      (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT |
+       GNUNET_SCHEDULER_REASON_PREREQ_DONE))
   {
     GNUNET_DISK_npipe_close (control_pipe);
   }
@@ -75,14 +83,13 @@ parent_control_handler (void *cls,
     if (GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)) !=
         sizeof (sig))
     {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
       GNUNET_DISK_npipe_close (control_pipe);
     }
     else
     {
 #if DEBUG_OS
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n",
-                  sig);
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig);
 #endif
       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                       control_pipe, &parent_control_handler,
@@ -107,9 +114,9 @@ GNUNET_OS_install_parent_control_handler (void *cls,
   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
   if ((env_buf == NULL) || (strlen (env_buf) <= 0))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _("Not installing a handler because $%s=%s\n"),
-                GNUNET_OS_CONTROL_PIPE, env_buf);
+    LOG (GNUNET_ERROR_TYPE_INFO, _("Not installing a handler because $%s=%s\n"),
+         GNUNET_OS_CONTROL_PIPE, env_buf);
+    putenv ("GNUNET_OS_CONTROL_PIPE=");
     return;
   }
   control_pipe =
@@ -118,16 +125,17 @@ GNUNET_OS_install_parent_control_handler (void *cls,
                               GNUNET_DISK_PERM_USER_WRITE);
   if (control_pipe == NULL)
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
+    putenv ("GNUNET_OS_CONTROL_PIPE=");
     return;
   }
 #if DEBUG_OS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Adding parent control handler pipe `%s' to the scheduler\n",
-              env_buf);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
 #endif
   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
                                   &parent_control_handler, control_pipe);
+  putenv ("GNUNET_OS_CONTROL_PIPE=");
 }
 
 
@@ -166,20 +174,20 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
     {
       /* Child process is not controllable via pipe */
 #if DEBUG_OS
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Child process is not controllable, will kill it directly\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Child process is not controllable, will kill it directly\n");
 #endif
     }
     else if (errno == EPIPE)
     {
 #if DEBUG_OS
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Failed to write into control pipe, because pipe is invalid (the child is most likely dead)\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Failed to write into control pipe, because pipe is invalid (the child is most likely dead)\n");
 #endif
     }
     else
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Failed to write into control pipe , errno is %d\n", errno);
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           "Failed to write into control pipe , errno is %d\n", errno);
 #if WINDOWS && !defined(__CYGWIN__)
     TerminateProcess (proc->handle, 0);
 #else
@@ -189,8 +197,8 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   else
   {
 #if DEBUG_OS
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Wrote control code into control pipe, now waiting\n");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Wrote control code into control pipe, now waiting\n");
 #endif
 
 #if WINDOWS
@@ -297,7 +305,7 @@ extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
  * @param proc pointer to process structure
  */
 static DWORD_WINAPI
-ChildWaitThread (void *arg)
+child_wait_thread (void *arg)
 {
   struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg;
 
@@ -395,8 +403,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
     errno = 0;
     if ((delta != 0) && (rprio == nice (delta)) && (errno != 0))
     {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
-                           "nice");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice");
       return GNUNET_SYSERR;
     }
   }
@@ -404,15 +411,15 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
   {
     if (0 != setpriority (PRIO_PROCESS, pid, rprio))
     {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
-                           "setpriority");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+                    "setpriority");
       return GNUNET_SYSERR;
     }
   }
 #else
 #if DEBUG_OS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-              "Priority management not availabe for this platform\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+       "Priority management not availabe for this platform\n");
 #endif
 #endif
   return GNUNET_OK;
@@ -527,16 +534,15 @@ CreateCustomEnvTable (char **vars)
  * @param pipe_stdin pipe to use to send input to child process (or NULL)
  * @param pipe_stdout pipe to use to get output from child process (or NULL)
  * @param filename name of the binary
- * @param va NULL-terminated list of arguments to the process
+ * @param argv NULL-terminated array of arguments to the process
  * @return pointer to process structure of the new process, NULL on error
  */
 struct GNUNET_OS_Process *
-GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
-                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
-                            const char *filename, va_list va)
+GNUNET_OS_start_process_vap (struct GNUNET_DISK_PipeHandle *pipe_stdin,
+                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                            const char *filename, 
+                            char *const argv[])
 {
-  va_list ap;
-
 #if ENABLE_WINDOWS_WORKAROUNDS
   char *childpipename = NULL;
   struct GNUNET_DISK_FileHandle *control_pipe = NULL;
@@ -545,8 +551,6 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 
 #ifndef MINGW
   pid_t ret;
-  char **argv;
-  int argc;
   int fd_stdout_write;
   int fd_stdout_read;
   int fd_stdin_read;
@@ -560,20 +564,6 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   if (control_pipe == NULL)
     return NULL;
 #endif
-
-  argc = 0;
-  va_copy (ap, va);
-  while (NULL != va_arg (ap, char *))
-         argc++;
-
-  va_end (ap);
-  argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
-  argc = 0;
-  va_copy (ap, va);
-  while (NULL != (argv[argc] = va_arg (ap, char *)))
-         argc++;
-
-  va_end (ap);
   if (pipe_stdout != NULL)
   {
     GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
@@ -594,45 +584,24 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
                                        &fd_stdin_write, sizeof (int));
   }
 
-#if HAVE_WORKING_VFORK
-  ret = vfork ();
-#else
   ret = fork ();
-#endif
   if (ret != 0)
   {
     if (ret == -1)
     {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
 #if ENABLE_WINDOWS_WORKAROUNDS
       GNUNET_DISK_npipe_close (control_pipe);
 #endif
     }
     else
     {
-
-#if HAVE_WORKING_VFORK
-      /* let's hope vfork actually works; for some extreme cases (including
-       * a testcase) we need 'execvp' to have run before we return, since
-       * we may send a signal to the process next and we don't want it
-       * to be caught by OUR signal handler (but either by the default
-       * handler or the actual handler as installed by the process itself). */
-#else
-      /* let's give the child process a chance to run execvp, 1s should
-       * be plenty in practice */
-      if (pipe_stdout != NULL)
-        GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
-      if (pipe_stdin != NULL)
-        GNUNET_DISK_pipe_close_end (pipe_stdin, GNUNET_DISK_PIPE_END_READ);
-      sleep (1);
-#endif
       gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
       gnunet_proc->pid = ret;
 #if ENABLE_WINDOWS_WORKAROUNDS
       gnunet_proc->control_pipe = control_pipe;
 #endif
     }
-    GNUNET_free (argv);
 #if ENABLE_WINDOWS_WORKAROUNDS
     GNUNET_free (childpipename);
 #endif
@@ -648,7 +617,7 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   {
     GNUNET_break (0 == close (fd_stdout_read));
     if (-1 == dup2 (fd_stdout_write, 1))
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
     GNUNET_break (0 == close (fd_stdout_write));
   }
 
@@ -657,19 +626,19 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 
     GNUNET_break (0 == close (fd_stdin_write));
     if (-1 == dup2 (fd_stdin_read, 0))
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
     GNUNET_break (0 == close (fd_stdin_read));
   }
   execvp (filename, argv);
-  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
+  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
   _exit (1);
 #else
   char *arg;
   unsigned int cmdlen;
   char *cmd, *idx;
-  STARTUPINFO start;
+  STARTUPINFOW start;
   PROCESS_INFORMATION proc;
-
+  int argc;
   HANDLE stdin_handle;
   HANDLE stdout_handle;
 
@@ -684,6 +653,7 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   char *libdir;
   char *ptr;
   char *non_const_filename;
+  wchar_t wpath[MAX_PATH + 1], wcmd[32768];
 
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
@@ -723,8 +693,8 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
             path, NULL))
   {
     SetErrnoFromWinError (GetLastError ());
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
-                              non_const_filename);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
+                       non_const_filename);
     GNUNET_free (non_const_filename);
     GNUNET_free (pathbuf);
     return NULL;
@@ -733,26 +703,24 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   GNUNET_free (non_const_filename);
 
   cmdlen = 0;
-  va_copy (ap, va);
-  while (NULL != (arg = va_arg (ap, char *)))
+  argc = 0;
+  while (NULL != (arg = argv[argc++]))
   {
     if (cmdlen == 0)
       cmdlen = cmdlen + strlen (path) + 3;
     else
       cmdlen = cmdlen + strlen (arg) + 3;
   }
-  va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
-  va_copy (ap, va);
-  while (NULL != (arg = va_arg (ap, char *)))
+  argc = 0;
+  while (NULL != (arg = argv[argc++]))
   {
     if (idx == cmd)
       idx += sprintf (idx, "\"%s\" ", path);
     else
       idx += sprintf (idx, "\"%s\" ", arg);
   }
-  va_end (ap);
 
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
@@ -789,8 +757,8 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   }
 
 #if DEBUG_OS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Opened the parent end of the pipe `%s'\n", childpipename);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
+       childpipename);
 #endif
 
   GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
@@ -800,12 +768,14 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   GNUNET_free (our_env[0]);
   GNUNET_free (our_env[1]);
 
-  if (!CreateProcessA
-      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
+  if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)
+      || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd)
+      || !CreateProcessW
+      (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
        env_block, NULL, &start, &proc))
   {
     SetErrnoFromWinError (GetLastError ());
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     return NULL;
@@ -818,7 +788,7 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = control_pipe;
 
-  CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
+  CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
 
   ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
@@ -830,6 +800,46 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 }
 
 
+/**
+ * Start a process.
+ *
+ * @param pipe_stdin pipe to use to send input to child process (or NULL)
+ * @param pipe_stdout pipe to use to get output from child process (or NULL)
+ * @param filename name of the binary
+ * @param va NULL-terminated list of arguments to the process
+ * @return pointer to process structure of the new process, NULL on error
+ */
+struct GNUNET_OS_Process *
+GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
+                            struct GNUNET_DISK_PipeHandle *pipe_stdout,
+                            const char *filename, va_list va)
+{
+  struct GNUNET_OS_Process *ret;
+  va_list ap;
+  char **argv;
+  int argc;
+
+  argc = 0;
+  va_copy (ap, va);
+  while (NULL != va_arg (ap, char *))
+    argc++;
+  va_end (ap);
+  argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
+  argc = 0;
+  va_copy (ap, va);
+  while (NULL != (argv[argc] = va_arg (ap, char *)))
+    argc++;
+  va_end (ap);
+  ret = GNUNET_OS_start_process_vap (pipe_stdin,
+                                    pipe_stdout,
+                                    filename,
+                                    argv);
+  GNUNET_free (argv);
+  return ret;
+}
+
+
+
 /**
  * Start a process.
  *
@@ -866,7 +876,8 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
  * @return process ID of the new process, -1 on error
  */
 struct GNUNET_OS_Process *
-GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
+GNUNET_OS_start_process_v (const SOCKTYPE *lsocks,
+                           const char *filename,
                            char *const argv[])
 {
 #if ENABLE_WINDOWS_WORKAROUNDS
@@ -905,33 +916,18 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
       GNUNET_array_append (lscp, ls, k);
     GNUNET_array_append (lscp, ls, -1);
   }
-#if HAVE_WORKING_VFORK
-  ret = vfork ();
-#else
   ret = fork ();
-#endif
   if (ret != 0)
   {
     if (ret == -1)
     {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
 #if ENABLE_WINDOWS_WORKAROUNDS
       GNUNET_DISK_npipe_close (control_pipe);
 #endif
     }
     else
     {
-#if HAVE_WORKING_VFORK
-      /* let's hope vfork actually works; for some extreme cases (including
-       * a testcase) we need 'execvp' to have run before we return, since
-       * we may send a signal to the process next and we don't want it
-       * to be caught by OUR signal handler (but either by the default
-       * handler or the actual handler as installed by the process itself). */
-#else
-      /* let's give the child process a chance to run execvp, 1s should
-       * be plenty in practice */
-      sleep (1);
-#endif
       gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
       gnunet_proc->pid = ret;
 #if ENABLE_WINDOWS_WORKAROUNDS
@@ -995,20 +991,20 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
   }
   GNUNET_array_grow (lscp, ls, 0);
   execvp (filename, argv);
-  GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
+  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
   _exit (1);
 #else
   char **arg, **non_const_argv;
   unsigned int cmdlen;
   char *cmd, *idx;
-  STARTUPINFO start;
+  STARTUPINFOW start;
   PROCESS_INFORMATION proc;
   int argcount = 0;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
 
   char path[MAX_PATH + 1];
 
-  char *our_env[3] = { NULL, NULL, NULL };
+  char *our_env[5] = { NULL, NULL, NULL, NULL, NULL };
   char *env_block = NULL;
   char *pathbuf;
   DWORD pathbuf_len, alloc_len;
@@ -1017,8 +1013,13 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
   char *libdir;
   char *ptr;
   char *non_const_filename;
+  struct GNUNET_DISK_PipeHandle *lsocks_pipe;
+  const struct GNUNET_DISK_FileHandle *lsocks_write_fd;
+  HANDLE lsocks_read;
+  HANDLE lsocks_write;
+  wchar_t wpath[MAX_PATH + 1], wcmd[32768];
 
-  GNUNET_assert (lsocks == NULL);
+  int fail;
 
   /* Search in prefix dir (hopefully - the directory from which
    * the current module was loaded), bindir and libdir, then in PATH
@@ -1063,8 +1064,8 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
             path, NULL))
   {
     SetErrnoFromWinError (GetLastError ());
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
-                              non_const_filename);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath",
+                       non_const_filename);
     GNUNET_free (non_const_filename);
     GNUNET_free (pathbuf);
     return NULL;
@@ -1132,25 +1133,60 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
     GNUNET_free (path);
     return NULL;
   }
+  if (lsocks != NULL && lsocks[0] != INVALID_SOCKET)
+  {
+    lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
+
+    if (lsocks_pipe == NULL)
+    {
+      GNUNET_free (cmd);
+      GNUNET_free (path);
+      GNUNET_DISK_pipe_close (lsocks_pipe);
+      return NULL;
+    }
+    lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe,
+        GNUNET_DISK_PIPE_END_WRITE);
+    GNUNET_DISK_internal_file_handle_ (lsocks_write_fd,
+                                       &lsocks_write, sizeof (HANDLE));
+    GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle
+                                       (lsocks_pipe, GNUNET_DISK_PIPE_END_READ),
+                                       &lsocks_read, sizeof (HANDLE));
+  }
 
 #if DEBUG_OS
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Opened the parent end of the pipe `%s'\n", childpipename);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n",
+       childpipename);
 #endif
 
   GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE);
   GNUNET_asprintf (&our_env[1], "%s", childpipename);
-  our_env[2] = NULL;
+  GNUNET_free (childpipename);
+  if (lsocks == NULL || lsocks[0] == INVALID_SOCKET)
+    our_env[2] = NULL;
+  else
+  {
+    /*This will tell the child that we're going to send lsocks over the pipe*/
+    GNUNET_asprintf (&our_env[2], "%s=", "GNUNET_OS_READ_LSOCKS");
+    GNUNET_asprintf (&our_env[3], "%lu", lsocks_read);
+    our_env[4] = NULL;
+  }
   env_block = CreateCustomEnvTable (our_env);
-  GNUNET_free (our_env[0]);
-  GNUNET_free (our_env[1]);
-
-  if (!CreateProcess
-      (path, cmd, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED,
+  GNUNET_free_non_null (our_env[0]);
+  GNUNET_free_non_null (our_env[1]);
+  GNUNET_free_non_null (our_env[2]);
+  GNUNET_free_non_null (our_env[3]);
+
+  if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)
+      || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd)
+      || !CreateProcessW
+      (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED,
        env_block, NULL, &start, &proc))
   {
     SetErrnoFromWinError (GetLastError ());
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+    GNUNET_DISK_npipe_close (control_pipe);
+    if (lsocks != NULL)
+      GNUNET_DISK_pipe_close (lsocks_pipe);
     GNUNET_free (env_block);
     GNUNET_free (cmd);
     return NULL;
@@ -1163,12 +1199,91 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
   gnunet_proc->handle = proc.hProcess;
   gnunet_proc->control_pipe = control_pipe;
 
-  CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
+  CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL);
 
   ResumeThread (proc.hThread);
   CloseHandle (proc.hThread);
   GNUNET_free (cmd);
 
+  if (lsocks == NULL || lsocks[0] == INVALID_SOCKET)
+    return gnunet_proc;
+
+  GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ);
+
+  /* This is a replacement for "goto error" that doesn't use goto */
+  fail = 1;
+  do
+  {
+    int wrote;
+    uint64_t size, count, i;
+
+    /* Tell the number of sockets */
+    for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++);
+
+    wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
+    if (wrote != sizeof (count))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ());
+      break;
+    }
+    for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      /* Get a socket duplication info */
+      if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ());
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
+        break;
+      }
+      /* Synchronous I/O is not nice, but we can't schedule this:
+       * lsocks will be closed/freed by the caller soon, and until
+       * the child creates a duplicate, closing a socket here will
+       * close it for good.
+       */
+      /* Send the size of the structure
+       * (the child might be built with different headers...)
+       */
+      size = sizeof (pi);
+      wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size));
+      if (wrote != sizeof (size))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ());
+        break;
+      }
+      /* Finally! Send the data */
+      wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi));
+      if (wrote != sizeof (pi))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ());
+        break;
+      }
+    }
+    /* This will block us until the child makes a final read or closes
+     * the pipe (hence no 'wrote' check), since we have to wait for it
+     * to duplicate the last socket, before we return and start closing
+     * our own copies)
+     */
+    wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count));
+    fail = 0;
+  }
+  while (fail);
+
+  GNUNET_DISK_file_sync (lsocks_write_fd);
+  GNUNET_DISK_pipe_close (lsocks_pipe);
+
+  if (fail)
+  {
+    /* If we can't pass on the socket(s), the child will block forever,
+     * better put it out of its misery.
+     */
+    TerminateProcess (gnunet_proc->handle, 0);
+    CloseHandle (gnunet_proc->handle);
+    GNUNET_DISK_npipe_close (gnunet_proc->control_pipe);
+    GNUNET_free (gnunet_proc);
+    return NULL;
+  }
+
   return gnunet_proc;
 #endif
 }
@@ -1194,7 +1309,7 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   ret = waitpid (proc->pid, &status, WNOHANG);
   if (ret < 0)
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
     return GNUNET_SYSERR;
   }
   if (0 == ret)
@@ -1205,7 +1320,7 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   }
   if (proc->pid != ret)
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
     return GNUNET_SYSERR;
   }
   if (WIFEXITED (status))
@@ -1243,8 +1358,8 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   ret = proc->pid;
   if (h == NULL || ret == 0)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Invalid process information {%d, %08X}\n", ret, h);
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
+         ret, h);
     return GNUNET_SYSERR;
   }
   if (h == NULL)
@@ -1256,7 +1371,7 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   if (ret == 0 || error_code != NO_ERROR)
   {
     SetErrnoFromWinError (error_code);
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
     return GNUNET_SYSERR;
   }
   if (STILL_ACTIVE == c)
@@ -1284,9 +1399,15 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 
 #ifndef MINGW
   pid_t pid = proc->pid;
+  pid_t ret;
 
-  if (pid != waitpid (pid, NULL, 0))
+  while ( (pid != (ret = waitpid (pid, NULL, 0))) &&
+         (EINTR == errno) ) ;
+  if (pid != ret) 
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid");
     return GNUNET_SYSERR;
+  }
   return GNUNET_OK;
 #else
   HANDLE h;
@@ -1295,8 +1416,8 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
   h = proc->handle;
   if (NULL == h)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Invalid process information {%d, %08X}\n", proc->pid, h);
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n",
+         proc->pid, h);
     return GNUNET_SYSERR;
   }
   if (h == NULL)
@@ -1467,7 +1588,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
   struct GNUNET_DISK_PipeHandle *opipe;
   va_list ap;
 
-  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);