#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;
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);
}
else
{
- if (GNUNET_DISK_file_read (control_pipe,
- &sig, sizeof (sig)) != sizeof (sig))
+ 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, control_pipe);
+ control_pipe, &parent_control_handler,
+ control_pipe);
raise (sig);
}
}
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 = GNUNET_DISK_npipe_open (env_buf,
- GNUNET_DISK_OPEN_READ,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE);
+ control_pipe =
+ GNUNET_DISK_npipe_open (env_buf, GNUNET_DISK_OPEN_READ,
+ GNUNET_DISK_PERM_USER_READ |
+ 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,
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
&parent_control_handler, control_pipe);
+ putenv ("GNUNET_OS_CONTROL_PIPE=");
}
{
/* 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
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
*/
while (1)
{
- ret = GNUNET_NETWORK_socket_select (rfds, NULL, efds,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_relative_get_unit (),
- 5000));
-
- if (ret < 1 || GNUNET_NETWORK_fdset_handle_isset (efds,
- proc->control_pipe))
+ ret =
+ GNUNET_NETWORK_socket_select (rfds, NULL, efds,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_relative_get_unit (),
+ 5000));
+
+ if (ret < 1 ||
+ GNUNET_NETWORK_fdset_handle_isset (efds, proc->control_pipe))
{
/* Just to be sure */
PLIBC_KILL (proc->pid, sig);
}
else
{
- if (GNUNET_DISK_file_read (proc->control_pipe, &ret,
- sizeof (ret)) != GNUNET_OK)
+ if (GNUNET_DISK_file_read (proc->control_pipe, &ret, sizeof (ret)) !=
+ GNUNET_OK)
res = PLIBC_KILL (proc->pid, sig);
/* Child signaled shutdown is in progress */
* @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;
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;
}
}
{
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;
* @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;
#ifndef MINGW
pid_t ret;
- char **argv;
- int argc;
int fd_stdout_write;
int fd_stdout_read;
int fd_stdin_read;
int fd_stdin_write;
#if ENABLE_WINDOWS_WORKAROUNDS
- control_pipe = GNUNET_DISK_npipe_create (&childpipename,
- GNUNET_DISK_OPEN_WRITE,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE);
+ control_pipe =
+ GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
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
&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
{
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));
}
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;
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
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;
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);
start.hStdOutput = stdout_handle;
}
- control_pipe = GNUNET_DISK_npipe_create (&childpipename,
- GNUNET_DISK_OPEN_WRITE,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE);
+ control_pipe =
+ GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
if (control_pipe == NULL)
{
GNUNET_free (cmd);
}
#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_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;
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);
}
+/**
+ * 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.
*
* @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, char *const argv[])
+GNUNET_OS_start_process_v (const SOCKTYPE *lsocks,
+ const char *filename,
+ char *const argv[])
{
#if ENABLE_WINDOWS_WORKAROUNDS
struct GNUNET_DISK_FileHandle *control_pipe = NULL;
unsigned int ls;
#if ENABLE_WINDOWS_WORKAROUNDS
- control_pipe = GNUNET_DISK_npipe_create (&childpipename,
- GNUNET_DISK_OPEN_WRITE,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE);
+ control_pipe =
+ GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
if (control_pipe == NULL)
return NULL;
#endif
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
}
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;
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
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;
memset (&start, 0, sizeof (start));
start.cb = sizeof (start);
- control_pipe = GNUNET_DISK_npipe_create (&childpipename,
- GNUNET_DISK_OPEN_WRITE,
- GNUNET_DISK_PERM_USER_READ |
- GNUNET_DISK_PERM_USER_WRITE);
+ control_pipe =
+ GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
if (control_pipe == NULL)
{
GNUNET_free (cmd);
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;
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
}
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)
}
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))
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)
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)
#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;
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)
proc (cmd->proc_cls, NULL);
return;
}
- ret = GNUNET_DISK_file_read (cmd->r,
- &cmd->buf[cmd->off],
- sizeof (cmd->buf) - cmd->off);
+ ret =
+ GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
+ sizeof (cmd->buf) - cmd->off);
if (ret <= 0)
{
if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
* @return NULL on error
*/
struct GNUNET_OS_CommandHandle *
-GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
- void *proc_cls,
- struct GNUNET_TIME_Relative timeout,
- const char *binary, ...)
+GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls,
+ struct GNUNET_TIME_Relative timeout, const char *binary,
+ ...)
{
struct GNUNET_OS_CommandHandle *cmd;
struct GNUNET_OS_Process *eip;
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);