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