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