Merge remote-tracking branch 'yawning/feature15435'

This commit is contained in:
Nick Mathewson 2015-04-01 13:34:14 -04:00
commit aa7b792250
5 changed files with 82 additions and 14 deletions

5
changes/feature15435 Normal file
View File

@ -0,0 +1,5 @@
o Minor features (pluggable Transports):
- When launching managed pluggable transports, setup a valid open stdin
in the child process that can be used to detect if tor has terminated.
The "TOR_PT_EXIT_ON_STDIN_CLOSE" enviornment variable can be used by
implementations to detect this new behavior. Resolves ticket 15435.

View File

@ -3942,9 +3942,11 @@ process_handle_new(void)
process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
#ifdef _WIN32
out->stdin_pipe = INVALID_HANDLE_VALUE;
out->stdout_pipe = INVALID_HANDLE_VALUE;
out->stderr_pipe = INVALID_HANDLE_VALUE;
#else
out->stdin_pipe = -1;
out->stdout_pipe = -1;
out->stderr_pipe = -1;
#endif
@ -3984,7 +3986,7 @@ process_handle_waitpid_cb(int status, void *arg)
#define CHILD_STATE_FORK 3
#define CHILD_STATE_DUPOUT 4
#define CHILD_STATE_DUPERR 5
#define CHILD_STATE_REDIRECT 6
#define CHILD_STATE_DUPIN 6
#define CHILD_STATE_CLOSEFD 7
#define CHILD_STATE_EXEC 8
#define CHILD_STATE_FAILEXEC 9
@ -4018,6 +4020,8 @@ tor_spawn_background(const char *const filename, const char **argv,
HANDLE stdout_pipe_write = NULL;
HANDLE stderr_pipe_read = NULL;
HANDLE stderr_pipe_write = NULL;
HANDLE stdin_pipe_read = NULL;
HANDLE stdin_pipe_write = NULL;
process_handle_t *process_handle;
int status;
@ -4063,6 +4067,20 @@ tor_spawn_background(const char *const filename, const char **argv,
return status;
}
/* Set up pipe for stdin */
if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) {
log_warn(LD_GENERAL,
"Failed to create pipe for stdin communication with child process: %s",
format_win32_error(GetLastError()));
return status;
}
if (!SetHandleInformation(stderr_pipe_write, HANDLE_FLAG_INHERIT, 0)) {
log_warn(LD_GENERAL,
"Failed to configure pipe for stdin communication with child "
"process: %s", format_win32_error(GetLastError()));
return status;
}
/* Create the child process */
/* Windows expects argv to be a whitespace delimited string, so join argv up
@ -4077,7 +4095,7 @@ tor_spawn_background(const char *const filename, const char **argv,
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = stderr_pipe_write;
siStartInfo.hStdOutput = stdout_pipe_write;
siStartInfo.hStdInput = NULL;
siStartInfo.hStdInput = stdin_pipe_read;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
/* Create the child process */
@ -4107,6 +4125,7 @@ tor_spawn_background(const char *const filename, const char **argv,
/* TODO: Close hProcess and hThread in process_handle->pid? */
process_handle->stdout_pipe = stdout_pipe_read;
process_handle->stderr_pipe = stderr_pipe_read;
process_handle->stdin_pipe = stdin_pipe_write;
status = process_handle->status = PROCESS_STATUS_RUNNING;
}
@ -4117,6 +4136,7 @@ tor_spawn_background(const char *const filename, const char **argv,
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
int stdin_pipe[2];
int fd, retval;
ssize_t nbytes;
process_handle_t *process_handle;
@ -4141,7 +4161,7 @@ tor_spawn_background(const char *const filename, const char **argv,
child_state = CHILD_STATE_PIPE;
/* Set up pipe for redirecting stdout and stderr of child */
/* Set up pipe for redirecting stdout, stderr, and stdin of child */
retval = pipe(stdout_pipe);
if (-1 == retval) {
log_warn(LD_GENERAL,
@ -4162,6 +4182,20 @@ tor_spawn_background(const char *const filename, const char **argv,
return status;
}
retval = pipe(stdin_pipe);
if (-1 == retval) {
log_warn(LD_GENERAL,
"Failed to set up pipe for stdin communication with child process: %s",
strerror(errno));
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(stderr_pipe[0]);
close(stderr_pipe[1]);
return status;
}
child_state = CHILD_STATE_MAXFD;
#ifdef _SC_OPEN_MAX
@ -4206,13 +4240,11 @@ tor_spawn_background(const char *const filename, const char **argv,
if (-1 == retval)
goto error;
child_state = CHILD_STATE_REDIRECT;
child_state = CHILD_STATE_DUPIN;
/* Link stdin to /dev/null */
fd = open("/dev/null", O_RDONLY); /* NOT cloexec, obviously. */
if (fd != -1)
dup2(fd, STDIN_FILENO);
else
/* Link child stdin to the read end of the pipe */
retval = dup2(stdin_pipe[0], STDIN_FILENO);
if (-1 == retval)
goto error;
child_state = CHILD_STATE_CLOSEFD;
@ -4221,7 +4253,8 @@ tor_spawn_background(const char *const filename, const char **argv,
close(stderr_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(fd);
close(stdin_pipe[0]);
close(stdin_pipe[1]);
/* Close all other fds, including the read end of the pipe */
/* XXX: We should now be doing enough FD_CLOEXEC setting to make
@ -4273,6 +4306,8 @@ tor_spawn_background(const char *const filename, const char **argv,
if (-1 == pid) {
log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno));
close(stdin_pipe[0]);
close(stdin_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(stderr_pipe[0]);
@ -4309,16 +4344,28 @@ tor_spawn_background(const char *const filename, const char **argv,
strerror(errno));
}
/* Return write end of the stdin pipe to caller, and close the read end */
process_handle->stdin_pipe = stdin_pipe[1];
retval = close(stdin_pipe[0]);
if (-1 == retval) {
log_warn(LD_GENERAL,
"Failed to close read end of stdin pipe in parent process: %s",
strerror(errno));
}
status = process_handle->status = PROCESS_STATUS_RUNNING;
/* Set stdout/stderr pipes to be non-blocking */
/* Set stdin/stdout/stderr pipes to be non-blocking */
if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 ||
fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0) {
log_warn(LD_GENERAL, "Failed to set stderror/stdout pipes nonblocking "
"in parent process: %s", strerror(errno));
fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 ||
fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) {
log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes "
"nonblocking in parent process: %s", strerror(errno));
}
/* Open the buffered IO streams */
process_handle->stdout_handle = fdopen(process_handle->stdout_pipe, "r");
process_handle->stderr_handle = fdopen(process_handle->stderr_pipe, "r");
process_handle->stdin_handle = fdopen(process_handle->stdin_pipe, "r");
*process_handle_out = process_handle;
return process_handle->status;
@ -4361,6 +4408,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
if (process_handle->stderr_pipe)
CloseHandle(process_handle->stderr_pipe);
if (process_handle->stdin_pipe)
CloseHandle(process_handle->stdin_pipe);
#else
if (process_handle->stdout_handle)
fclose(process_handle->stdout_handle);
@ -4368,6 +4418,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
if (process_handle->stderr_handle)
fclose(process_handle->stderr_handle);
if (process_handle->stdin_handle)
fclose(process_handle->stdin_handle);
clear_waitpid_callback(process_handle->waitpid_cb);
#endif

View File

@ -474,12 +474,15 @@ struct process_handle_t {
/** One of the PROCESS_STATUS_* values */
int status;
#ifdef _WIN32
HANDLE stdin_pipe;
HANDLE stdout_pipe;
HANDLE stderr_pipe;
PROCESS_INFORMATION pid;
#else
int stdin_pipe;
int stdout_pipe;
int stderr_pipe;
FILE *stdin_handle;
FILE *stdout_handle;
FILE *stderr_handle;
pid_t pid;

View File

@ -1388,6 +1388,11 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
} else {
smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=");
}
/* All new versions of tor will keep stdin open, so PTs can use it
* as a reliable termination detection mechanism.
*/
smartlist_add_asprintf(envs, "TOR_PT_EXIT_ON_STDIN_CLOSE=1");
} else {
/* If ClientTransportPlugin has a HTTPS/SOCKS proxy configured, set the
* TOR_PT_PROXY line.

View File

@ -107,9 +107,11 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
#ifdef _WIN32
tt_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
tt_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
tt_assert(process_handle->stdin_pipe != INVALID_HANDLE_VALUE);
#else
tt_assert(process_handle->stdout_pipe >= 0);
tt_assert(process_handle->stderr_pipe >= 0);
tt_assert(process_handle->stdin_pipe >= 0);
#endif
/* Check stdout */