Sync to Wine-20050830:
[reactos.git] / reactos / lib / rpcrt4 / rpc_server.c
1 /*
2 * RPC server API
3 *
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2004 Filip Navara
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * TODO:
22 * - a whole lot
23 */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "ntstatus.h"
38
39 #include "rpc.h"
40 #include "rpcndr.h"
41 #include "excpt.h"
42
43 #include "wine/debug.h"
44 #include "wine/exception.h"
45
46 #include "rpc_server.h"
47 #include "rpc_misc.h"
48 #include "rpc_message.h"
49 #include "rpc_defs.h"
50
51 #define MAX_THREADS 128
52
53 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
54
55 typedef struct _RpcPacket
56 {
57 struct _RpcPacket* next;
58 struct _RpcConnection* conn;
59 RpcPktHdr* hdr;
60 RPC_MESSAGE* msg;
61 } RpcPacket;
62
63 typedef struct _RpcObjTypeMap
64 {
65 /* FIXME: a hash table would be better. */
66 struct _RpcObjTypeMap *next;
67 UUID Object;
68 UUID Type;
69 } RpcObjTypeMap;
70
71 static RpcObjTypeMap *RpcObjTypeMaps;
72
73 static RpcServerProtseq* protseqs;
74 static RpcServerInterface* ifs;
75
76 static CRITICAL_SECTION server_cs;
77 static CRITICAL_SECTION_DEBUG server_cs_debug =
78 {
79 0, 0, &server_cs,
80 { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
81 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") }
82 };
83 static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
84
85 static CRITICAL_SECTION listen_cs;
86 static CRITICAL_SECTION_DEBUG listen_cs_debug =
87 {
88 0, 0, &listen_cs,
89 { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
90 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") }
91 };
92 static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
93
94 /* whether the server is currently listening */
95 static BOOL std_listen;
96 /* number of manual listeners (calls to RpcServerListen) */
97 static LONG manual_listen_count;
98 /* total listeners including auto listeners */
99 static LONG listen_count;
100 /* set on change of configuration (e.g. listening on new protseq) */
101 static HANDLE mgr_event;
102 /* mutex for ensuring only one thread can change state at a time */
103 static HANDLE mgr_mutex;
104 /* set when server thread has finished opening connections */
105 static HANDLE server_ready_event;
106
107 static CRITICAL_SECTION spacket_cs;
108 static CRITICAL_SECTION_DEBUG spacket_cs_debug =
109 {
110 0, 0, &spacket_cs,
111 { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList },
112 0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") }
113 };
114 static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 };
115
116 static RpcPacket* spacket_head;
117 static RpcPacket* spacket_tail;
118 static HANDLE server_sem;
119
120 static LONG worker_count, worker_free, worker_tls;
121
122 static UUID uuid_nil;
123
124 inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
125 {
126 RpcObjTypeMap *rslt = RpcObjTypeMaps;
127 RPC_STATUS dummy;
128
129 while (rslt) {
130 if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
131 rslt = rslt->next;
132 }
133
134 return rslt;
135 }
136
137 inline static UUID *LookupObjType(UUID *ObjUuid)
138 {
139 RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
140 if (map)
141 return &map->Type;
142 else
143 return &uuid_nil;
144 }
145
146 static RpcServerInterface* RPCRT4_find_interface(UUID* object,
147 RPC_SYNTAX_IDENTIFIER* if_id,
148 BOOL check_object)
149 {
150 UUID* MgrType = NULL;
151 RpcServerInterface* cif = NULL;
152 RPC_STATUS status;
153
154 if (check_object)
155 MgrType = LookupObjType(object);
156 EnterCriticalSection(&server_cs);
157 cif = ifs;
158 while (cif) {
159 if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
160 (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
161 std_listen) break;
162 cif = cif->Next;
163 }
164 LeaveCriticalSection(&server_cs);
165 TRACE("returning %p for %s\n", cif, debugstr_guid(object));
166 return cif;
167 }
168
169 static void RPCRT4_push_packet(RpcPacket* packet)
170 {
171 packet->next = NULL;
172 EnterCriticalSection(&spacket_cs);
173 if (spacket_tail) {
174 spacket_tail->next = packet;
175 spacket_tail = packet;
176 } else {
177 spacket_head = packet;
178 spacket_tail = packet;
179 }
180 LeaveCriticalSection(&spacket_cs);
181 }
182
183 static RpcPacket* RPCRT4_pop_packet(void)
184 {
185 RpcPacket* packet;
186 EnterCriticalSection(&spacket_cs);
187 packet = spacket_head;
188 if (packet) {
189 spacket_head = packet->next;
190 if (!spacket_head) spacket_tail = NULL;
191 }
192 LeaveCriticalSection(&spacket_cs);
193 if (packet) packet->next = NULL;
194 return packet;
195 }
196
197 #ifndef __REACTOS__
198 typedef struct {
199 PRPC_MESSAGE msg;
200 void* buf;
201 } packet_state;
202
203 static WINE_EXCEPTION_FILTER(rpc_filter)
204 {
205 packet_state* state;
206 PRPC_MESSAGE msg;
207 state = TlsGetValue(worker_tls);
208 msg = state->msg;
209 if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg);
210 msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
211 msg->BufferLength = sizeof(DWORD);
212 I_RpcGetBuffer(msg);
213 *(DWORD*)msg->Buffer = GetExceptionCode();
214 WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer);
215 TRACE("returning failure packet\n");
216 return EXCEPTION_EXECUTE_HANDLER;
217 }
218 #endif
219
220 static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg)
221 {
222 RpcServerInterface* sif;
223 RPC_DISPATCH_FUNCTION func;
224 #ifndef __REACTOS__
225 packet_state state;
226 #endif
227 UUID *object_uuid;
228 RpcPktHdr *response;
229 void *buf = msg->Buffer;
230 RPC_STATUS status;
231
232 #ifndef __REACTOS__
233 state.msg = msg;
234 state.buf = buf;
235 TlsSetValue(worker_tls, &state);
236 #endif
237
238 switch (hdr->common.ptype) {
239 case PKT_BIND:
240 TRACE("got bind packet\n");
241
242 /* FIXME: do more checks! */
243 if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||
244 !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
245 TRACE("packet size less than min size, or active interface syntax guid non-null\n");
246 sif = NULL;
247 } else {
248 sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);
249 }
250 if (sif == NULL) {
251 TRACE("rejecting bind request on connection %p\n", conn);
252 /* Report failure to client. */
253 response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
254 RPC_VER_MAJOR, RPC_VER_MINOR);
255 } else {
256 TRACE("accepting bind request on connection %p\n", conn);
257
258 /* accept. */
259 response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
260 RPC_MAX_PACKET_SIZE,
261 RPC_MAX_PACKET_SIZE,
262 conn->Endpoint,
263 RESULT_ACCEPT, NO_REASON,
264 &sif->If->TransferSyntax);
265
266 /* save the interface for later use */
267 conn->ActiveInterface = hdr->bind.abstract;
268 conn->MaxTransmissionSize = hdr->bind.max_tsize;
269 }
270
271 if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK)
272 goto fail;
273
274 break;
275
276 case PKT_REQUEST:
277 TRACE("got request packet\n");
278
279 /* fail if the connection isn't bound with an interface */
280 if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
281 response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
282 status);
283
284 RPCRT4_Send(conn, response, NULL, 0);
285 break;
286 }
287
288 if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
289 object_uuid = (UUID*)(&hdr->request + 1);
290 } else {
291 object_uuid = NULL;
292 }
293
294 sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE);
295 msg->RpcInterfaceInformation = sif->If;
296 /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
297 msg->ManagerEpv = sif->MgrEpv;
298 if (object_uuid != NULL) {
299 RPCRT4_SetBindingObject(msg->Handle, object_uuid);
300 }
301
302 /* find dispatch function */
303 msg->ProcNum = hdr->request.opnum;
304 if (sif->Flags & RPC_IF_OLE) {
305 /* native ole32 always gives us a dispatch table with a single entry
306 * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
307 func = *sif->If->DispatchTable->DispatchTable;
308 } else {
309 if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
310 ERR("invalid procnum\n");
311 func = NULL;
312 }
313 func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
314 }
315
316 /* put in the drep. FIXME: is this more universally applicable?
317 perhaps we should move this outward... */
318 msg->DataRepresentation =
319 MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
320 MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));
321
322 /* dispatch */
323 #ifndef __REACTOS__
324 __TRY {
325 if (func) func(msg);
326 } __EXCEPT(rpc_filter) {
327 /* failure packet was created in rpc_filter */
328 } __ENDTRY
329 #else
330 if (func) func(msg);
331 #endif
332
333 /* send response packet */
334 I_RpcSend(msg);
335
336 msg->RpcInterfaceInformation = NULL;
337
338 break;
339
340 default:
341 FIXME("unhandled packet type\n");
342 break;
343 }
344
345 fail:
346 /* clean up */
347 if (msg->Buffer == buf) msg->Buffer = NULL;
348 TRACE("freeing Buffer=%p\n", buf);
349 HeapFree(GetProcessHeap(), 0, buf);
350 RPCRT4_DestroyBinding(msg->Handle);
351 msg->Handle = 0;
352 I_RpcFreeBuffer(msg);
353 msg->Buffer = NULL;
354 RPCRT4_FreeHeader(hdr);
355 #ifndef __REACTOS__
356 TlsSetValue(worker_tls, NULL);
357 #endif
358 }
359
360 static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
361 {
362 DWORD obj;
363 RpcPacket* pkt;
364
365 for (;;) {
366 /* idle timeout after 5s */
367 obj = WaitForSingleObject(server_sem, 5000);
368 if (obj == WAIT_TIMEOUT) {
369 /* if another idle thread exist, self-destruct */
370 if (worker_free > 1) break;
371 continue;
372 }
373 pkt = RPCRT4_pop_packet();
374 if (!pkt) continue;
375 InterlockedDecrement(&worker_free);
376 for (;;) {
377 RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg);
378 HeapFree(GetProcessHeap(), 0, pkt);
379 /* try to grab another packet here without waiting
380 * on the semaphore, in case it hits max */
381 pkt = RPCRT4_pop_packet();
382 if (!pkt) break;
383 /* decrement semaphore */
384 WaitForSingleObject(server_sem, 0);
385 }
386 InterlockedIncrement(&worker_free);
387 }
388 InterlockedDecrement(&worker_free);
389 InterlockedDecrement(&worker_count);
390 return 0;
391 }
392
393 static void RPCRT4_create_worker_if_needed(void)
394 {
395 if (!worker_free && worker_count < MAX_THREADS) {
396 HANDLE thread;
397 InterlockedIncrement(&worker_count);
398 InterlockedIncrement(&worker_free);
399 thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL);
400 if (thread) CloseHandle(thread);
401 else {
402 InterlockedDecrement(&worker_free);
403 InterlockedDecrement(&worker_count);
404 }
405 }
406 }
407
408 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
409 {
410 RpcConnection* conn = (RpcConnection*)the_arg;
411 RpcPktHdr *hdr;
412 RpcBinding *pbind;
413 RPC_MESSAGE *msg;
414 RPC_STATUS status;
415 RpcPacket *packet;
416
417 TRACE("(%p)\n", conn);
418
419 for (;;) {
420 msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
421
422 /* create temporary binding for dispatch, it will be freed in
423 * RPCRT4_process_packet */
424 RPCRT4_MakeBinding(&pbind, conn);
425 msg->Handle = (RPC_BINDING_HANDLE)pbind;
426
427 status = RPCRT4_Receive(conn, &hdr, msg);
428 if (status != RPC_S_OK) {
429 WARN("receive failed with error %lx\n", status);
430 break;
431 }
432
433 #if 0
434 RPCRT4_process_packet(conn, hdr, msg);
435 #else
436 packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
437 packet->conn = conn;
438 packet->hdr = hdr;
439 packet->msg = msg;
440 RPCRT4_create_worker_if_needed();
441 RPCRT4_push_packet(packet);
442 ReleaseSemaphore(server_sem, 1, NULL);
443 #endif
444 msg = NULL;
445 }
446 HeapFree(GetProcessHeap(), 0, msg);
447 RPCRT4_DestroyConnection(conn);
448 return 0;
449 }
450
451 static void RPCRT4_new_client(RpcConnection* conn)
452 {
453 HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
454 if (!thread) {
455 DWORD err = GetLastError();
456 ERR("failed to create thread, error=%08lx\n", err);
457 RPCRT4_DestroyConnection(conn);
458 }
459 /* we could set conn->thread, but then we'd have to make the io_thread wait
460 * for that, otherwise the thread might finish, destroy the connection, and
461 * free the memory we'd write to before we did, causing crashes and stuff -
462 * so let's implement that later, when we really need conn->thread */
463
464 CloseHandle( thread );
465 }
466
467 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
468 {
469 HANDLE m_event = mgr_event, b_handle;
470 HANDLE *objs = NULL;
471 DWORD count, res;
472 RpcServerProtseq* cps;
473 RpcConnection* conn;
474 RpcConnection* cconn;
475 BOOL set_ready_event = FALSE;
476
477 TRACE("(the_arg == ^%p)\n", the_arg);
478
479 for (;;) {
480 EnterCriticalSection(&server_cs);
481 /* open and count connections */
482 count = 1;
483 cps = protseqs;
484 while (cps) {
485 conn = cps->conn;
486 while (conn) {
487 RPCRT4_OpenConnection(conn);
488 if (conn->ovl[0].hEvent) count++;
489 conn = conn->Next;
490 }
491 cps = cps->Next;
492 }
493 /* make array of connections */
494 if (objs)
495 objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
496 else
497 objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE));
498
499 objs[0] = m_event;
500 count = 1;
501 cps = protseqs;
502 while (cps) {
503 conn = cps->conn;
504 while (conn) {
505 if (conn->ovl[0].hEvent) objs[count++] = conn->ovl[0].hEvent;
506 conn = conn->Next;
507 }
508 cps = cps->Next;
509 }
510 LeaveCriticalSection(&server_cs);
511
512 if (set_ready_event)
513 {
514 /* signal to function that changed state that we are now sync'ed */
515 SetEvent(server_ready_event);
516 set_ready_event = FALSE;
517 }
518
519 /* start waiting */
520 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
521 if (res == WAIT_OBJECT_0) {
522 if (!std_listen)
523 {
524 SetEvent(server_ready_event);
525 break;
526 }
527 set_ready_event = TRUE;
528 }
529 else if (res == WAIT_FAILED) {
530 ERR("wait failed\n");
531 }
532 else {
533 b_handle = objs[res - WAIT_OBJECT_0];
534 /* find which connection got a RPC */
535 EnterCriticalSection(&server_cs);
536 conn = NULL;
537 cps = protseqs;
538 while (cps) {
539 conn = cps->conn;
540 while (conn) {
541 if (conn->ovl[0].hEvent == b_handle) break;
542 conn = conn->Next;
543 }
544 if (conn) break;
545 cps = cps->Next;
546 }
547 cconn = NULL;
548 if (conn) RPCRT4_SpawnConnection(&cconn, conn);
549 LeaveCriticalSection(&server_cs);
550 if (!conn) {
551 ERR("failed to locate connection for handle %p\n", b_handle);
552 }
553 if (cconn) RPCRT4_new_client(cconn);
554 }
555 }
556 HeapFree(GetProcessHeap(), 0, objs);
557 EnterCriticalSection(&server_cs);
558 /* close connections */
559 cps = protseqs;
560 while (cps) {
561 conn = cps->conn;
562 while (conn) {
563 RPCRT4_CloseConnection(conn);
564 conn = conn->Next;
565 }
566 cps = cps->Next;
567 }
568 LeaveCriticalSection(&server_cs);
569 return 0;
570 }
571
572 /* tells the server thread that the state has changed and waits for it to
573 * make the changes */
574 static void RPCRT4_sync_with_server_thread(void)
575 {
576 /* make sure we are the only thread sync'ing the server state, otherwise
577 * there is a race with the server thread setting an older state and setting
578 * the server_ready_event when the new state hasn't yet been applied */
579 WaitForSingleObject(mgr_mutex, INFINITE);
580
581 SetEvent(mgr_event);
582 /* wait for server thread to make the requested changes before returning */
583 WaitForSingleObject(server_ready_event, INFINITE);
584
585 ReleaseMutex(mgr_mutex);
586 }
587
588 static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
589 {
590 RPC_STATUS status = RPC_S_ALREADY_LISTENING;
591
592 TRACE("\n");
593
594 EnterCriticalSection(&listen_cs);
595 if (auto_listen || (manual_listen_count++ == 0))
596 {
597 status = RPC_S_OK;
598 if (++listen_count == 1) {
599 HANDLE server_thread;
600 /* first listener creates server thread */
601 if (!mgr_mutex) mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
602 if (!mgr_event) mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
603 if (!server_ready_event) server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
604 if (!server_sem) server_sem = CreateSemaphoreW(NULL, 0, MAX_THREADS, NULL);
605 if (!worker_tls) worker_tls = TlsAlloc();
606 std_listen = TRUE;
607 server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
608 CloseHandle(server_thread);
609 }
610 }
611 LeaveCriticalSection(&listen_cs);
612
613 return status;
614 }
615
616 static void RPCRT4_stop_listen(BOOL auto_listen)
617 {
618 EnterCriticalSection(&listen_cs);
619 if (auto_listen || (--manual_listen_count == 0))
620 {
621 if (listen_count != 0 && --listen_count == 0) {
622 std_listen = FALSE;
623 LeaveCriticalSection(&listen_cs);
624 RPCRT4_sync_with_server_thread();
625 return;
626 }
627 assert(listen_count >= 0);
628 }
629 LeaveCriticalSection(&listen_cs);
630 }
631
632 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
633 {
634 RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);
635
636 EnterCriticalSection(&server_cs);
637 ps->Next = protseqs;
638 protseqs = ps;
639 LeaveCriticalSection(&server_cs);
640
641 if (std_listen) RPCRT4_sync_with_server_thread();
642
643 return RPC_S_OK;
644 }
645
646 /***********************************************************************
647 * RpcServerInqBindings (RPCRT4.@)
648 */
649 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
650 {
651 RPC_STATUS status;
652 DWORD count;
653 RpcServerProtseq* ps;
654 RpcConnection* conn;
655
656 if (BindingVector)
657 TRACE("(*BindingVector == ^%p)\n", *BindingVector);
658 else
659 ERR("(BindingVector == NULL!!?)\n");
660
661 EnterCriticalSection(&server_cs);
662 /* count connections */
663 count = 0;
664 ps = protseqs;
665 while (ps) {
666 conn = ps->conn;
667 while (conn) {
668 count++;
669 conn = conn->Next;
670 }
671 ps = ps->Next;
672 }
673 if (count) {
674 /* export bindings */
675 *BindingVector = HeapAlloc(GetProcessHeap(), 0,
676 sizeof(RPC_BINDING_VECTOR) +
677 sizeof(RPC_BINDING_HANDLE)*(count-1));
678 (*BindingVector)->Count = count;
679 count = 0;
680 ps = protseqs;
681 while (ps) {
682 conn = ps->conn;
683 while (conn) {
684 RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
685 conn);
686 count++;
687 conn = conn->Next;
688 }
689 ps = ps->Next;
690 }
691 status = RPC_S_OK;
692 } else {
693 *BindingVector = NULL;
694 status = RPC_S_NO_BINDINGS;
695 }
696 LeaveCriticalSection(&server_cs);
697 return status;
698 }
699
700 /***********************************************************************
701 * RpcServerUseProtseqEpA (RPCRT4.@)
702 */
703 RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor )
704 {
705 RPC_POLICY policy;
706
707 TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
708
709 /* This should provide the default behaviour */
710 policy.Length = sizeof( policy );
711 policy.EndpointFlags = 0;
712 policy.NICFlags = 0;
713
714 return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
715 }
716
717 /***********************************************************************
718 * RpcServerUseProtseqEpW (RPCRT4.@)
719 */
720 RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
721 {
722 RPC_POLICY policy;
723
724 TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
725
726 /* This should provide the default behaviour */
727 policy.Length = sizeof( policy );
728 policy.EndpointFlags = 0;
729 policy.NICFlags = 0;
730
731 return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
732 }
733
734 /***********************************************************************
735 * RpcServerUseProtseqEpExA (RPCRT4.@)
736 */
737 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor,
738 PRPC_POLICY lpPolicy )
739 {
740 RpcServerProtseq* ps;
741
742 TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( (char*)Protseq ), MaxCalls,
743 debugstr_a( (char*)Endpoint ), SecurityDescriptor,
744 lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
745
746 ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
747 ps->MaxCalls = MaxCalls;
748 ps->Protseq = RPCRT4_strdupA((char*)Protseq);
749 ps->Endpoint = RPCRT4_strdupA((char*)Endpoint);
750
751 return RPCRT4_use_protseq(ps);
752 }
753
754 /***********************************************************************
755 * RpcServerUseProtseqEpExW (RPCRT4.@)
756 */
757 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
758 PRPC_POLICY lpPolicy )
759 {
760 RpcServerProtseq* ps;
761
762 TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls,
763 debugstr_w( Endpoint ), SecurityDescriptor,
764 lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
765
766 ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
767 ps->MaxCalls = MaxCalls;
768 ps->Protseq = RPCRT4_strdupWtoA(Protseq);
769 ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);
770
771 return RPCRT4_use_protseq(ps);
772 }
773
774 /***********************************************************************
775 * RpcServerUseProtseqA (RPCRT4.@)
776 */
777 RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
778 {
779 TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor);
780 return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor);
781 }
782
783 /***********************************************************************
784 * RpcServerUseProtseqW (RPCRT4.@)
785 */
786 RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
787 {
788 TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
789 return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor);
790 }
791
792 /***********************************************************************
793 * RpcServerRegisterIf (RPCRT4.@)
794 */
795 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
796 {
797 TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
798 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
799 }
800
801 /***********************************************************************
802 * RpcServerRegisterIfEx (RPCRT4.@)
803 */
804 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
805 UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
806 {
807 TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
808 return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
809 }
810
811 /***********************************************************************
812 * RpcServerRegisterIf2 (RPCRT4.@)
813 */
814 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
815 UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
816 {
817 PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
818 RpcServerInterface* sif;
819 unsigned int i;
820
821 TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
822 MaxRpcSize, IfCallbackFn);
823 TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
824 If->InterfaceId.SyntaxVersion.MajorVersion,
825 If->InterfaceId.SyntaxVersion.MinorVersion);
826 TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
827 If->TransferSyntax.SyntaxVersion.MajorVersion,
828 If->TransferSyntax.SyntaxVersion.MinorVersion);
829 TRACE(" dispatch table: %p\n", If->DispatchTable);
830 if (If->DispatchTable) {
831 TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
832 for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
833 TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
834 }
835 TRACE(" reserved: %ld\n", If->DispatchTable->Reserved);
836 }
837 TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
838 TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
839 TRACE(" interpreter info: %p\n", If->InterpreterInfo);
840
841 sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
842 sif->If = If;
843 if (MgrTypeUuid) {
844 memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
845 sif->MgrEpv = MgrEpv;
846 } else {
847 memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
848 sif->MgrEpv = If->DefaultManagerEpv;
849 }
850 sif->Flags = Flags;
851 sif->MaxCalls = MaxCalls;
852 sif->MaxRpcSize = MaxRpcSize;
853 sif->IfCallbackFn = IfCallbackFn;
854
855 EnterCriticalSection(&server_cs);
856 sif->Next = ifs;
857 ifs = sif;
858 LeaveCriticalSection(&server_cs);
859
860 if (sif->Flags & RPC_IF_AUTOLISTEN) {
861 RPCRT4_start_listen(TRUE);
862
863 /* make sure server is actually listening on the interface before
864 * returning */
865 RPCRT4_sync_with_server_thread();
866 }
867
868 return RPC_S_OK;
869 }
870
871 /***********************************************************************
872 * RpcServerUnregisterIf (RPCRT4.@)
873 */
874 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
875 {
876 FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n",
877 IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
878
879 return RPC_S_OK;
880 }
881
882 /***********************************************************************
883 * RpcServerUnregisterIfEx (RPCRT4.@)
884 */
885 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
886 {
887 FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
888 IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
889
890 return RPC_S_OK;
891 }
892
893 /***********************************************************************
894 * RpcObjectSetType (RPCRT4.@)
895 *
896 * PARAMS
897 * ObjUuid [I] "Object" UUID
898 * TypeUuid [I] "Type" UUID
899 *
900 * RETURNS
901 * RPC_S_OK The call succeeded
902 * RPC_S_INVALID_OBJECT The provided object (nil) is not valid
903 * RPC_S_ALREADY_REGISTERED The provided object is already registered
904 *
905 * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type
906 * resets the mapping for the specified object UUID to nil (the default).
907 * The nil object is always associated with the nil type and cannot be
908 * reassigned. Servers can support multiple implementations on the same
909 * interface by registering different end-point vectors for the different
910 * types. There's no need to call this if a server only supports the nil
911 * type, as is typical.
912 */
913 RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
914 {
915 RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
916 RPC_STATUS dummy;
917
918 TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
919 if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
920 /* nil uuid cannot be remapped */
921 return RPC_S_INVALID_OBJECT;
922 }
923
924 /* find the mapping for this object if there is one ... */
925 while (map) {
926 if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
927 prev = map;
928 map = map->next;
929 }
930 if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
931 /* ... and drop it from the list */
932 if (map) {
933 if (prev)
934 prev->next = map->next;
935 else
936 RpcObjTypeMaps = map->next;
937 HeapFree(GetProcessHeap(), 0, map);
938 }
939 } else {
940 /* ... , fail if we found it ... */
941 if (map)
942 return RPC_S_ALREADY_REGISTERED;
943 /* ... otherwise create a new one and add it in. */
944 map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
945 memcpy(&map->Object, ObjUuid, sizeof(UUID));
946 memcpy(&map->Type, TypeUuid, sizeof(UUID));
947 map->next = NULL;
948 if (prev)
949 prev->next = map; /* prev is the last map in the linklist */
950 else
951 RpcObjTypeMaps = map;
952 }
953
954 return RPC_S_OK;
955 }
956
957 /***********************************************************************
958 * RpcServerRegisterAuthInfoA (RPCRT4.@)
959 */
960 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
961 LPVOID Arg )
962 {
963 FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
964
965 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
966 }
967
968 /***********************************************************************
969 * RpcServerRegisterAuthInfoW (RPCRT4.@)
970 */
971 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
972 LPVOID Arg )
973 {
974 FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
975
976 return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
977 }
978
979 /***********************************************************************
980 * RpcServerListen (RPCRT4.@)
981 */
982 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
983 {
984 RPC_STATUS status;
985
986 TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
987
988 if (!protseqs)
989 return RPC_S_NO_PROTSEQS_REGISTERED;
990
991 status = RPCRT4_start_listen(FALSE);
992
993 if (DontWait || (status != RPC_S_OK)) return status;
994
995 return RpcMgmtWaitServerListen();
996 }
997
998 /***********************************************************************
999 * RpcMgmtServerWaitListen (RPCRT4.@)
1000 */
1001 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
1002 {
1003 TRACE("()\n");
1004
1005 EnterCriticalSection(&listen_cs);
1006
1007 if (!std_listen) {
1008 LeaveCriticalSection(&listen_cs);
1009 return RPC_S_NOT_LISTENING;
1010 }
1011
1012 LeaveCriticalSection(&listen_cs);
1013
1014 RPCRT4_sync_with_server_thread();
1015
1016 return RPC_S_OK;
1017 }
1018
1019 /***********************************************************************
1020 * RpcMgmtStopServerListening (RPCRT4.@)
1021 */
1022 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
1023 {
1024 TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
1025
1026 if (Binding) {
1027 FIXME("client-side invocation not implemented.\n");
1028 return RPC_S_WRONG_KIND_OF_BINDING;
1029 }
1030
1031 RPCRT4_stop_listen(FALSE);
1032
1033 return RPC_S_OK;
1034 }
1035
1036 /***********************************************************************
1037 * I_RpcServerStartListening (RPCRT4.@)
1038 */
1039 RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
1040 {
1041 FIXME( "(%p): stub\n", hWnd );
1042
1043 return RPC_S_OK;
1044 }
1045
1046 /***********************************************************************
1047 * I_RpcServerStopListening (RPCRT4.@)
1048 */
1049 RPC_STATUS WINAPI I_RpcServerStopListening( void )
1050 {
1051 FIXME( "(): stub\n" );
1052
1053 return RPC_S_OK;
1054 }
1055
1056 /***********************************************************************
1057 * I_RpcWindowProc (RPCRT4.@)
1058 */
1059 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1060 {
1061 FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
1062
1063 return 0;
1064 }