[2/2] advapi32: Unify service startup and control handling.

Sebastian Lackner sebastian at fds-team.de
Wed Aug 31 01:46:20 CDT 2016


Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
 dlls/advapi32/service.c      |   65 +++++++++++++++++++++----------------------
 include/wine/svcctl.idl      |    9 +----
 programs/services/rpc.c      |    8 ++---
 programs/services/services.c |   27 +++++++----------
 programs/services/services.h |    3 +
 5 files changed, 52 insertions(+), 60 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index cd3cd2f..1150805 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -379,9 +379,9 @@ static DWORD WINAPI service_thread(LPVOID arg)
 /******************************************************************************
  * service_handle_start
  */
-static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
+static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size)
 {
-    TRACE("%s argsize %u\n", debugstr_w(service->name), count);
+    DWORD count = data_size / sizeof(WCHAR);
 
     if (service->thread)
     {
@@ -390,8 +390,11 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR
     }
 
     heap_free(service->args);
-    service->args = heap_alloc(count * sizeof(WCHAR));
-    memcpy( service->args, data, count * sizeof(WCHAR) );
+    service->args = heap_alloc((count + 2) * sizeof(WCHAR));
+    if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
+    service->args[count++] = 0;
+    service->args[count++] = 0;
+
     service->thread = CreateThread( NULL, 0, service_thread,
                                     service, 0, NULL );
     SetEvent( service_event );  /* notify the main loop */
@@ -401,14 +404,16 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR
 /******************************************************************************
  * service_handle_control
  */
-static DWORD service_handle_control(const service_data *service, DWORD control, void *data)
+static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size)
 {
     DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
 
-    TRACE("%s control %u data %p\n", debugstr_w(service->name), control, data);
+    TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size);
 
-    if (service->handler)
-        ret = service->handler(control, 0, data, service->context);
+    if (control == SERVICE_CONTROL_START)
+        ret = service_handle_start(service, data, data_size);
+    else if (service->handler)
+        ret = service->handler(control, 0, (void *)data, service->context);
     return ret;
 }
 
@@ -472,39 +477,33 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
             goto done;
         }
 
+        if (info.magic != SERVICE_PROTOCOL_MAGIC)
+        {
+            ERR( "received invalid request for service %s\n", debugstr_w(name) );
+            result = ERROR_INVALID_PARAMETER;
+            goto done;
+        }
+
         /* find the service */
         if (!(service = find_service_by_name( name )))
         {
-            FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(name));
+            FIXME( "got request for unknown service %s\n", debugstr_w(name) );
             result = ERROR_INVALID_PARAMETER;
             goto done;
         }
 
-        TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(name) );
-
-        /* handle the request */
-        switch (info.cmd)
+        if (!service->handle)
         {
-        case WINESERV_STARTINFO:
-            if (!service->handle)
-            {
-                if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
-                    !(service->full_access_handle = OpenServiceW( disp->manager, name,
-                            GENERIC_READ|GENERIC_WRITE )))
-                    FIXME( "failed to open service %s\n", debugstr_w(name) );
-            }
-            result = service_handle_start(service, (WCHAR *)data, data_size / sizeof(WCHAR));
-            break;
-        case WINESERV_SENDCONTROL:
-            result = service_handle_control(service, info.control, (data_size > info.name_size * sizeof(WCHAR)) ?
-                                            &data[info.name_size * sizeof(WCHAR)] : NULL);
-            break;
-        default:
-            ERR("received invalid command %u\n", info.cmd);
-            result = ERROR_INVALID_PARAMETER;
-            break;
+            if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
+                !(service->full_access_handle = OpenServiceW( disp->manager, name,
+                        GENERIC_READ|GENERIC_WRITE )))
+                FIXME( "failed to open service %s\n", debugstr_w(name) );
         }
 
+        data_size -= info.name_size * sizeof(WCHAR);
+        result = service_handle_control(service, info.control, data_size ?
+                                        &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
+
     done:
         LeaveCriticalSection( &service_cs );
         WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
@@ -592,13 +591,13 @@ static BOOL service_run_main_thread(void)
                     {
                         FIXME("service should be able to delay shutdown\n");
                         timeout += spi.dwPreshutdownTimeout;
-                        ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL );
+                        ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
                         wait_handles[n++] = services[i]->thread;
                     }
                 }
                 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
                 {
-                    ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL );
+                    ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
                     wait_handles[n++] = services[i]->thread;
                 }
             }
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index 98412d6..0c0b49b 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -34,15 +34,12 @@ cpp_quote("#define SVCCTL_ENDPOINTA \"\\\\pipe\\\\svcctl\"")
 cpp_quote("#define SVCCTL_STARTED_EVENT {'_','_','w','i','n','e','_','S','v','c','c','t','l','S','t','a','r','t','e','d',0}")
 
 /* Service startup protocol over control pipe - not compatible with Windows */
-enum service_pipe_command
-{
-    WINESERV_STARTINFO = 1,
-    WINESERV_SENDCONTROL = 2
-};
+cpp_quote("#define SERVICE_PROTOCOL_MAGIC 0x57494e45")
+cpp_quote("#define SERVICE_CONTROL_START 0")
 
 typedef struct service_start_info_t
 {
-    enum service_pipe_command cmd;        /* request code */
+    DWORD                     magic;      /* protocol magic */
     DWORD                     total_size; /* total request size */
     DWORD                     name_size;  /* size of name in data buffer */
     DWORD                     control;    /* control code */
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index bd6af95..468b380 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -979,7 +979,7 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d
 /******************************************************************************
  * process_send_command
  */
-BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
+static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
 {
     OVERLAPPED overlapped;
     DWORD count, ret;
@@ -1030,8 +1030,8 @@ BOOL process_send_command(struct process_entry *process, const void *data, DWORD
 /******************************************************************************
  * process_send_control
  */
-static BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
-                                 const BYTE *data, DWORD data_size, DWORD *result)
+BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
+                          const BYTE *data, DWORD data_size, DWORD *result)
 {
     service_start_info *ssi;
     DWORD len;
@@ -1041,7 +1041,7 @@ static BOOL process_send_control(struct process_entry *process, const WCHAR *nam
     len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size;
 
     ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
-    ssi->cmd = WINESERV_SENDCONTROL;
+    ssi->magic = SERVICE_PROTOCOL_MAGIC;
     ssi->control = control;
     ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
     ssi->name_size = strlenW(name) + 1;
diff --git a/programs/services/services.c b/programs/services/services.c
index cf5cb90..e7610bd 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -844,8 +844,7 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH
 {
     OVERLAPPED overlapped;
     DWORD i, len, result;
-    service_start_info *ssi;
-    LPWSTR p;
+    WCHAR *str, *p;
 
     WINE_TRACE("%p %s %p %d\n", process, wine_dbgstr_w(name), argv, argc);
 
@@ -872,32 +871,28 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH
         }
     }
 
-    /* calculate how much space do we need to send the startup info */
     len = strlenW(name) + 1;
-    for (i=0; i<argc; i++)
+    for (i = 0; i < argc; i++)
         len += strlenW(argv[i])+1;
     len = (len + 1) * sizeof(WCHAR);
 
-    ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
-    ssi->cmd = WINESERV_STARTINFO;
-    ssi->control = 0;
-    ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
-    ssi->name_size = strlenW(name) + 1;
-    strcpyW((WCHAR *)ssi->data, name);
+    if (!(str = HeapAlloc(GetProcessHeap(), 0, len)))
+        return ERROR_NOT_ENOUGH_SERVER_MEMORY;
 
-    /* copy service args into a single buffer*/
-    p = (WCHAR *)&ssi->data[ssi->name_size * sizeof(WCHAR)];
-    for (i=0; i<argc; i++)
+    p = str;
+    strcpyW(p, name);
+    p += strlenW(name) + 1;
+    for (i = 0; i < argc; i++)
     {
         strcpyW(p, argv[i]);
         p += strlenW(p) + 1;
     }
-    *p=0;
+    *p = 0;
 
-    if (!process_send_command(process, ssi, ssi->total_size, &result))
+    if (!process_send_control(process, name, SERVICE_CONTROL_START, (const BYTE *)str, len, &result))
         result = ERROR_SERVICE_REQUEST_TIMEOUT;
 
-    HeapFree(GetProcessHeap(), 0, ssi);
+    HeapFree(GetProcessHeap(), 0, str);
     return result;
 }
 
diff --git a/programs/services/services.h b/programs/services/services.h
index b03a157..126ef26 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -95,7 +95,8 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *
 
 struct process_entry *grab_process(struct process_entry *process);
 void release_process(struct process_entry *process);
-BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result);
+BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
+                          const BYTE *data, DWORD data_size, DWORD *result);
 void process_terminate(struct process_entry *process);
 
 extern DWORD service_pipe_timeout;
-- 
2.9.0



More information about the wine-patches mailing list