advapi32: Unify service startup and control handling.

Signed-off-by: Sebastian Lackner <sebastian@fds-team.de>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Sebastian Lackner 2016-08-31 08:46:20 +02:00 committed by Alexandre Julliard
parent 328fbb6880
commit 1c5affa205
5 changed files with 53 additions and 61 deletions

View File

@ -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;
}
/* find the service */
if (!(service = find_service_by_name( name )))
if (info.magic != SERVICE_PROTOCOL_MAGIC)
{
FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(name));
ERR( "received invalid request for 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)
/* find the service */
if (!(service = find_service_by_name( name )))
{
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);
FIXME( "got request for unknown service %s\n", debugstr_w(name) );
result = ERROR_INVALID_PARAMETER;
break;
goto done;
}
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) );
}
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;
}
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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;