Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
33914a1b
Commit
33914a1b
authored
May 08, 2008
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
services: Send the service name in the control requests.
Only start a single dispatcher thread for all services.
parent
cd550bf6
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
149 additions
and
107 deletions
+149
-107
service.c
dlls/advapi32/service.c
+105
-80
svcctl.idl
include/wine/svcctl.idl
+14
-9
rpc.c
programs/services/rpc.c
+16
-7
services.c
programs/services/services.c
+14
-11
No files found.
dlls/advapi32/service.c
View file @
33914a1b
...
...
@@ -81,6 +81,7 @@ typedef struct service_data_t
LPHANDLER_FUNCTION_EX
handler
;
LPVOID
context
;
HANDLE
thread
;
SC_HANDLE
handle
;
BOOL
unicode
:
1
;
union
{
LPSERVICE_MAIN_FUNCTIONA
a
;
...
...
@@ -356,6 +357,17 @@ static HANDLE service_open_pipe(void)
return
handle
;
}
static
service_data
*
find_service_by_name
(
const
WCHAR
*
name
)
{
unsigned
int
i
;
if
(
nb_services
==
1
)
/* only one service (FIXME: should depend on OWN_PROCESS etc.) */
return
services
[
0
];
for
(
i
=
0
;
i
<
nb_services
;
i
++
)
if
(
!
strcmpiW
(
name
,
services
[
i
]
->
name
))
return
services
[
i
];
return
NULL
;
}
/******************************************************************************
* service_thread
*
...
...
@@ -420,57 +432,37 @@ static DWORD WINAPI service_thread(LPVOID arg)
/******************************************************************************
* service_handle_start
*/
static
BOOL
service_handle_start
(
HANDLE
pipe
,
service_data
*
service
,
DWORD
count
)
static
DWORD
service_handle_start
(
service_data
*
service
,
const
WCHAR
*
data
,
DWORD
count
)
{
DWORD
read
=
0
,
result
=
0
;
LPWSTR
args
;
BOOL
r
;
TRACE
(
"%p %p %d
\n
"
,
pipe
,
service
,
count
);
args
=
HeapAlloc
(
GetProcessHeap
(),
0
,
count
*
sizeof
(
WCHAR
));
r
=
ReadFile
(
pipe
,
args
,
count
*
sizeof
(
WCHAR
),
&
read
,
NULL
);
if
(
!
r
||
count
!=
read
/
sizeof
(
WCHAR
)
||
args
[
count
-
1
])
{
ERR
(
"pipe read failed r = %d count = %d read = %d args[n-1]=%s
\n
"
,
r
,
count
,
read
,
debugstr_wn
(
args
,
count
));
goto
end
;
}
TRACE
(
"%s argsize %u
\n
"
,
debugstr_w
(
service
->
name
),
count
);
if
(
service
->
thread
)
{
WARN
(
"service is not stopped
\n
"
);
result
=
ERROR_SERVICE_ALREADY_RUNNING
;
goto
end
;
return
ERROR_SERVICE_ALREADY_RUNNING
;
}
HeapFree
(
GetProcessHeap
(),
0
,
service
->
args
);
service
->
args
=
args
;
args
=
NULL
;
service
->
args
=
HeapAlloc
(
GetProcessHeap
(),
0
,
count
*
sizeof
(
WCHAR
))
;
memcpy
(
service
->
args
,
data
,
count
*
sizeof
(
WCHAR
)
)
;
service
->
thread
=
CreateThread
(
NULL
,
0
,
service_thread
,
service
,
0
,
NULL
);
SetEvent
(
service_event
);
/* notify the main loop */
end:
HeapFree
(
GetProcessHeap
(),
0
,
args
);
WriteFile
(
pipe
,
&
result
,
sizeof
result
,
&
read
,
NULL
);
return
TRUE
;
return
0
;
}
/******************************************************************************
* service_handle_control
*/
static
BOOL
service_handle_control
(
HANDLE
pipe
,
service_data
*
service
,
DWORD
dwControl
)
static
DWORD
service_handle_control
(
service_data
*
service
,
DWORD
dwControl
)
{
DWORD
count
,
ret
=
ERROR_INVALID_SERVICE_CONTROL
;
DWORD
ret
=
ERROR_INVALID_SERVICE_CONTROL
;
TRACE
(
"%s control %u
\n
"
,
debugstr_w
(
service
->
name
),
dwControl
);
TRACE
(
"received control %d
\n
"
,
dwControl
);
if
(
service
->
handler
)
ret
=
service
->
handler
(
dwControl
,
0
,
NULL
,
service
->
context
);
return
WriteFile
(
pipe
,
&
ret
,
sizeof
ret
,
&
count
,
NULL
)
;
return
ret
;
}
/******************************************************************************
...
...
@@ -478,61 +470,108 @@ static BOOL service_handle_control(HANDLE pipe, service_data *service,
*/
static
DWORD
WINAPI
service_control_dispatcher
(
LPVOID
arg
)
{
service_data
*
service
=
arg
;
SC_HANDLE
manager
;
HANDLE
pipe
;
TRACE
(
"%p %s
\n
"
,
service
,
debugstr_w
(
service
->
name
));
if
(
!
(
manager
=
OpenSCManagerW
(
NULL
,
NULL
,
SC_MANAGER_CONNECT
)))
{
ERR
(
"failed to open service manager error %u
\n
"
,
GetLastError
());
return
0
;
}
pipe
=
service_open_pipe
();
if
(
pipe
==
INVALID_HANDLE_VALUE
)
{
ERR
(
"failed to create pipe for %s, error = %d
\n
"
,
debugstr_w
(
service
->
name
),
GetLastError
());
ERR
(
"failed to create control pipe error = %d
\n
"
,
GetLastError
());
return
0
;
}
/* dispatcher loop */
while
(
1
)
{
service_data
*
service
;
service_start_info
info
;
WCHAR
*
data
=
NULL
;
BOOL
r
;
DWORD
count
,
req
[
2
]
=
{
0
,
0
}
;
DWORD
data_size
=
0
,
count
,
result
;
r
=
ReadFile
(
pipe
,
&
req
,
sizeof
req
,
&
count
,
NULL
);
r
=
ReadFile
(
pipe
,
&
info
,
FIELD_OFFSET
(
service_start_info
,
data
)
,
&
count
,
NULL
);
if
(
!
r
)
{
if
(
GetLastError
()
!=
ERROR_BROKEN_PIPE
)
ERR
(
"pipe read failed error %u
\n
"
,
GetLastError
()
);
break
;
}
if
(
count
!=
sizeof
(
req
))
if
(
count
!=
FIELD_OFFSET
(
service_start_info
,
data
))
{
ERR
(
"partial pipe read %u
\n
"
,
count
);
break
;
}
if
(
count
<
info
.
total_size
)
{
data_size
=
info
.
total_size
-
FIELD_OFFSET
(
service_start_info
,
data
);
data
=
HeapAlloc
(
GetProcessHeap
(),
0
,
data_size
);
r
=
ReadFile
(
pipe
,
data
,
data_size
,
&
count
,
NULL
);
if
(
!
r
)
{
if
(
GetLastError
()
!=
ERROR_BROKEN_PIPE
)
ERR
(
"pipe read failed error %u
\n
"
,
GetLastError
()
);
break
;
}
if
(
count
!=
data_size
)
{
ERR
(
"partial pipe read %u/%u
\n
"
,
count
,
data_size
);
break
;
}
}
/* find the service */
if
(
!
(
service
=
find_service_by_name
(
data
)))
{
FIXME
(
"got request %u for unknown service %s
\n
"
,
info
.
cmd
,
debugstr_w
(
data
));
result
=
ERROR_INVALID_PARAMETER
;
goto
done
;
}
TRACE
(
"got request %u for service %s
\n
"
,
info
.
cmd
,
debugstr_w
(
data
)
);
/* handle the request */
switch
(
req
[
0
]
)
switch
(
info
.
cmd
)
{
case
WINESERV_STARTINFO
:
service_handle_start
(
pipe
,
service
,
req
[
1
]);
if
(
!
service
->
handle
)
{
if
(
!
(
service
->
handle
=
OpenServiceW
(
manager
,
data
,
SERVICE_SET_STATUS
)))
FIXME
(
"failed to open service %s
\n
"
,
debugstr_w
(
data
)
);
}
result
=
service_handle_start
(
service
,
data
+
info
.
name_size
,
data_size
/
sizeof
(
WCHAR
)
-
info
.
name_size
);
break
;
case
WINESERV_SENDCONTROL
:
service_handle_control
(
pipe
,
service
,
req
[
1
]
);
result
=
service_handle_control
(
service
,
info
.
control
);
break
;
default:
ERR
(
"received invalid command %d length %d
\n
"
,
req
[
0
],
req
[
1
]);
ERR
(
"received invalid command %u
\n
"
,
info
.
cmd
);
result
=
ERROR_INVALID_PARAMETER
;
break
;
}
done:
WriteFile
(
pipe
,
&
result
,
sizeof
(
result
),
&
count
,
NULL
);
HeapFree
(
GetProcessHeap
(),
0
,
data
);
}
CloseHandle
(
pipe
);
CloseServiceHandle
(
manager
);
return
1
;
}
/******************************************************************************
* service_run_
threads
* service_run_
main_thread
*/
static
BOOL
service_run_
threads
(
void
)
static
BOOL
service_run_
main_thread
(
void
)
{
DWORD
i
,
n
,
ret
;
HANDLE
wait_handles
[
MAXIMUM_WAIT_OBJECTS
];
...
...
@@ -540,22 +579,19 @@ static BOOL service_run_threads(void)
service_event
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
/* FIXME: service_control_dispatcher should be merged into the main thread */
wait_handles
[
0
]
=
__wine_make_process_system
();
wait_handles
[
1
]
=
service_event
;
wait_handles
[
1
]
=
CreateThread
(
NULL
,
0
,
service_control_dispatcher
,
NULL
,
0
,
NULL
);
wait_handles
[
2
]
=
service_event
;
TRACE
(
"Starting %d
pipe listener threads. S
ervices running as process %d
\n
"
,
TRACE
(
"Starting %d
s
ervices running as process %d
\n
"
,
nb_services
,
GetCurrentProcessId
());
EnterCriticalSection
(
&
service_cs
);
for
(
i
=
0
;
i
<
nb_services
;
i
++
)
CloseHandle
(
CreateThread
(
NULL
,
0
,
service_control_dispatcher
,
services
[
i
],
0
,
NULL
));
LeaveCriticalSection
(
&
service_cs
);
/* wait for all the threads to pack up and exit */
for
(;;)
{
EnterCriticalSection
(
&
service_cs
);
for
(
i
=
0
,
n
=
2
;
i
<
nb_services
&&
n
<
MAXIMUM_WAIT_OBJECTS
;
i
++
)
for
(
i
=
0
,
n
=
3
;
i
<
nb_services
&&
n
<
MAXIMUM_WAIT_OBJECTS
;
i
++
)
{
if
(
!
services
[
i
]
->
thread
)
continue
;
wait_services
[
n
]
=
i
;
...
...
@@ -572,13 +608,19 @@ static BOOL service_run_threads(void)
}
else
if
(
ret
==
1
)
{
TRACE
(
"control dispatcher exited, shutting down
\n
"
);
/* FIXME: we should maybe send a shutdown control to running services */
ExitProcess
(
0
);
}
else
if
(
ret
==
2
)
{
continue
;
/* rebuild the list */
}
else
if
(
ret
<
n
)
{
services
[
wait_services
[
ret
]]
->
thread
=
0
;
CloseHandle
(
wait_handles
[
ret
]
);
if
(
n
==
3
)
return
TRUE
;
/* it was the last running thread */
if
(
n
==
4
)
return
TRUE
;
/* it was the last running thread */
}
else
return
FALSE
;
}
...
...
@@ -616,7 +658,7 @@ BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
services
[
i
]
=
info
;
}
service_run_
threads
();
service_run_
main_thread
();
return
ret
;
}
...
...
@@ -661,7 +703,7 @@ BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
services
[
i
]
=
info
;
}
service_run_
threads
();
service_run_
main_thread
();
return
ret
;
}
...
...
@@ -2214,40 +2256,23 @@ SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDL
SERVICE_STATUS_HANDLE
WINAPI
RegisterServiceCtrlHandlerExW
(
LPCWSTR
lpServiceName
,
LPHANDLER_FUNCTION_EX
lpHandlerProc
,
LPVOID
lpContext
)
{
SC_HANDLE
hService
;
SC_HANDLE
hSCM
;
unsigned
int
i
;
service_data
*
service
;
SC_HANDLE
hService
=
0
;
BOOL
found
=
FALSE
;
TRACE
(
"%s %p %p
\n
"
,
debugstr_w
(
lpServiceName
),
lpHandlerProc
,
lpContext
);
hSCM
=
OpenSCManagerW
(
NULL
,
NULL
,
SC_MANAGER_CONNECT
);
if
(
!
hSCM
)
return
NULL
;
hService
=
OpenServiceW
(
hSCM
,
lpServiceName
,
SERVICE_SET_STATUS
);
CloseServiceHandle
(
hSCM
);
if
(
!
hService
)
return
NULL
;
EnterCriticalSection
(
&
service_cs
);
for
(
i
=
0
;
i
<
nb_services
;
i
++
)
if
((
service
=
find_service_by_name
(
lpServiceName
))
)
{
if
(
!
strcmpW
(
lpServiceName
,
services
[
i
]
->
name
))
{
services
[
i
]
->
handler
=
lpHandlerProc
;
services
[
i
]
->
context
=
lpContext
;
found
=
TRUE
;
break
;
}
service
->
handler
=
lpHandlerProc
;
service
->
context
=
lpContext
;
hService
=
service
->
handle
;
found
=
TRUE
;
}
LeaveCriticalSection
(
&
service_cs
);
if
(
!
found
)
{
CloseServiceHandle
(
hService
);
SetLastError
(
ERROR_SERVICE_DOES_NOT_EXIST
);
return
NULL
;
}
if
(
!
found
)
SetLastError
(
ERROR_SERVICE_DOES_NOT_EXIST
);
return
(
SERVICE_STATUS_HANDLE
)
hService
;
}
...
...
include/wine/svcctl.idl
View file @
33914a1b
...
...
@@ -32,15 +32,20 @@ cpp_quote("#define SVCCTL_ENDPOINT {'\\\\','p','i','p','e','\\\\','s','v','c','c
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
*/
cpp_quote
(
"typedef struct service_start_info_t"
)
cpp_quote
(
"{"
)
cpp_quote
(
" DWORD cmd;"
)
cpp_quote
(
" DWORD size;"
)
cpp_quote
(
" WCHAR str[1];"
)
cpp_quote
(
"} service_start_info;"
)
cpp_quote
(
"#define WINESERV_STARTINFO 1"
)
cpp_quote
(
"#define WINESERV_SENDCONTROL 2"
)
enum
service_pipe_command
{
WINESERV_STARTINFO
=
1
,
WINESERV_SENDCONTROL
=
2
}
;
typedef
struct
service_start_info_t
{
enum
service_pipe_command
cmd
; /* request code */
DWORD
total_size
; /* total request size */
DWORD
name_size
; /* size of name in data buffer */
DWORD
control
; /* control code */
WCHAR
data
[
1
]
;
}
service_start_info
;
[
uuid
(
367
abb81
-
9844
-
35
f1
-
ad32
-
98
f038001003
),
...
...
programs/services/rpc.c
View file @
33914a1b
...
...
@@ -708,15 +708,24 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d
/******************************************************************************
* service_send_control
*/
static
BOOL
service_send_control
(
HANDLE
pipe
,
DWORD
dwControl
,
DWORD
*
result
)
static
BOOL
service_send_control
(
struct
service_entry
*
service
,
HANDLE
pipe
,
DWORD
dwControl
,
DWORD
*
result
)
{
DWORD
cmd
[
2
],
count
=
0
;
service_start_info
*
ssi
;
DWORD
len
,
count
=
0
;
BOOL
r
;
cmd
[
0
]
=
WINESERV_SENDCONTROL
;
cmd
[
1
]
=
dwControl
;
r
=
WriteFile
(
pipe
,
cmd
,
sizeof
cmd
,
&
count
,
NULL
);
if
(
!
r
||
count
!=
sizeof
cmd
)
/* calculate how much space we need to send the startup info */
len
=
strlenW
(
service
->
name
)
+
1
;
ssi
=
HeapAlloc
(
GetProcessHeap
(),
0
,
FIELD_OFFSET
(
service_start_info
,
data
[
len
]));
ssi
->
cmd
=
WINESERV_SENDCONTROL
;
ssi
->
control
=
dwControl
;
ssi
->
total_size
=
FIELD_OFFSET
(
service_start_info
,
data
[
len
]);
ssi
->
name_size
=
strlenW
(
service
->
name
)
+
1
;
strcpyW
(
ssi
->
data
,
service
->
name
);
r
=
WriteFile
(
pipe
,
ssi
,
ssi
->
total_size
,
&
count
,
NULL
);
if
(
!
r
||
count
!=
ssi
->
total_size
)
{
WINE_ERR
(
"service protocol error - failed to write pipe!
\n
"
);
return
r
;
...
...
@@ -837,7 +846,7 @@ DWORD svcctl_ControlService(
{
DWORD
result
=
ERROR_SUCCESS
;
ret
=
service_send_control
(
control_pipe
,
dwControl
,
&
result
);
ret
=
service_send_control
(
service
->
service_entry
,
control_pipe
,
dwControl
,
&
result
);
if
(
dwControl
==
SERVICE_CONTROL_STOP
)
{
...
...
programs/services/services.c
View file @
33914a1b
...
...
@@ -621,17 +621,17 @@ static DWORD service_wait_for_startup(struct service_entry *service_entry, HANDL
/******************************************************************************
* service_send_start_message
*/
static
BOOL
service_send_start_message
(
HANDLE
pip
e
,
LPCWSTR
*
argv
,
DWORD
argc
)
static
BOOL
service_send_start_message
(
struct
service_entry
*
servic
e
,
LPCWSTR
*
argv
,
DWORD
argc
)
{
DWORD
i
,
len
,
count
,
result
;
service_start_info
*
ssi
;
LPWSTR
p
;
BOOL
r
;
WINE_TRACE
(
"%
p %p %d
\n
"
,
pipe
,
argv
,
argc
);
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
(
pipe
,
NULL
);
r
=
ConnectNamedPipe
(
service
->
control_
pipe
,
NULL
);
if
(
!
r
&&
GetLastError
()
!=
ERROR_PIPE_CONNECTED
)
{
WINE_ERR
(
"pipe connect failed
\n
"
);
...
...
@@ -639,16 +639,20 @@ static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
}
/* calculate how much space do we need to send the startup info */
len
=
1
;
len
=
strlenW
(
service
->
name
)
+
1
;
for
(
i
=
0
;
i
<
argc
;
i
++
)
len
+=
strlenW
(
argv
[
i
])
+
1
;
len
++
;
ssi
=
HeapAlloc
(
GetProcessHeap
(),
0
,
FIELD_OFFSET
(
service_start_info
,
str
[
len
]));
ssi
=
HeapAlloc
(
GetProcessHeap
(),
0
,
FIELD_OFFSET
(
service_start_info
,
data
[
len
]));
ssi
->
cmd
=
WINESERV_STARTINFO
;
ssi
->
size
=
len
;
ssi
->
control
=
0
;
ssi
->
total_size
=
FIELD_OFFSET
(
service_start_info
,
data
[
len
]);
ssi
->
name_size
=
strlenW
(
service
->
name
)
+
1
;
strcpyW
(
ssi
->
data
,
service
->
name
);
/* copy service args into a single buffer*/
p
=
&
ssi
->
str
[
0
];
p
=
&
ssi
->
data
[
ssi
->
name_size
];
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
strcpyW
(
p
,
argv
[
i
]);
...
...
@@ -656,10 +660,10 @@ static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
}
*
p
=
0
;
r
=
WriteFile
(
pipe
,
ssi
,
FIELD_OFFSET
(
service_start_info
,
str
[
len
])
,
&
count
,
NULL
);
r
=
WriteFile
(
service
->
control_pipe
,
ssi
,
ssi
->
total_size
,
&
count
,
NULL
);
if
(
r
)
{
r
=
ReadFile
(
pipe
,
&
result
,
sizeof
result
,
&
count
,
NULL
);
r
=
ReadFile
(
service
->
control_
pipe
,
&
result
,
sizeof
result
,
&
count
,
NULL
);
if
(
r
&&
result
)
{
SetLastError
(
result
);
...
...
@@ -709,8 +713,7 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *
if
(
err
==
ERROR_SUCCESS
)
{
if
(
!
service_send_start_message
(
service
->
control_pipe
,
service_argv
,
service_argc
))
if
(
!
service_send_start_message
(
service
,
service_argv
,
service_argc
))
err
=
ERROR_SERVICE_REQUEST_TIMEOUT
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment