From f51668fdf9dad4e40194f7e08e44743c1c1c1388 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 20 May 2011 12:31:27 +0200 Subject: [PATCH] services: Add a timeout to all pipe communications with the service process. --- programs/services/rpc.c | 16 ++++++++++++++-- programs/services/services.c | 36 ++++++++++++++++++++++++++++-------- programs/services/services.h | 1 + 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index d1dd39e8c2a..15ea7cf90c1 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -893,16 +893,28 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d BOOL service_send_command( struct service_entry *service, HANDLE pipe, const void *data, DWORD size, DWORD *result ) { + OVERLAPPED overlapped; DWORD count; BOOL r; - r = WriteFile(pipe, data, size, &count, NULL); + overlapped.hEvent = service->overlapped_event; + r = WriteFile(pipe, data, size, &count, &overlapped); + if (!r && GetLastError() == ERROR_IO_PENDING) + { + WaitForSingleObject( service->overlapped_event, service_pipe_timeout ); + r = GetOverlappedResult( pipe, &overlapped, &count, FALSE ); + } if (!r || count != size) { WINE_ERR("service protocol error - failed to write pipe!\n"); return FALSE; } - r = ReadFile(pipe, result, sizeof *result, &count, NULL); + r = ReadFile(pipe, result, sizeof *result, &count, &overlapped); + if (!r && GetLastError() == ERROR_IO_PENDING) + { + WaitForSingleObject( service->overlapped_event, service_pipe_timeout ); + r = GetOverlappedResult( pipe, &overlapped, &count, FALSE ); + } if (!r || count != sizeof *result) { WINE_ERR("service protocol error - failed to read pipe " diff --git a/programs/services/services.c b/programs/services/services.c index 2b1b8c52707..35edbbaa44c 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -95,6 +95,7 @@ void free_service_entry(struct service_entry *entry) HeapFree(GetProcessHeap(), 0, entry->dependOnGroups); CloseHandle(entry->control_mutex); CloseHandle(entry->control_pipe); + CloseHandle(entry->overlapped_event); CloseHandle(entry->status_changed_event); HeapFree(GetProcessHeap(), 0, entry); } @@ -672,8 +673,10 @@ static DWORD service_wait_for_startup(struct service_entry *service_entry, HANDL /****************************************************************************** * service_send_start_message */ -static BOOL service_send_start_message(struct service_entry *service, LPCWSTR *argv, DWORD argc) +static BOOL service_send_start_message(struct service_entry *service, HANDLE process_handle, + LPCWSTR *argv, DWORD argc) { + OVERLAPPED overlapped; DWORD i, len, result; service_start_info *ssi; LPWSTR p; @@ -681,12 +684,27 @@ static BOOL service_send_start_message(struct service_entry *service, LPCWSTR *a WINE_TRACE("%s %p %d\n", wine_dbgstr_w(service->name), argv, argc); - /* FIXME: this can block so should be done in another thread */ - r = ConnectNamedPipe(service->control_pipe, NULL); - if (!r && GetLastError() != ERROR_PIPE_CONNECTED) + overlapped.hEvent = service->overlapped_event; + if (!ConnectNamedPipe(service->control_pipe, &overlapped)) { - WINE_ERR("pipe connect failed\n"); - return FALSE; + if (GetLastError() == ERROR_IO_PENDING) + { + HANDLE handles[2]; + handles[0] = service->overlapped_event; + handles[1] = process_handle; + if (WaitForMultipleObjects( 2, handles, FALSE, service_pipe_timeout ) != WAIT_OBJECT_0) + CancelIo( service->control_pipe ); + if (!HasOverlappedCompleted( &overlapped )) + { + WINE_ERR( "service %s failed to start\n", wine_dbgstr_w( service->name )); + return FALSE; + } + } + else if (GetLastError() != ERROR_PIPE_CONNECTED) + { + WINE_ERR("pipe connect failed\n"); + return FALSE; + } } /* calculate how much space do we need to send the startup info */ @@ -743,9 +761,11 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * if (!service->status_changed_event) service->status_changed_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!service->overlapped_event) + service->overlapped_event = CreateEventW(NULL, TRUE, FALSE, NULL); name = service_get_pipe_name(); - service->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX, + service->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL ); HeapFree(GetProcessHeap(), 0, name); if (service->control_pipe==INVALID_HANDLE_VALUE) @@ -760,7 +780,7 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * if (err == ERROR_SUCCESS) { - if (!service_send_start_message(service, service_argv, service_argc)) + if (!service_send_start_message(service, process_handle, service_argv, service_argc)) err = ERROR_SERVICE_REQUEST_TIMEOUT; } diff --git a/programs/services/services.h b/programs/services/services.h index 63154c8f9dc..448ddfaffbb 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -44,6 +44,7 @@ struct service_entry LPWSTR dependOnGroups; HANDLE control_mutex; HANDLE control_pipe; + HANDLE overlapped_event; HANDLE status_changed_event; };