4 * Copyright 2001 Ove Kåven, TransGaming Technologies
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "wine/debug.h"
36 #include "rpc_server.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41 static RpcServerProtseq* protseqs;
42 static RpcServerInterface* ifs;
44 static CRITICAL_SECTION server_cs = CRITICAL_SECTION_INIT("RpcServer");
45 static BOOL std_listen;
46 static LONG listen_count = -1;
47 static HANDLE mgr_event, server_thread;
49 static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id)
52 RpcServerInterface* cif = NULL;
55 /* FIXME: object -> MgrType */
56 EnterCriticalSection(&server_cs);
59 if (UuidEqual(if_id, &cif->If->InterfaceId.SyntaxGUID, &status) &&
60 UuidEqual(MgrType, &cif->MgrTypeUuid, &status) &&
61 (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break;
64 LeaveCriticalSection(&server_cs);
68 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
70 RpcBinding* bind = (RpcBinding*)the_arg;
74 RpcServerInterface* sif;
75 RPC_DISPATCH_FUNCTION func;
77 memset(&msg, 0, sizeof(msg));
78 msg.Handle = (RPC_BINDING_HANDLE)bind;
81 /* read packet header */
82 #ifdef OVERLAPPED_WORKS
83 if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, &bind->ovl)) {
84 DWORD err = GetLastError();
85 if (err != ERROR_IO_PENDING) {
86 TRACE("connection lost, error=%08lx\n", err);
89 if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
92 if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
93 TRACE("connection lost, error=%08lx\n", GetLastError());
97 if (dwRead != sizeof(hdr)) {
98 TRACE("protocol error\n");
102 /* read packet body */
103 msg.BufferLength = hdr.len;
104 msg.Buffer = HeapAlloc(GetProcessHeap(), 0, msg.BufferLength);
105 #ifdef OVERLAPPED_WORKS
106 if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, &bind->ovl)) {
107 DWORD err = GetLastError();
108 if (err != ERROR_IO_PENDING) {
109 TRACE("connection lost, error=%08lx\n", err);
112 if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
115 if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, NULL)) {
116 TRACE("connection lost, error=%08lx\n", GetLastError());
120 if (dwRead != hdr.len) {
121 TRACE("protocol error\n");
125 sif = RPCRT4_find_interface(&hdr.object, &hdr.if_id);
127 msg.RpcInterfaceInformation = sif->If;
128 /* associate object with binding (this is a bit of a hack...
129 * a new binding should probably be created for each object) */
130 RPCRT4_SetBindingObject(bind, &hdr.object);
134 /* find dispatch function */
135 msg.ProcNum = hdr.opnum;
136 if (sif->Flags & RPC_IF_OLE) {
137 /* native ole32 always gives us a dispatch table with a single entry
138 * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
139 func = *sif->If->DispatchTable->DispatchTable;
141 if (msg.ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
142 ERR("invalid procnum\n");
145 func = sif->If->DispatchTable->DispatchTable[msg.ProcNum];
149 if (func) func(&msg);
151 /* prepare response packet */
152 hdr.ptype = PKT_RESPONSE;
155 ERR("unknown packet type\n");
159 /* write reply packet */
160 hdr.len = msg.BufferLength;
161 WriteFile(bind->conn, &hdr, sizeof(hdr), NULL, NULL);
162 WriteFile(bind->conn, msg.Buffer, msg.BufferLength, NULL, NULL);
165 /* un-associate object */
166 RPCRT4_SetBindingObject(bind, NULL);
167 msg.RpcInterfaceInformation = NULL;
170 ERR("got RPC packet to unregistered interface %s\n", debugstr_guid(&hdr.if_id));
174 HeapFree(GetProcessHeap(), 0, msg.Buffer);
177 if (msg.Buffer) HeapFree(GetProcessHeap(), 0, msg.Buffer);
178 RPCRT4_DestroyBinding(bind);
182 static void RPCRT4_new_client(RpcBinding* bind)
184 bind->thread = CreateThread(NULL, 0, RPCRT4_io_thread, bind, 0, NULL);
187 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
189 HANDLE m_event = mgr_event, b_handle;
192 RpcServerProtseq* cps;
197 EnterCriticalSection(&server_cs);
198 /* open and count bindings */
204 RPCRT4_OpenBinding(bind);
205 if (bind->ovl.hEvent) count++;
210 /* make array of bindings */
211 objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
218 if (bind->ovl.hEvent) objs[count++] = bind->ovl.hEvent;
223 LeaveCriticalSection(&server_cs);
226 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
227 if (res == WAIT_OBJECT_0) {
228 if (listen_count == -1) break;
230 else if (res == WAIT_FAILED) {
231 ERR("wait failed\n");
234 b_handle = objs[res - WAIT_OBJECT_0];
235 /* find which binding got a RPC */
236 EnterCriticalSection(&server_cs);
242 if (bind->ovl.hEvent == b_handle) break;
249 if (bind) RPCRT4_SpawnBinding(&cbind, bind);
250 LeaveCriticalSection(&server_cs);
252 ERR("failed to locate binding for handle %p\n", b_handle);
254 if (cbind) RPCRT4_new_client(cbind);
257 HeapFree(GetProcessHeap(), 0, objs);
258 EnterCriticalSection(&server_cs);
264 RPCRT4_CloseBinding(bind);
269 LeaveCriticalSection(&server_cs);
273 static void RPCRT4_start_listen(void)
276 if (!InterlockedIncrement(&listen_count)) {
277 mgr_event = CreateEventA(NULL, FALSE, FALSE, NULL);
278 server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
280 else SetEvent(mgr_event);
283 /* not used (WTF?) ---------------------------
285 static void RPCRT4_stop_listen(void)
287 HANDLE m_event = mgr_event;
288 if (InterlockedDecrement(&listen_count) < 0)
292 --------------------- */
294 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
296 RPCRT4_CreateBindingA(&ps->bind, TRUE, ps->Protseq);
297 RPCRT4_CompleteBindingA(ps->bind, NULL, ps->Endpoint, NULL);
299 EnterCriticalSection(&server_cs);
302 LeaveCriticalSection(&server_cs);
304 if (listen_count >= 0) SetEvent(mgr_event);
309 /***********************************************************************
310 * RpcServerInqBindings (RPCRT4.@)
312 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
316 RpcServerProtseq* ps;
320 TRACE("(*BindingVector == ^%p)\n", *BindingVector);
322 ERR("(BindingVector == ^null!!?)\n");
324 EnterCriticalSection(&server_cs);
337 /* export bindings */
338 *BindingVector = HeapAlloc(GetProcessHeap(), 0,
339 sizeof(RPC_BINDING_VECTOR) +
340 sizeof(RPC_BINDING_HANDLE)*(count-1));
341 (*BindingVector)->Count = count;
347 RPCRT4_ExportBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
356 *BindingVector = NULL;
357 status = RPC_S_NO_BINDINGS;
359 LeaveCriticalSection(&server_cs);
363 /***********************************************************************
364 * RpcServerUseProtseqEpA (RPCRT4.@)
366 RPC_STATUS WINAPI RpcServerUseProtseqEpA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor )
370 TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
372 /* This should provide the default behaviour */
373 policy.Length = sizeof( policy );
374 policy.EndpointFlags = 0;
377 return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
380 /***********************************************************************
381 * RpcServerUseProtseqEpW (RPCRT4.@)
383 RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
387 TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
389 /* This should provide the default behaviour */
390 policy.Length = sizeof( policy );
391 policy.EndpointFlags = 0;
394 return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
397 /***********************************************************************
398 * RpcServerUseProtseqEpExA (RPCRT4.@)
400 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor,
401 PRPC_POLICY lpPolicy )
403 RpcServerProtseq* ps;
405 TRACE("(%s,%u,%s,%p,{%u,%lu,%lu}): stub\n", debugstr_a( Protseq ), MaxCalls,
406 debugstr_a( Endpoint ), SecurityDescriptor,
407 lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
409 ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
410 ps->MaxCalls = MaxCalls;
411 ps->Protseq = RPCRT4_strdupA(Protseq);
412 ps->Endpoint = RPCRT4_strdupA(Endpoint);
414 return RPCRT4_use_protseq(ps);
417 /***********************************************************************
418 * RpcServerUseProtseqEpExW (RPCRT4.@)
420 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
421 PRPC_POLICY lpPolicy )
423 RpcServerProtseq* ps;
425 TRACE("(%s,%u,%s,%p,{%u,%lu,%lu}): stub\n", debugstr_w( Protseq ), MaxCalls,
426 debugstr_w( Endpoint ), SecurityDescriptor,
427 lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
429 ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
430 ps->MaxCalls = MaxCalls;
431 /* FIXME: Did Ove have these next two as RPCRT4_strdupW for a reason? */
432 ps->Protseq = RPCRT4_strdupWtoA(Protseq);
433 ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);
435 return RPCRT4_use_protseq(ps);
438 /***********************************************************************
439 * RpcServerUseProtseqA (RPCRT4.@)
441 RPC_STATUS WINAPI RpcServerUseProtseqA(LPSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
447 /***********************************************************************
448 * RpcServerUseProtseqW (RPCRT4.@)
450 RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
456 /***********************************************************************
457 * RpcServerRegisterIf (RPCRT4.@)
459 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
461 TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
462 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
465 /***********************************************************************
466 * RpcServerRegisterIfEx (RPCRT4.@)
468 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
469 UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
471 TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
472 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
475 /***********************************************************************
476 * RpcServerRegisterIf2 (RPCRT4.@)
478 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
479 UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
481 PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
482 RpcServerInterface* sif;
485 TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
486 MaxRpcSize, IfCallbackFn);
487 TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
488 If->InterfaceId.SyntaxVersion.MajorVersion,
489 If->InterfaceId.SyntaxVersion.MinorVersion);
490 TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
491 If->InterfaceId.SyntaxVersion.MajorVersion,
492 If->InterfaceId.SyntaxVersion.MinorVersion);
493 TRACE(" dispatch table: %p\n", If->DispatchTable);
494 if (If->DispatchTable) {
495 TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
496 for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
497 TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
499 TRACE(" reserved: %ld\n", If->DispatchTable->Reserved);
501 TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
502 TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
503 TRACE(" interpreter info: %p\n", If->InterpreterInfo);
504 TRACE(" flags: %08x\n", If->Flags);
506 sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
509 memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
511 memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
512 sif->MgrEpv = MgrEpv;
514 sif->MaxCalls = MaxCalls;
515 sif->MaxRpcSize = MaxRpcSize;
516 sif->IfCallbackFn = IfCallbackFn;
518 EnterCriticalSection(&server_cs);
521 LeaveCriticalSection(&server_cs);
523 if (sif->Flags & RPC_IF_AUTOLISTEN) {
524 /* well, start listening, I think... */
525 RPCRT4_start_listen();
531 /***********************************************************************
532 * RpcServerRegisterAuthInfoA (RPCRT4.@)
534 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( LPSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
537 FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
539 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
542 /***********************************************************************
543 * RpcServerRegisterAuthInfoW (RPCRT4.@)
545 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
548 FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
550 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
553 /***********************************************************************
554 * RpcServerListen (RPCRT4.@)
556 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
558 TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
561 return RPC_S_ALREADY_LISTENING;
564 return RPC_S_NO_PROTSEQS_REGISTERED;
567 RPCRT4_start_listen();
569 if (DontWait) return RPC_S_OK;
571 return RpcMgmtWaitServerListen();
574 /***********************************************************************
575 * RpcMgmtServerWaitListen (RPCRT4.@)
577 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
579 RPC_STATUS rslt = RPC_S_OK;
583 if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK )
587 WaitForSingleObject(mgr_event, 1000);
593 /***********************************************************************
594 * I_RpcServerStartListening (RPCRT4.@)
596 RPC_STATUS WINAPI I_RpcServerStartListening( void* hWnd )
598 FIXME( "(%p): stub\n", hWnd );
603 /***********************************************************************
604 * I_RpcServerStopListening (RPCRT4.@)
606 RPC_STATUS WINAPI I_RpcServerStopListening( void )
608 FIXME( "(): stub\n" );
613 /***********************************************************************
614 * I_RpcWindowProc (RPCRT4.@)
616 UINT WINAPI I_RpcWindowProc( void* hWnd, UINT Message, UINT wParam, ULONG lParam )
618 FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );