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 * RpcServerRegisterIf (RPCRT4.@)
441 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
443 TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
444 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
447 /***********************************************************************
448 * RpcServerRegisterIfEx (RPCRT4.@)
450 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
451 UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
453 TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
454 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
457 /***********************************************************************
458 * RpcServerRegisterIf2 (RPCRT4.@)
460 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
461 UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
463 PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
464 RpcServerInterface* sif;
467 TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
468 MaxRpcSize, IfCallbackFn);
469 TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
470 If->InterfaceId.SyntaxVersion.MajorVersion,
471 If->InterfaceId.SyntaxVersion.MinorVersion);
472 TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
473 If->InterfaceId.SyntaxVersion.MajorVersion,
474 If->InterfaceId.SyntaxVersion.MinorVersion);
475 TRACE(" dispatch table: %p\n", If->DispatchTable);
476 if (If->DispatchTable) {
477 TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
478 for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
479 TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
481 TRACE(" reserved: %ld\n", If->DispatchTable->Reserved);
483 TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
484 TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
485 TRACE(" interpreter info: %p\n", If->InterpreterInfo);
486 TRACE(" flags: %08x\n", If->Flags);
488 sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
491 memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
493 memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
494 sif->MgrEpv = MgrEpv;
496 sif->MaxCalls = MaxCalls;
497 sif->MaxRpcSize = MaxRpcSize;
498 sif->IfCallbackFn = IfCallbackFn;
500 EnterCriticalSection(&server_cs);
503 LeaveCriticalSection(&server_cs);
505 if (sif->Flags & RPC_IF_AUTOLISTEN) {
506 /* well, start listening, I think... */
507 RPCRT4_start_listen();
513 /***********************************************************************
514 * RpcServerRegisterAuthInfoA (RPCRT4.@)
516 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( LPSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
519 FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
521 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
524 /***********************************************************************
525 * RpcServerRegisterAuthInfoW (RPCRT4.@)
527 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
530 FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
532 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
535 /***********************************************************************
536 * RpcServerListen (RPCRT4.@)
538 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
540 TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
543 return RPC_S_ALREADY_LISTENING;
546 return RPC_S_NO_PROTSEQS_REGISTERED;
549 RPCRT4_start_listen();
551 if (DontWait) return RPC_S_OK;
553 return RpcMgmtWaitServerListen();
556 /***********************************************************************
557 * RpcMgmtServerWaitListen (RPCRT4.@)
559 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
563 RPCRT4_start_listen();
564 while (listen_count > -1) {
565 WaitForSingleObject(mgr_event, 1000);
571 /***********************************************************************
572 * I_RpcServerStartListening (RPCRT4.@)
574 RPC_STATUS WINAPI I_RpcServerStartListening( void* hWnd )
576 FIXME( "(%p): stub\n", hWnd );
581 /***********************************************************************
582 * I_RpcServerStopListening (RPCRT4.@)
584 RPC_STATUS WINAPI I_RpcServerStopListening( void )
586 FIXME( "(): stub\n" );
591 /***********************************************************************
592 * I_RpcWindowProc (RPCRT4.@)
594 UINT WINAPI I_RpcWindowProc( void* hWnd, UINT Message, UINT wParam, ULONG lParam )
596 FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );