Alexandre Julliard : services: Add a timeout to all pipe communications with the service process.

Alexandre Julliard julliard at winehq.org
Fri May 20 12:44:31 CDT 2011


Module: wine
Branch: master
Commit: f51668fdf9dad4e40194f7e08e44743c1c1c1388
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f51668fdf9dad4e40194f7e08e44743c1c1c1388

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri May 20 12:31:27 2011 +0200

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 d1dd39e..15ea7cf 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 2b1b8c5..35edbba 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 63154c8..448ddfa 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;
 };
 




More information about the wine-cvs mailing list