11 #define PROCESS_WIN32_PRIVATE
23 #ifdef HAVE_SYS_TIME_H
34 #define BUFFER_SIZE (1024)
45 struct process_win32_handle_t {
53 size_t data_available;
56 char buffer[BUFFER_SIZE];
59 OVERLAPPED overlapped;
71 struct process_win32_t {
73 process_win32_handle_t stdin_handle;
76 process_win32_handle_t stdout_handle;
79 process_win32_handle_t stderr_handle;
82 PROCESS_INFORMATION process_information;
90 process_win32_new(
void)
92 process_win32_t *win32_process;
93 win32_process = tor_malloc_zero(
sizeof(process_win32_t));
95 win32_process->stdin_handle.pipe = INVALID_HANDLE_VALUE;
96 win32_process->stdout_handle.pipe = INVALID_HANDLE_VALUE;
97 win32_process->stderr_handle.pipe = INVALID_HANDLE_VALUE;
107 process_win32_free_(process_win32_t *win32_process)
113 process_win32_cleanup_handle(&win32_process->stdin_handle);
114 process_win32_cleanup_handle(&win32_process->stdout_handle);
115 process_win32_cleanup_handle(&win32_process->stderr_handle);
122 process_win32_init(
void)
131 process_win32_deinit(
void)
134 if (process_win32_timer_running())
135 process_win32_timer_stop();
146 process_win32_t *win32_process = process_get_win32_process(process);
148 HANDLE stdout_pipe_read = NULL;
149 HANDLE stdout_pipe_write = NULL;
150 HANDLE stderr_pipe_read = NULL;
151 HANDLE stderr_pipe_write = NULL;
152 HANDLE stdin_pipe_read = NULL;
153 HANDLE stdin_pipe_write = NULL;
157 SECURITY_ATTRIBUTES security_attributes;
158 security_attributes.nLength =
sizeof(security_attributes);
159 security_attributes.bInheritHandle = TRUE;
162 security_attributes.lpSecurityDescriptor = NULL;
165 if (! process_win32_create_pipe(&stdout_pipe_read,
167 &security_attributes,
168 PROCESS_WIN32_PIPE_TYPE_READER)) {
173 if (! process_win32_create_pipe(&stderr_pipe_read,
175 &security_attributes,
176 PROCESS_WIN32_PIPE_TYPE_READER)) {
181 if (! process_win32_create_pipe(&stdin_pipe_read,
183 &security_attributes,
184 PROCESS_WIN32_PIPE_TYPE_WRITER)) {
189 STARTUPINFOA startup_info;
191 memset(&startup_info, 0,
sizeof(startup_info));
192 startup_info.cb =
sizeof(startup_info);
193 startup_info.hStdError = stderr_pipe_write;
194 startup_info.hStdOutput = stdout_pipe_write;
195 startup_info.hStdInput = stdin_pipe_read;
196 startup_info.dwFlags |= STARTF_USESTDHANDLES;
206 char *joined_argv = tor_join_win_cmdline((
const char **)argv);
209 ret = CreateProcessA(NULL,
219 &win32_process->process_information);
223 process_environment_free(env);
226 log_warn(
LD_PROCESS,
"CreateProcessA() failed: %s",
227 format_win32_error(GetLastError()));
230 CloseHandle(stdout_pipe_read);
231 CloseHandle(stdout_pipe_write);
232 CloseHandle(stderr_pipe_read);
233 CloseHandle(stderr_pipe_write);
234 CloseHandle(stdin_pipe_read);
235 CloseHandle(stdin_pipe_write);
260 win32_process->stdout_handle.pipe = stdout_pipe_read;
261 win32_process->stderr_handle.pipe = stderr_pipe_read;
262 win32_process->stdin_handle.pipe = stdin_pipe_write;
265 CloseHandle(stdout_pipe_write);
266 CloseHandle(stderr_pipe_write);
267 CloseHandle(stdin_pipe_read);
278 win32_process->stdout_handle.overlapped.hEvent = (HANDLE)process;
279 win32_process->stderr_handle.overlapped.hEvent = (HANDLE)process;
280 win32_process->stdin_handle.overlapped.hEvent = (HANDLE)process;
283 if (! process_win32_timer_running())
284 process_win32_timer_start();
297 process_win32_terminate(
process_t *process)
301 process_win32_t *win32_process = process_get_win32_process(process);
306 ret = TerminateProcess(win32_process->process_information.hProcess, 0);
309 log_warn(
LD_PROCESS,
"TerminateProcess() failed: %s",
310 format_win32_error(GetLastError()));
315 process_win32_cleanup_handle(&win32_process->stdin_handle);
316 process_win32_cleanup_handle(&win32_process->stdout_handle);
317 process_win32_cleanup_handle(&win32_process->stderr_handle);
324 process_win32_get_pid(
process_t *process)
328 process_win32_t *win32_process = process_get_win32_process(process);
329 return (process_pid_t)win32_process->process_information.dwProcessId;
338 process_win32_write(
struct process_t *process, buf_t *buffer)
343 process_win32_t *win32_process = process_get_win32_process(process);
345 DWORD error_code = 0;
349 if (win32_process->stdin_handle.busy)
353 if (buffer_size == 0)
357 if (BUG(win32_process->stdin_handle.reached_eof))
361 const size_t write_size = MIN(buffer_size,
362 sizeof(win32_process->stdin_handle.buffer));
365 buf_get_bytes(buffer, win32_process->stdin_handle.buffer, write_size);
374 ret = WriteFileEx(win32_process->stdin_handle.pipe,
375 win32_process->stdin_handle.buffer,
377 &win32_process->stdin_handle.overlapped,
378 process_win32_stdin_write_done);
381 error_code = GetLastError();
384 if (error_code == ERROR_HANDLE_EOF || error_code == ERROR_BROKEN_PIPE) {
385 log_debug(
LD_PROCESS,
"WriteFileEx() returned EOF from pipe: %s",
386 format_win32_error(error_code));
388 log_warn(
LD_PROCESS,
"WriteFileEx() failed: %s",
389 format_win32_error(error_code));
392 win32_process->stdin_handle.reached_eof =
true;
403 error_code = GetLastError();
405 if (error_code != ERROR_SUCCESS) {
407 log_warn(
LD_PROCESS,
"WriteFileEx() failed after returning success: %s",
408 format_win32_error(error_code));
409 win32_process->stdin_handle.reached_eof =
true;
416 return (
int)write_size;
426 process_win32_read_stdout(
struct process_t *process, buf_t *buffer)
431 process_win32_t *win32_process = process_get_win32_process(process);
433 return process_win32_read_from_handle(&win32_process->stdout_handle,
435 process_win32_stdout_read_done);
445 process_win32_read_stderr(
struct process_t *process, buf_t *buffer)
450 process_win32_t *win32_process = process_get_win32_process(process);
452 return process_win32_read_from_handle(&win32_process->stderr_handle,
454 process_win32_stderr_read_done);
462 process_win32_trigger_completion_callbacks(
void)
474 ret = SleepEx(0, TRUE);
477 if (ret != 0 && ret != WAIT_IO_COMPLETION) {
478 log_warn(
LD_PROCESS,
"SleepEx() returned %lu", ret);
486 process_win32_timer_start(
void)
489 if (BUG(process_win32_timer_running()))
493 static const struct timeval interval = {1, 0};
495 log_info(
LD_PROCESS,
"Starting Windows Process I/O timer");
498 process_win32_timer_callback,
504 process_win32_timer_stop(
void)
506 if (BUG(periodic_timer == NULL))
509 log_info(
LD_PROCESS,
"Stopping Windows Process I/O timer");
510 periodic_timer_free(periodic_timer);
515 process_win32_timer_running(
void)
517 return periodic_timer != NULL;
531 process_win32_trigger_completion_callbacks();
552 if (process_win32_timer_test_process(process)) {
556 } SMARTLIST_FOREACH_END(process);
564 process_win32_timer_test_process(
process_t *process)
572 process_win32_t *win32_process = process_get_win32_process(process);
592 if (! win32_process->stdout_handle.reached_eof)
595 if (! win32_process->stderr_handle.reached_eof)
599 ret = GetExitCodeProcess(win32_process->process_information.hProcess,
603 log_warn(
LD_PROCESS,
"GetExitCodeProcess() failed: %s",
604 format_win32_error(GetLastError()));
612 if (exit_code != STILL_ACTIVE) {
624 process_win32_create_pipe(HANDLE *read_pipe,
626 SECURITY_ATTRIBUTES *attributes,
627 process_win32_pipe_type_t pipe_type)
636 const size_t size = 4096;
641 DWORD write_mode = 0;
644 char pipe_name[MAX_PATH];
645 static DWORD process_id = 0;
646 static DWORD counter = 0;
649 process_id = GetCurrentProcessId();
652 "\\\\.\\Pipe\\Tor-Process-Pipe-%lu-%lu",
653 process_id, counter++);
657 case PROCESS_WIN32_PIPE_TYPE_READER:
658 read_mode = FILE_FLAG_OVERLAPPED;
660 case PROCESS_WIN32_PIPE_TYPE_WRITER:
661 write_mode = FILE_FLAG_OVERLAPPED;
665 tor_assert_nonfatal_unreached_once();
674 read_handle = CreateNamedPipeA(pipe_name,
675 (PIPE_ACCESS_INBOUND|read_mode),
676 (PIPE_TYPE_BYTE|PIPE_WAIT),
683 if (read_handle == INVALID_HANDLE_VALUE) {
684 log_warn(
LD_PROCESS,
"CreateNamedPipeA() failed: %s",
685 format_win32_error(GetLastError()));
690 write_handle = CreateFileA(pipe_name,
695 (FILE_ATTRIBUTE_NORMAL|write_mode),
698 if (write_handle == INVALID_HANDLE_VALUE) {
699 log_warn(
LD_PROCESS,
"CreateFileA() failed: %s",
700 format_win32_error(GetLastError()));
702 CloseHandle(read_handle);
709 case PROCESS_WIN32_PIPE_TYPE_READER:
710 ret = SetHandleInformation(read_handle, HANDLE_FLAG_INHERIT, 0);
712 case PROCESS_WIN32_PIPE_TYPE_WRITER:
713 ret = SetHandleInformation(write_handle, HANDLE_FLAG_INHERIT, 0);
717 tor_assert_nonfatal_unreached_once();
722 log_warn(
LD_PROCESS,
"SetHandleInformation() failed: %s",
723 format_win32_error(GetLastError()));
725 CloseHandle(read_handle);
726 CloseHandle(write_handle);
732 *read_pipe = read_handle;
733 *write_pipe = write_handle;
740 process_win32_cleanup_handle(process_win32_handle_t *handle)
751 ret = CancelIo(handle->pipe);
754 error_code = GetLastError();
757 if (error_code != ERROR_NOT_FOUND) {
759 format_win32_error(error_code));
765 if (handle->pipe != INVALID_HANDLE_VALUE) {
766 CloseHandle(handle->pipe);
767 handle->pipe = INVALID_HANDLE_VALUE;
768 handle->reached_eof =
true;
776 process_win32_stdout_read_done(DWORD error_code,
778 LPOVERLAPPED overlapped)
785 process_win32_t *win32_process = process_get_win32_process(process);
787 if (process_win32_handle_read_completion(&win32_process->stdout_handle,
799 process_win32_stderr_read_done(DWORD error_code,
801 LPOVERLAPPED overlapped)
808 process_win32_t *win32_process = process_get_win32_process(process);
810 if (process_win32_handle_read_completion(&win32_process->stderr_handle,
822 process_win32_stdin_write_done(DWORD error_code,
824 LPOVERLAPPED overlapped)
832 process_win32_t *win32_process = process_get_win32_process(process);
835 win32_process->stdin_handle.busy =
false;
839 if (BUG(win32_process->stdin_handle.reached_eof))
842 if (error_code == 0) {
845 win32_process->stdin_handle.data_available = 0;
846 memset(win32_process->stdin_handle.buffer, 0,
847 sizeof(win32_process->stdin_handle.buffer));
851 }
else if (error_code == ERROR_HANDLE_EOF ||
852 error_code == ERROR_BROKEN_PIPE) {
857 win32_process->stdin_handle.reached_eof =
true;
862 "Error in I/O completion routine from WriteFileEx(): %s",
863 format_win32_error(error_code));
864 win32_process->stdin_handle.reached_eof =
true;
873 process_win32_read_from_handle(process_win32_handle_t *handle,
875 LPOVERLAPPED_COMPLETION_ROUTINE callback)
882 int bytes_available = 0;
883 DWORD error_code = 0;
886 if (BUG(handle->busy))
891 if (BUG(handle->reached_eof))
896 bytes_available = (int)handle->data_available;
898 if (handle->data_available > 0) {
900 buf_add(buffer, handle->buffer, handle->data_available);
903 handle->data_available = 0;
904 memset(handle->buffer, 0,
sizeof(handle->buffer));
915 ret = ReadFileEx(handle->pipe,
917 sizeof(handle->buffer),
922 error_code = GetLastError();
925 if (error_code == ERROR_HANDLE_EOF || error_code == ERROR_BROKEN_PIPE) {
926 log_debug(
LD_PROCESS,
"ReadFileEx() returned EOF from pipe: %s",
927 format_win32_error(error_code));
929 log_warn(
LD_PROCESS,
"ReadFileEx() failed: %s",
930 format_win32_error(error_code));
933 handle->reached_eof =
true;
934 return bytes_available;
944 error_code = GetLastError();
946 if (error_code != ERROR_SUCCESS) {
948 log_warn(
LD_PROCESS,
"ReadFileEx() failed after returning success: %s",
949 format_win32_error(error_code));
950 handle->reached_eof =
true;
951 return bytes_available;
958 return bytes_available;
965 process_win32_handle_read_completion(process_win32_handle_t *handle,
972 handle->busy =
false;
974 if (error_code == 0) {
980 handle->data_available = (size_t)byte_count;
984 }
else if (error_code == ERROR_HANDLE_EOF ||
985 error_code == ERROR_BROKEN_PIPE) {
990 handle->reached_eof =
true;
995 "Error in I/O completion routine from ReadFileEx(): %s",
996 format_win32_error(error_code));
998 handle->reached_eof =
true;
1008 format_win_cmdline_argument(
const char *arg)
1010 char *formatted_arg;
1016 const char backslash =
'\\';
1023 need_quotes = (strchr(arg,
' ') || strchr(arg,
'\t') ||
'\0' == arg[0]);
1026 for (c=arg; *c !=
'\0'; c++) {
1029 for (i=0; i<(bs_counter*2); i++)
1035 }
else if (
'\\' == *c) {
1040 for (i=0; i<bs_counter; i++)
1047 for (i=0; i<bs_counter; i++)
1051 const size_t formatted_arg_len = smartlist_len(arg_chars) +
1052 (need_quotes ? 2 : 0) + 1;
1053 formatted_arg = tor_malloc_zero(formatted_arg_len);
1058 formatted_arg[i++] =
'"';
1063 formatted_arg[i++] = *ch;
1068 formatted_arg[i++] =
'"';
1069 formatted_arg[i] =
'\0';
1071 smartlist_free(arg_chars);
1072 return formatted_arg;
1080 tor_join_win_cmdline(
const char *argv[])
1088 for (i=0; argv[i] != NULL; i++) {
1089 smartlist_add(argv_list, (
void *)format_win_cmdline_argument(argv[i]));
1100 smartlist_free(argv_list);
int buf_add(buf_t *buf, const char *string, size_t string_len)
size_t buf_datalen(const buf_t *buf)
int buf_get_bytes(buf_t *buf, char *string, size_t string_len)
Header file for buffers.c.
Header file for buffers_net.c.
Macro definitions for MIN, MAX, and CLAMP.
struct event_base * tor_libevent_get_base(void)
periodic_timer_t * periodic_timer_new(struct event_base *base, const struct timeval *tv, void(*cb)(periodic_timer_t *timer, void *data), void *data)
int tor_snprintf(char *str, size_t size, const char *format,...)
void process_notify_event_stdout(process_t *process)
static smartlist_t * processes
void process_notify_event_exit(process_t *process, process_exit_code_t exit_code)
const smartlist_t * process_get_all_processes(void)
void process_notify_event_stderr(process_t *process)
process_environment_t * process_get_environment(const process_t *process)
process_status_t process_get_status(const process_t *process)
char ** process_get_argv(const process_t *process)
void process_notify_event_stdin(process_t *process)
Header for process_win32.c.
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
char * windows_environment_block
Macros to manage assertions, fatal and non-fatal.