[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