2 * RPCSS named pipe server
4 * Copyright (C) 2002 Greg Turner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
28 static HANDLE np_server_end
;
29 static HANDLE np_server_work_event
;
30 static CRITICAL_SECTION np_server_cs
;
31 static LONG srv_thread_count
;
32 static BOOL server_live
;
34 LONG
RPCSS_SrvThreadCount(void)
36 return srv_thread_count
;
39 BOOL
RPCSS_UnBecomePipeServer(void)
43 WINE_TRACE("shutting down pipe.\n");
45 if (!CloseHandle(np_server_end
))
46 WINE_WARN("Failed to close named pipe.\n");
47 if (!CloseHandle(np_server_work_event
))
48 WINE_WARN("Failed to close the event handle.\n");
49 DeleteCriticalSection(&np_server_cs
);
54 static void RPCSS_ServerProcessRANMessage(PRPCSS_NP_MESSAGE pMsg
, PRPCSS_NP_REPLY pReply
)
60 static void RPCSS_ServerProcessREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg
, PRPCSS_NP_REPLY pReply
,
65 RPCSS_RegisterRpcEndpoints(
66 pMsg
->message
.registerepmsg
.iface
,
67 pMsg
->message
.registerepmsg
.object_count
,
68 pMsg
->message
.registerepmsg
.binding_count
,
69 pMsg
->message
.registerepmsg
.no_replace
,
71 pMsg
->vardata_payload_size
78 static void RPCSS_ServerProcessUNREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg
,
79 PRPCSS_NP_REPLY pReply
, char *vardata
)
83 RPCSS_UnregisterRpcEndpoints(
84 pMsg
->message
.unregisterepmsg
.iface
,
85 pMsg
->message
.unregisterepmsg
.object_count
,
86 pMsg
->message
.unregisterepmsg
.binding_count
,
88 pMsg
->vardata_payload_size
95 static void RPCSS_ServerProcessRESOLVEEPMessage(PRPCSS_NP_MESSAGE pMsg
,
96 PRPCSS_NP_REPLY pReply
, char *vardata
)
100 /* for now, reply is placed into *pReply.as_string, on success, by RPCSS_ResolveRpcEndpoints */
101 ZeroMemory(pReply
->as_string
, MAX_RPCSS_NP_REPLY_STRING_LEN
);
102 RPCSS_ResolveRpcEndpoints(
103 pMsg
->message
.resolveepmsg
.iface
,
104 pMsg
->message
.resolveepmsg
.object
,
110 static void RPCSS_ServerProcessMessage(PRPCSS_NP_MESSAGE pMsg
, PRPCSS_NP_REPLY pReply
, char *vardata
)
113 switch (pMsg
->message_type
) {
114 case RPCSS_NP_MESSAGE_TYPEID_RANMSG
:
115 RPCSS_ServerProcessRANMessage(pMsg
, pReply
);
117 case RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG
:
118 RPCSS_ServerProcessREGISTEREPMessage(pMsg
, pReply
, vardata
);
120 case RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG
:
121 RPCSS_ServerProcessUNREGISTEREPMessage(pMsg
, pReply
, vardata
);
123 case RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG
:
124 RPCSS_ServerProcessRESOLVEEPMessage(pMsg
, pReply
, vardata
);
127 WINE_ERR("Message type unknown!! No action taken.\n");
131 /* each message gets its own thread. this is it. */
132 static DWORD WINAPI
HandlerThread(LPVOID lpvPipeHandle
)
134 RPCSS_NP_MESSAGE msg
, vardata_payload_msg
;
135 char *c
, *vardata
= NULL
;
136 RPCSS_NP_REPLY reply
;
137 DWORD bytesread
, written
;
138 BOOL success
, had_payload
= FALSE
;
141 mypipe
= (HANDLE
) lpvPipeHandle
;
143 WINE_TRACE("mypipe: %p\n", mypipe
);
146 mypipe
, /* pipe handle */
147 (char *) &msg
, /* message buffer */
148 sizeof(RPCSS_NP_MESSAGE
), /* message buffer size */
149 &bytesread
, /* receives number of bytes read */
150 NULL
/* not overlapped */
153 if (msg
.vardata_payload_size
) {
155 /* this fudge space allows us not to worry about exceeding the buffer space
157 vardata
= LocalAlloc(LPTR
, (msg
.vardata_payload_size
) + VARDATA_PAYLOAD_BYTES
);
159 WINE_ERR("vardata memory allocation failure.\n");
162 for ( c
= vardata
; (c
- vardata
) < msg
.vardata_payload_size
;
163 c
+= VARDATA_PAYLOAD_BYTES
) {
166 (char *) &vardata_payload_msg
,
167 sizeof(RPCSS_NP_MESSAGE
),
171 if ( (!success
) || (bytesread
!= sizeof(RPCSS_NP_MESSAGE
)) ||
172 (vardata_payload_msg
.message_type
!= RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG
) ) {
173 WINE_ERR("vardata payload read failure! (s=%s,br=%d,mt=%u,mt_exp=%u\n",
174 success
? "TRUE" : "FALSE", bytesread
,
175 vardata_payload_msg
.message_type
, RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG
);
179 CopyMemory(c
, vardata_payload_msg
.message
.vardatapayloadmsg
.payload
, VARDATA_PAYLOAD_BYTES
);
180 WINE_TRACE("payload read.\n");
185 if (success
&& (bytesread
== sizeof(RPCSS_NP_MESSAGE
))) {
186 WINE_TRACE("read success.\n");
187 /* process the message and send a reply, serializing requests. */
188 EnterCriticalSection(&np_server_cs
);
189 WINE_TRACE("processing message.\n");
190 RPCSS_ServerProcessMessage(&msg
, &reply
, vardata
);
191 LeaveCriticalSection(&np_server_cs
);
193 if (had_payload
) LocalFree(vardata
);
195 WINE_TRACE("message processed, sending reply....\n");
198 mypipe
, /* pipe handle */
199 (char *) &reply
, /* reply buffer */
200 sizeof(RPCSS_NP_REPLY
), /* reply buffer size */
201 &written
, /* receives number of bytes written */
202 NULL
/* not overlapped */
205 if ( (!success
) || (written
!= sizeof(RPCSS_NP_REPLY
)) )
206 WINE_WARN("Message reply failed. (success=%d, br=%d)\n", success
, written
);
208 WINE_TRACE("Reply sent successfully.\n");
210 WINE_WARN("Message receipt failed.\n");
212 FlushFileBuffers(mypipe
);
213 DisconnectNamedPipe(mypipe
);
215 InterlockedDecrement(&srv_thread_count
);
219 static DWORD WINAPI
NPMainWorkThread(LPVOID ignored
)
222 HANDLE hthread
, master_mutex
= RPCSS_GetMasterMutex();
223 DWORD threadid
, wait_result
;
227 while (server_live
) {
228 connected
= ConnectNamedPipe(np_server_end
, NULL
) ?
229 TRUE
: (GetLastError() == ERROR_PIPE_CONNECTED
);
232 /* is "work" the act of connecting pipes, or the act of serving
233 requests successfully? for now I will make it the former. */
234 if (!SetEvent(np_server_work_event
))
235 WINE_WARN("failed to signal np_server_work_event.\n");
237 /* Create a thread for this client. */
238 InterlockedIncrement(&srv_thread_count
);
239 hthread
= CreateThread(
240 NULL
, /* no security attribute */
241 0, /* default stack size */
243 (LPVOID
) np_server_end
, /* thread parameter */
244 0, /* not suspended */
245 &threadid
/* returns thread ID (not used) */
249 WINE_TRACE("Spawned handler thread: %p\n", hthread
);
250 CloseHandle(hthread
);
252 /* for safety's sake, hold the mutex while we switch the pipe */
254 wait_result
= WaitForSingleObject(master_mutex
, MASTER_MUTEX_TIMEOUT
);
256 switch (wait_result
) {
257 case WAIT_ABANDONED
: /* ? */
259 /* we have ownership */
265 wait_result
= WAIT_FAILED
;
268 if (wait_result
== WAIT_FAILED
) {
269 WINE_ERR("Couldn't enter master mutex. Expect prolems.\n");
271 /* now create a new named pipe instance to listen on */
272 np_server_end
= CreateNamedPipe(
273 NAME_RPCSS_NAMED_PIPE
, /* pipe name */
274 PIPE_ACCESS_DUPLEX
, /* pipe open mode */
275 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
, /* pipe-specific modes */
276 PIPE_UNLIMITED_INSTANCES
, /* maximum instances */
277 sizeof(RPCSS_NP_REPLY
), /* output buffer size */
278 sizeof(RPCSS_NP_MESSAGE
), /* input buffer size */
279 2000, /* time-out interval */
283 if (np_server_end
== INVALID_HANDLE_VALUE
) {
284 WINE_ERR("Failed to recreate named pipe!\n");
285 /* not sure what to do? */
289 if (!ReleaseMutex(master_mutex
))
290 WINE_ERR("Uh oh. Couldn't leave master mutex. Expect deadlock.\n");
293 WINE_ERR("Failed to spawn handler thread!\n");
294 DisconnectNamedPipe(np_server_end
);
295 InterlockedDecrement(&srv_thread_count
);
299 WINE_TRACE("Server thread shutdown.\n");
303 static HANDLE
RPCSS_NPConnect(void)
306 DWORD dwmode
, wait_result
;
307 HANDLE master_mutex
= RPCSS_GetMasterMutex();
313 wait_result
= WaitForSingleObject(master_mutex
, MASTER_MUTEX_TIMEOUT
);
314 switch (wait_result
) {
321 WINE_ERR("This should never happen: couldn't enter mutex.\n");
325 /* try to open the client side of the named pipe. */
326 the_pipe
= CreateFileA(
327 NAME_RPCSS_NAMED_PIPE
, /* pipe name */
328 GENERIC_READ
| GENERIC_WRITE
, /* r/w access */
330 NULL
, /* no security attributes */
331 OPEN_EXISTING
, /* open an existing pipe */
332 0, /* default attributes */
333 NULL
/* no template file */
336 if (the_pipe
!= INVALID_HANDLE_VALUE
)
339 if (GetLastError() != ERROR_PIPE_BUSY
) {
340 WINE_WARN("Unable to open named pipe %s (assuming unavailable).\n",
341 wine_dbgstr_a(NAME_RPCSS_NAMED_PIPE
));
345 WINE_WARN("Named pipe busy (will wait)\n");
347 if (!ReleaseMutex(master_mutex
))
348 WINE_ERR("Failed to release master mutex. Expect deadlock.\n");
350 /* wait for the named pipe. We are only
351 willing to wait only 5 seconds. It should be available /very/ soon. */
352 if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE
, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT
))
354 WINE_ERR("Named pipe unavailable after waiting. Something is probably wrong.\n");
360 if (the_pipe
!= INVALID_HANDLE_VALUE
) {
361 dwmode
= PIPE_READMODE_MESSAGE
;
362 /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */
363 if (! SetNamedPipeHandleState(the_pipe
, &dwmode
, NULL
, NULL
))
364 WINE_WARN("Failed to set pipe handle state\n");
367 if (!ReleaseMutex(master_mutex
))
368 WINE_ERR("Uh oh, failed to leave the RPC Master Mutex!\n");
373 static BOOL
RPCSS_SendReceiveNPMsg(HANDLE np
, PRPCSS_NP_MESSAGE msg
, PRPCSS_NP_REPLY reply
)
377 WINE_TRACE("(np == %p, msg == %p, reply == %p)\n", np
, msg
, reply
);
379 if (! WriteFile(np
, msg
, sizeof(RPCSS_NP_MESSAGE
), &count
, NULL
)) {
380 WINE_ERR("write failed.\n");
384 if (count
!= sizeof(RPCSS_NP_MESSAGE
)) {
385 WINE_ERR("write count mismatch.\n");
389 if (! ReadFile(np
, reply
, sizeof(RPCSS_NP_REPLY
), &count
, NULL
)) {
390 WINE_ERR("read failed.\n");
394 if (count
!= sizeof(RPCSS_NP_REPLY
)) {
395 WINE_ERR("read count mismatch, got %d.\n", count
);
399 /* message execution was successful */
403 BOOL
RPCSS_BecomePipeServer(void)
405 RPCSS_NP_MESSAGE msg
;
406 RPCSS_NP_REPLY reply
;
408 HANDLE client_handle
, hthread
, master_mutex
= RPCSS_GetMasterMutex();
409 DWORD threadid
, wait_result
;
413 wait_result
= WaitForSingleObject(master_mutex
, MASTER_MUTEX_TIMEOUT
);
415 switch (wait_result
) {
416 case WAIT_ABANDONED
: /* ? */
418 /* we have ownership */
423 WINE_ERR("Couldn't enter master mutex.\n");
427 /* now we have the master mutex. during this time we will
429 * o check if an rpcss already listens on the pipe. If so,
430 * we will tell it we were invoked, which will cause the
431 * other end to update its timeouts. After, we just return
434 * o otherwise, we establish the pipe for ourselves and get
435 * ready to listen on it
438 if ((client_handle
= RPCSS_NPConnect()) != INVALID_HANDLE_VALUE
) {
439 msg
.message_type
= RPCSS_NP_MESSAGE_TYPEID_RANMSG
;
440 msg
.message
.ranmsg
.timeout
= 1000;
441 msg
.vardata_payload_size
= 0;
442 if (!RPCSS_SendReceiveNPMsg(client_handle
, &msg
, &reply
))
443 WINE_ERR("Something is amiss: RPC_SendReceive failed.\n");
444 CloseHandle(client_handle
);
448 np_server_work_event
= CreateEventA(NULL
, FALSE
, FALSE
, "RpcNpServerWorkEvent");
449 if (np_server_work_event
== NULL
) {
450 /* dunno what we can do then */
451 WINE_ERR("Unable to create the np_server_work_event\n");
454 InitializeCriticalSection(&np_server_cs
);
456 np_server_end
= CreateNamedPipe(
457 NAME_RPCSS_NAMED_PIPE
, /* pipe name */
458 PIPE_ACCESS_DUPLEX
, /* pipe open mode */
459 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
, /* pipe-specific modes */
460 PIPE_UNLIMITED_INSTANCES
, /* maximum number of instances */
461 sizeof(RPCSS_NP_REPLY
), /* output buffer size */
462 sizeof(RPCSS_NP_MESSAGE
), /* input buffer size */
463 2000, /* time-out interval */
467 if (np_server_end
== INVALID_HANDLE_VALUE
) {
468 WINE_ERR("Failed to create named pipe!\n");
469 DeleteCriticalSection(&np_server_cs
);
470 if (!CloseHandle(np_server_work_event
)) /* we will leak the handle... */
471 WINE_WARN("Failed to close np_server_work_event handle!\n");
472 np_server_work_event
= NULL
;
473 np_server_end
= NULL
;
481 /* OK, now spawn the (single) server thread */
482 hthread
= CreateThread(
483 NULL
, /* no security attribute */
484 0, /* default stack size */
486 NULL
, /* thread parameter */
487 0, /* not suspended */
488 &threadid
/* returns thread ID (not used) */
491 WINE_TRACE("Created server thread.\n");
492 CloseHandle(hthread
);
494 WINE_ERR("Serious error: unable to create server thread!\n");
495 if (!CloseHandle(np_server_work_event
)) /* we will leak the handle... */
496 WINE_WARN("Failed to close np_server_work_event handle!\n");
497 if (!CloseHandle(np_server_end
)) /* we will leak the handle... */
498 WINE_WARN("Unable to close named pipe handle!\n");
499 DeleteCriticalSection(&np_server_cs
);
500 np_server_end
= NULL
;
501 np_server_work_event
= NULL
;
506 if (!ReleaseMutex(master_mutex
))
507 WINE_ERR("Unable to leave master mutex!??\n");
512 BOOL
RPCSS_NPDoWork(HANDLE exit_handle
)
517 handles
[0] = np_server_work_event
;
518 handles
[1] = exit_handle
;
519 waitresult
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
521 if (waitresult
== WAIT_OBJECT_0
)