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