ole32: Remove an unnecessary special case in StorageBaseImpl_CopyTo.
[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  * Copyright 2006-2008 Robert Shearman (for CodeWeavers)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34
35 #include "rpc.h"
36 #include "rpcndr.h"
37 #include "excpt.h"
38
39 #include "wine/debug.h"
40 #include "wine/exception.h"
41
42 #include "rpc_server.h"
43 #include "rpc_assoc.h"
44 #include "rpc_message.h"
45 #include "rpc_defs.h"
46 #include "ncastatus.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
49
50 typedef struct _RpcPacket
51 {
52   struct _RpcConnection* conn;
53   RpcPktHdr* hdr;
54   RPC_MESSAGE* msg;
55 } RpcPacket;
56
57 typedef struct _RpcObjTypeMap
58 {
59   /* FIXME: a hash table would be better. */
60   struct _RpcObjTypeMap *next;
61   UUID Object;
62   UUID Type;
63 } RpcObjTypeMap;
64
65 static RpcObjTypeMap *RpcObjTypeMaps;
66
67 /* list of type RpcServerProtseq */
68 static struct list protseqs = LIST_INIT(protseqs);
69 static struct list server_interfaces = LIST_INIT(server_interfaces);
70
71 static CRITICAL_SECTION server_cs;
72 static CRITICAL_SECTION_DEBUG server_cs_debug =
73 {
74     0, 0, &server_cs,
75     { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
76       0, 0, { (DWORD_PTR)(__FILE__ ": server_cs") }
77 };
78 static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
79
80 static CRITICAL_SECTION listen_cs;
81 static CRITICAL_SECTION_DEBUG listen_cs_debug =
82 {
83     0, 0, &listen_cs,
84     { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
85       0, 0, { (DWORD_PTR)(__FILE__ ": listen_cs") }
86 };
87 static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
88
89 /* whether the server is currently listening */
90 static BOOL std_listen;
91 /* number of manual listeners (calls to RpcServerListen) */
92 static LONG manual_listen_count;
93 /* total listeners including auto listeners */
94 static LONG listen_count;
95
96 static UUID uuid_nil;
97
98 static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
99 {
100   RpcObjTypeMap *rslt = RpcObjTypeMaps;
101   RPC_STATUS dummy;
102
103   while (rslt) {
104     if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
105     rslt = rslt->next;
106   }
107
108   return rslt;
109 }
110
111 static inline UUID *LookupObjType(UUID *ObjUuid)
112 {
113   RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
114   if (map)
115     return &map->Type;
116   else
117     return &uuid_nil;
118 }
119
120 static RpcServerInterface* RPCRT4_find_interface(UUID* object,
121                                                  const RPC_SYNTAX_IDENTIFIER *if_id,
122                                                  const RPC_SYNTAX_IDENTIFIER *transfer_syntax,
123                                                  BOOL check_object)
124 {
125   UUID* MgrType = NULL;
126   RpcServerInterface* cif;
127   RPC_STATUS status;
128
129   if (check_object)
130     MgrType = LookupObjType(object);
131   EnterCriticalSection(&server_cs);
132   LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
133     if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
134         (!transfer_syntax || !memcmp(transfer_syntax, &cif->If->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
135         (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
136         std_listen) {
137       InterlockedIncrement(&cif->CurrentCalls);
138       break;
139     }
140   }
141   LeaveCriticalSection(&server_cs);
142   if (&cif->entry == &server_interfaces) cif = NULL;
143   TRACE("returning %p for object %s, if_id { %d.%d %s }\n", cif,
144     debugstr_guid(object), if_id->SyntaxVersion.MajorVersion,
145     if_id->SyntaxVersion.MinorVersion, debugstr_guid(&if_id->SyntaxGUID));
146   return cif;
147 }
148
149 static void RPCRT4_release_server_interface(RpcServerInterface *sif)
150 {
151   if (!InterlockedDecrement(&sif->CurrentCalls) &&
152       sif->Delete) {
153     /* sif must have been removed from server_interfaces before
154      * CallsCompletedEvent is set */
155     if (sif->CallsCompletedEvent)
156       SetEvent(sif->CallsCompletedEvent);
157     HeapFree(GetProcessHeap(), 0, sif);
158   }
159 }
160
161 static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg)
162 {
163   RPC_STATUS status;
164   RpcPktHdr *response;
165   RpcContextElement *ctxt_elem;
166   unsigned int i;
167
168   for (i = 0, ctxt_elem = msg->Buffer;
169        i < hdr->num_elements;
170        i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
171   {
172       if (((char *)ctxt_elem - (char *)msg->Buffer) > msg->BufferLength ||
173           ((char *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes] - (char *)msg->Buffer) > msg->BufferLength)
174       {
175           ERR("inconsistent data in packet - packet length %d, num elements %d\n",
176               msg->BufferLength, hdr->num_elements);
177           /* Report failure to client. */
178           response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
179                                                 RPC_VER_MAJOR, RPC_VER_MINOR,
180                                                 REJECT_REASON_NOT_SPECIFIED);
181           goto send;
182       }
183   }
184
185   if (hdr->max_tsize < RPC_MIN_PACKET_SIZE ||
186       !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
187       conn->server_binding)
188   {
189     TRACE("packet size less than min size, or active interface syntax guid non-null\n");
190
191     /* Report failure to client. */
192     response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
193                                           RPC_VER_MAJOR, RPC_VER_MINOR,
194                                           REJECT_REASON_NOT_SPECIFIED);
195   }
196   else
197   {
198     RpcResult *results = HeapAlloc(GetProcessHeap(), 0,
199                                    hdr->num_elements * sizeof(*results));
200     if (!results)
201     {
202         /* Report failure to client. */
203         response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
204                                               RPC_VER_MAJOR, RPC_VER_MINOR,
205                                               REJECT_LOCAL_LIMIT_EXCEEDED);
206         goto send;
207     }
208
209     for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer;
210          i < hdr->num_elements;
211          i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
212     {
213         RpcServerInterface* sif = NULL;
214         unsigned int j;
215
216         for (j = 0; !sif && j < ctxt_elem->num_syntaxes; j++)
217         {
218             sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
219                                         &ctxt_elem->transfer_syntaxes[j], FALSE);
220             if (sif)
221                 break;
222         }
223
224         if (sif)
225         {
226             RPCRT4_release_server_interface(sif);
227             TRACE("accepting bind request on connection %p for %s\n", conn,
228                   debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
229             results[i].result = RESULT_ACCEPT;
230             results[i].reason = REASON_NONE;
231             results[i].transfer_syntax = ctxt_elem->transfer_syntaxes[j];
232
233             /* save the interface for later use */
234             /* FIXME: save linked list */
235             conn->ActiveInterface = ctxt_elem->abstract_syntax;
236         }
237         else if ((sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
238                                               NULL, FALSE)) != NULL)
239         {
240             RPCRT4_release_server_interface(sif);
241             TRACE("not accepting bind request on connection %p for %s - no transfer syntaxes supported\n",
242                   conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
243             results[i].result = RESULT_PROVIDER_REJECTION;
244             results[i].reason = REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED;
245             memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
246         }
247         else
248         {
249             TRACE("not accepting bind request on connection %p for %s - abstract syntax not supported\n",
250                   conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
251             results[i].result = RESULT_PROVIDER_REJECTION;
252             results[i].reason = REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
253             memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
254         }
255     }
256
257     /* create temporary binding */
258     if (RPCRT4_MakeBinding(&conn->server_binding, conn) == RPC_S_OK &&
259         RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn),
260                                       conn->NetworkAddr, conn->Endpoint,
261                                       conn->NetworkOptions,
262                                       hdr->assoc_gid,
263                                       &conn->server_binding->Assoc) == RPC_S_OK)
264     {
265         response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
266                                              RPC_MAX_PACKET_SIZE,
267                                              RPC_MAX_PACKET_SIZE,
268                                              conn->server_binding->Assoc->assoc_group_id,
269                                              conn->Endpoint, hdr->num_elements,
270                                              results);
271
272         conn->MaxTransmissionSize = hdr->max_tsize;
273     }
274     else
275     {
276         /* Report failure to client. */
277         response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
278                                               RPC_VER_MAJOR, RPC_VER_MINOR,
279                                               REJECT_LOCAL_LIMIT_EXCEEDED);
280     }
281     HeapFree(GetProcessHeap(), 0, results);
282   }
283
284 send:
285   if (response)
286     status = RPCRT4_Send(conn, response, NULL, 0);
287   else
288     status = ERROR_OUTOFMEMORY;
289   RPCRT4_FreeHeader(response);
290
291   return status;
292 }
293
294 static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg)
295 {
296   RPC_STATUS status;
297   RpcPktHdr *response = NULL;
298   RpcServerInterface* sif;
299   RPC_DISPATCH_FUNCTION func;
300   BOOL exception;
301   UUID *object_uuid;
302   NDR_SCONTEXT context_handle;
303   void *buf = msg->Buffer;
304
305   /* fail if the connection isn't bound with an interface */
306   if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
307     /* FIXME: should send BindNack instead */
308     response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
309                                        status);
310
311     RPCRT4_Send(conn, response, NULL, 0);
312     RPCRT4_FreeHeader(response);
313     return RPC_S_OK;
314   }
315
316   if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
317     object_uuid = (UUID*)(hdr + 1);
318   } else {
319     object_uuid = NULL;
320   }
321
322   sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, NULL, TRUE);
323   if (!sif) {
324     WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID));
325     response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
326                                        NCA_S_UNK_IF);
327
328     RPCRT4_Send(conn, response, NULL, 0);
329     RPCRT4_FreeHeader(response);
330     return RPC_S_OK;
331   }
332   msg->RpcInterfaceInformation = sif->If;
333   /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
334   msg->ManagerEpv = sif->MgrEpv;
335   if (object_uuid != NULL) {
336     RPCRT4_SetBindingObject(msg->Handle, object_uuid);
337   }
338
339   /* find dispatch function */
340   msg->ProcNum = hdr->opnum;
341   if (sif->Flags & RPC_IF_OLE) {
342     /* native ole32 always gives us a dispatch table with a single entry
343     * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
344     func = *sif->If->DispatchTable->DispatchTable;
345   } else {
346     if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
347       WARN("invalid procnum (%d/%d)\n", msg->ProcNum, sif->If->DispatchTable->DispatchTableCount);
348       response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
349                                          NCA_S_OP_RNG_ERROR);
350
351       RPCRT4_Send(conn, response, NULL, 0);
352       RPCRT4_FreeHeader(response);
353     }
354     func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
355   }
356
357   /* put in the drep. FIXME: is this more universally applicable?
358     perhaps we should move this outward... */
359   msg->DataRepresentation =
360     MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
361               MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));
362
363   exception = FALSE;
364
365   /* dispatch */
366   RPCRT4_SetThreadCurrentCallHandle(msg->Handle);
367   __TRY {
368     if (func) func(msg);
369   } __EXCEPT_ALL {
370     WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode());
371     exception = TRUE;
372     if (GetExceptionCode() == STATUS_ACCESS_VIOLATION)
373       status = ERROR_NOACCESS;
374     else
375       status = GetExceptionCode();
376     response = RPCRT4_BuildFaultHeader(msg->DataRepresentation,
377                                        RPC2NCA_STATUS(status));
378   } __ENDTRY
379     RPCRT4_SetThreadCurrentCallHandle(NULL);
380
381   /* release any unmarshalled context handles */
382   while ((context_handle = RPCRT4_PopThreadContextHandle()) != NULL)
383     RpcServerAssoc_ReleaseContextHandle(conn->server_binding->Assoc, context_handle, TRUE);
384
385   if (!exception)
386     response = RPCRT4_BuildResponseHeader(msg->DataRepresentation,
387                                           msg->BufferLength);
388
389   /* send response packet */
390   if (response) {
391     status = RPCRT4_Send(conn, response, exception ? NULL : msg->Buffer,
392                          exception ? 0 : msg->BufferLength);
393     RPCRT4_FreeHeader(response);
394   } else
395     ERR("out of memory\n");
396
397   msg->RpcInterfaceInformation = NULL;
398   RPCRT4_release_server_interface(sif);
399
400   if (msg->Buffer == buf) buf = NULL;
401   TRACE("freeing Buffer=%p\n", buf);
402   I_RpcFree(buf);
403
404   return status;
405 }
406
407 static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg)
408 {
409   RPC_STATUS status;
410
411   msg->Handle = (RPC_BINDING_HANDLE)conn->server_binding;
412
413   switch (hdr->common.ptype) {
414     case PKT_BIND:
415       TRACE("got bind packet\n");
416
417       status = process_bind_packet(conn, &hdr->bind, msg);
418       break;
419
420     case PKT_REQUEST:
421       TRACE("got request packet\n");
422
423       status = process_request_packet(conn, &hdr->request, msg);
424       break;
425
426     default:
427       FIXME("unhandled packet type %u\n", hdr->common.ptype);
428       break;
429   }
430
431   /* clean up */
432   I_RpcFree(msg->Buffer);
433   RPCRT4_FreeHeader(hdr);
434   HeapFree(GetProcessHeap(), 0, msg);
435 }
436
437 static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
438 {
439   RpcPacket *pkt = the_arg;
440   RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg);
441   HeapFree(GetProcessHeap(), 0, pkt);
442   return 0;
443 }
444
445 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
446 {
447   RpcConnection* conn = the_arg;
448   RpcPktHdr *hdr;
449   RPC_MESSAGE *msg;
450   RPC_STATUS status;
451   RpcPacket *packet;
452
453   TRACE("(%p)\n", conn);
454
455   for (;;) {
456     msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
457
458     status = RPCRT4_Receive(conn, &hdr, msg);
459     if (status != RPC_S_OK) {
460       WARN("receive failed with error %x\n", status);
461       HeapFree(GetProcessHeap(), 0, msg);
462       break;
463     }
464
465     packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
466     if (!packet) {
467       I_RpcFree(msg->Buffer);
468       RPCRT4_FreeHeader(hdr);
469       HeapFree(GetProcessHeap(), 0, msg);
470       break;
471     }
472     packet->conn = conn;
473     packet->hdr = hdr;
474     packet->msg = msg;
475     if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) {
476       ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError());
477       I_RpcFree(msg->Buffer);
478       RPCRT4_FreeHeader(hdr);
479       HeapFree(GetProcessHeap(), 0, msg);
480       HeapFree(GetProcessHeap(), 0, packet);
481       break;
482     }
483
484     msg = NULL;
485   }
486   RPCRT4_DestroyConnection(conn);
487   return 0;
488 }
489
490 void RPCRT4_new_client(RpcConnection* conn)
491 {
492   HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
493   if (!thread) {
494     DWORD err = GetLastError();
495     ERR("failed to create thread, error=%08x\n", err);
496     RPCRT4_DestroyConnection(conn);
497   }
498   /* we could set conn->thread, but then we'd have to make the io_thread wait
499    * for that, otherwise the thread might finish, destroy the connection, and
500    * free the memory we'd write to before we did, causing crashes and stuff -
501    * so let's implement that later, when we really need conn->thread */
502
503   CloseHandle( thread );
504 }
505
506 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
507 {
508   int res;
509   unsigned int count;
510   void *objs = NULL;
511   RpcServerProtseq* cps = the_arg;
512   RpcConnection* conn;
513   BOOL set_ready_event = FALSE;
514
515   TRACE("(the_arg == ^%p)\n", the_arg);
516
517   for (;;) {
518     objs = cps->ops->get_wait_array(cps, objs, &count);
519
520     if (set_ready_event)
521     {
522         /* signal to function that changed state that we are now sync'ed */
523         SetEvent(cps->server_ready_event);
524         set_ready_event = FALSE;
525     }
526
527     /* start waiting */
528     res = cps->ops->wait_for_new_connection(cps, count, objs);
529
530     if (res == -1 || (res == 0 && !std_listen))
531     {
532       /* cleanup */
533       cps->ops->free_wait_array(cps, objs);
534       EnterCriticalSection(&cps->cs);
535       for (conn = cps->conn; conn; conn = conn->Next)
536         RPCRT4_CloseConnection(conn);
537       LeaveCriticalSection(&cps->cs);
538
539       if (res == 0 && !std_listen)
540         SetEvent(cps->server_ready_event);
541       break;
542     }
543     else if (res == 0)
544       set_ready_event = TRUE;
545   }
546   return 0;
547 }
548
549 /* tells the server thread that the state has changed and waits for it to
550  * make the changes */
551 static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps)
552 {
553   /* make sure we are the only thread sync'ing the server state, otherwise
554    * there is a race with the server thread setting an older state and setting
555    * the server_ready_event when the new state hasn't yet been applied */
556   WaitForSingleObject(ps->mgr_mutex, INFINITE);
557
558   ps->ops->signal_state_changed(ps);
559
560   /* wait for server thread to make the requested changes before returning */
561   WaitForSingleObject(ps->server_ready_event, INFINITE);
562
563   ReleaseMutex(ps->mgr_mutex);
564 }
565
566 static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen)
567 {
568   RPC_STATUS status = RPC_S_OK;
569   HANDLE server_thread;
570
571   EnterCriticalSection(&listen_cs);
572   if (ps->is_listening) goto done;
573
574   if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
575   if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
576   server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL);
577   if (!server_thread)
578   {
579     status = RPC_S_OUT_OF_RESOURCES;
580     goto done;
581   }
582   ps->is_listening = TRUE;
583   CloseHandle(server_thread);
584
585 done:
586   LeaveCriticalSection(&listen_cs);
587   return status;
588 }
589
590 static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
591 {
592   RPC_STATUS status = RPC_S_ALREADY_LISTENING;
593   RpcServerProtseq *cps;
594
595   TRACE("\n");
596
597   EnterCriticalSection(&listen_cs);
598   if (auto_listen || (manual_listen_count++ == 0))
599   {
600     status = RPC_S_OK;
601     if (++listen_count == 1)
602       std_listen = TRUE;
603   }
604   LeaveCriticalSection(&listen_cs);
605
606   if (std_listen)
607   {
608     EnterCriticalSection(&server_cs);
609     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
610     {
611       status = RPCRT4_start_listen_protseq(cps, TRUE);
612       if (status != RPC_S_OK)
613         break;
614       
615       /* make sure server is actually listening on the interface before
616        * returning */
617       RPCRT4_sync_with_server_thread(cps);
618     }
619     LeaveCriticalSection(&server_cs);
620   }
621
622   return status;
623 }
624
625 static void RPCRT4_stop_listen(BOOL auto_listen)
626 {
627   EnterCriticalSection(&listen_cs);
628   if (auto_listen || (--manual_listen_count == 0))
629   {
630     if (listen_count != 0 && --listen_count == 0) {
631       RpcServerProtseq *cps;
632
633       std_listen = FALSE;
634       LeaveCriticalSection(&listen_cs);
635
636       LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
637         RPCRT4_sync_with_server_thread(cps);
638
639       return;
640     }
641     assert(listen_count >= 0);
642   }
643   LeaveCriticalSection(&listen_cs);
644 }
645
646 static BOOL RPCRT4_protseq_is_endpoint_registered(RpcServerProtseq *protseq, const char *endpoint)
647 {
648   RpcConnection *conn;
649   EnterCriticalSection(&protseq->cs);
650   for (conn = protseq->conn; conn; conn = conn->Next)
651   {
652     if (!endpoint || !strcmp(endpoint, conn->Endpoint))
653       break;
654   }
655   LeaveCriticalSection(&protseq->cs);
656   return (conn != NULL);
657 }
658
659 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, const char *endpoint)
660 {
661   RPC_STATUS status;
662
663   EnterCriticalSection(&ps->cs);
664
665   if (RPCRT4_protseq_is_endpoint_registered(ps, endpoint))
666     status = RPC_S_OK;
667   else
668     status = ps->ops->open_endpoint(ps, endpoint);
669
670   LeaveCriticalSection(&ps->cs);
671
672   if (status != RPC_S_OK)
673     return status;
674
675   if (std_listen)
676   {
677     status = RPCRT4_start_listen_protseq(ps, FALSE);
678     if (status == RPC_S_OK)
679       RPCRT4_sync_with_server_thread(ps);
680   }
681
682   return status;
683 }
684
685 /***********************************************************************
686  *             RpcServerInqBindings (RPCRT4.@)
687  */
688 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
689 {
690   RPC_STATUS status;
691   DWORD count;
692   RpcServerProtseq* ps;
693   RpcConnection* conn;
694
695   if (BindingVector)
696     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
697   else
698     ERR("(BindingVector == NULL!!?)\n");
699
700   EnterCriticalSection(&server_cs);
701   /* count connections */
702   count = 0;
703   LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
704     EnterCriticalSection(&ps->cs);
705     for (conn = ps->conn; conn; conn = conn->Next)
706       count++;
707     LeaveCriticalSection(&ps->cs);
708   }
709   if (count) {
710     /* export bindings */
711     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
712                               sizeof(RPC_BINDING_VECTOR) +
713                               sizeof(RPC_BINDING_HANDLE)*(count-1));
714     (*BindingVector)->Count = count;
715     count = 0;
716     LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
717       EnterCriticalSection(&ps->cs);
718       for (conn = ps->conn; conn; conn = conn->Next) {
719        RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
720                           conn);
721        count++;
722       }
723       LeaveCriticalSection(&ps->cs);
724     }
725     status = RPC_S_OK;
726   } else {
727     *BindingVector = NULL;
728     status = RPC_S_NO_BINDINGS;
729   }
730   LeaveCriticalSection(&server_cs);
731   return status;
732 }
733
734 /***********************************************************************
735  *             RpcServerUseProtseqEpA (RPCRT4.@)
736  */
737 RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor )
738 {
739   RPC_POLICY policy;
740   
741   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
742   
743   /* This should provide the default behaviour */
744   policy.Length        = sizeof( policy );
745   policy.EndpointFlags = 0;
746   policy.NICFlags      = 0;
747   
748   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
749 }
750
751 /***********************************************************************
752  *             RpcServerUseProtseqEpW (RPCRT4.@)
753  */
754 RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor )
755 {
756   RPC_POLICY policy;
757   
758   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
759   
760   /* This should provide the default behaviour */
761   policy.Length        = sizeof( policy );
762   policy.EndpointFlags = 0;
763   policy.NICFlags      = 0;
764   
765   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
766 }
767
768 /***********************************************************************
769  *             alloc_serverprotoseq (internal)
770  *
771  * Must be called with server_cs held.
772  */
773 static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
774 {
775   const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq);
776
777   if (!ops)
778   {
779     FIXME("protseq %s not supported\n", debugstr_a(Protseq));
780     return RPC_S_PROTSEQ_NOT_SUPPORTED;
781   }
782
783   *ps = ops->alloc();
784   if (!*ps)
785     return RPC_S_OUT_OF_RESOURCES;
786   (*ps)->MaxCalls = MaxCalls;
787   (*ps)->Protseq = RPCRT4_strdupA(Protseq);
788   (*ps)->ops = ops;
789   (*ps)->MaxCalls = 0;
790   (*ps)->conn = NULL;
791   InitializeCriticalSection(&(*ps)->cs);
792   (*ps)->is_listening = FALSE;
793   (*ps)->mgr_mutex = NULL;
794   (*ps)->server_ready_event = NULL;
795
796   list_add_head(&protseqs, &(*ps)->entry);
797
798   TRACE("new protseq %p created for %s\n", *ps, Protseq);
799
800   return RPC_S_OK;
801 }
802
803 /* must be called with server_cs held */
804 static void destroy_serverprotoseq(RpcServerProtseq *ps)
805 {
806     RPCRT4_strfree(ps->Protseq);
807     DeleteCriticalSection(&ps->cs);
808     CloseHandle(ps->mgr_mutex);
809     CloseHandle(ps->server_ready_event);
810     list_remove(&ps->entry);
811     HeapFree(GetProcessHeap(), 0, ps);
812 }
813
814 /* Finds a given protseq or creates a new one if one doesn't already exist */
815 static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
816 {
817     RPC_STATUS status;
818     RpcServerProtseq *cps;
819
820     EnterCriticalSection(&server_cs);
821
822     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
823         if (!strcmp(cps->Protseq, Protseq))
824         {
825             TRACE("found existing protseq object for %s\n", Protseq);
826             *ps = cps;
827             LeaveCriticalSection(&server_cs);
828             return S_OK;
829         }
830
831     status = alloc_serverprotoseq(MaxCalls, Protseq, ps);
832
833     LeaveCriticalSection(&server_cs);
834
835     return status;
836 }
837
838 /***********************************************************************
839  *             RpcServerUseProtseqEpExA (RPCRT4.@)
840  */
841 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor,
842                                             PRPC_POLICY lpPolicy )
843 {
844   RpcServerProtseq* ps;
845   RPC_STATUS status;
846
847   TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_a((const char *)Protseq),
848        MaxCalls, debugstr_a((const char *)Endpoint), SecurityDescriptor,
849        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
850
851   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
852   if (status != RPC_S_OK)
853     return status;
854
855   return RPCRT4_use_protseq(ps, (const char *)Endpoint);
856 }
857
858 /***********************************************************************
859  *             RpcServerUseProtseqEpExW (RPCRT4.@)
860  */
861 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor,
862                                             PRPC_POLICY lpPolicy )
863 {
864   RpcServerProtseq* ps;
865   RPC_STATUS status;
866   LPSTR ProtseqA;
867   LPSTR EndpointA;
868
869   TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_w( Protseq ), MaxCalls,
870        debugstr_w( Endpoint ), SecurityDescriptor,
871        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
872
873   ProtseqA = RPCRT4_strdupWtoA(Protseq);
874   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
875   RPCRT4_strfree(ProtseqA);
876   if (status != RPC_S_OK)
877     return status;
878
879   EndpointA = RPCRT4_strdupWtoA(Endpoint);
880   status = RPCRT4_use_protseq(ps, EndpointA);
881   RPCRT4_strfree(EndpointA);
882   return status;
883 }
884
885 /***********************************************************************
886  *             RpcServerUseProtseqA (RPCRT4.@)
887  */
888 RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
889 {
890   RPC_STATUS status;
891   RpcServerProtseq* ps;
892
893   TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor);
894
895   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
896   if (status != RPC_S_OK)
897     return status;
898
899   return RPCRT4_use_protseq(ps, NULL);
900 }
901
902 /***********************************************************************
903  *             RpcServerUseProtseqW (RPCRT4.@)
904  */
905 RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
906 {
907   RPC_STATUS status;
908   RpcServerProtseq* ps;
909   LPSTR ProtseqA;
910
911   TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
912
913   ProtseqA = RPCRT4_strdupWtoA(Protseq);
914   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
915   RPCRT4_strfree(ProtseqA);
916   if (status != RPC_S_OK)
917     return status;
918
919   return RPCRT4_use_protseq(ps, NULL);
920 }
921
922 void RPCRT4_destroy_all_protseqs(void)
923 {
924     RpcServerProtseq *cps, *cursor2;
925
926     if (listen_count != 0)
927         std_listen = FALSE;
928
929     EnterCriticalSection(&server_cs);
930     LIST_FOR_EACH_ENTRY_SAFE(cps, cursor2, &protseqs, RpcServerProtseq, entry)
931     {
932         if (listen_count != 0)
933             RPCRT4_sync_with_server_thread(cps);
934         destroy_serverprotoseq(cps);
935     }
936     LeaveCriticalSection(&server_cs);
937 }
938
939 /***********************************************************************
940  *             RpcServerRegisterIf (RPCRT4.@)
941  */
942 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
943 {
944   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
945   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
946 }
947
948 /***********************************************************************
949  *             RpcServerRegisterIfEx (RPCRT4.@)
950  */
951 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
952                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
953 {
954   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
955   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
956 }
957
958 /***********************************************************************
959  *             RpcServerRegisterIf2 (RPCRT4.@)
960  */
961 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
962                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
963 {
964   PRPC_SERVER_INTERFACE If = IfSpec;
965   RpcServerInterface* sif;
966   unsigned int i;
967
968   TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
969          MaxRpcSize, IfCallbackFn);
970   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
971                                      If->InterfaceId.SyntaxVersion.MajorVersion,
972                                      If->InterfaceId.SyntaxVersion.MinorVersion);
973   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
974                                         If->TransferSyntax.SyntaxVersion.MajorVersion,
975                                         If->TransferSyntax.SyntaxVersion.MinorVersion);
976   TRACE(" dispatch table: %p\n", If->DispatchTable);
977   if (If->DispatchTable) {
978     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
979     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
980       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
981     }
982     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
983   }
984   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
985   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
986   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
987
988   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
989   sif->If           = If;
990   if (MgrTypeUuid) {
991     sif->MgrTypeUuid = *MgrTypeUuid;
992     sif->MgrEpv       = MgrEpv;
993   } else {
994     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
995     sif->MgrEpv       = If->DefaultManagerEpv;
996   }
997   sif->Flags        = Flags;
998   sif->MaxCalls     = MaxCalls;
999   sif->MaxRpcSize   = MaxRpcSize;
1000   sif->IfCallbackFn = IfCallbackFn;
1001
1002   EnterCriticalSection(&server_cs);
1003   list_add_head(&server_interfaces, &sif->entry);
1004   LeaveCriticalSection(&server_cs);
1005
1006   if (sif->Flags & RPC_IF_AUTOLISTEN)
1007       RPCRT4_start_listen(TRUE);
1008
1009   return RPC_S_OK;
1010 }
1011
1012 /***********************************************************************
1013  *             RpcServerUnregisterIf (RPCRT4.@)
1014  */
1015 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
1016 {
1017   PRPC_SERVER_INTERFACE If = IfSpec;
1018   HANDLE event = NULL;
1019   BOOL found = FALSE;
1020   BOOL completed = TRUE;
1021   RpcServerInterface *cif;
1022   RPC_STATUS status;
1023
1024   TRACE("(IfSpec == (RPC_IF_HANDLE)^%p (%s), MgrTypeUuid == %s, WaitForCallsToComplete == %u)\n",
1025     IfSpec, debugstr_guid(&If->InterfaceId.SyntaxGUID), debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
1026
1027   EnterCriticalSection(&server_cs);
1028   LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
1029     if ((!IfSpec || !memcmp(&If->InterfaceId, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
1030         UuidEqual(MgrTypeUuid, &cif->MgrTypeUuid, &status)) {
1031       list_remove(&cif->entry);
1032       TRACE("unregistering cif %p\n", cif);
1033       if (cif->CurrentCalls) {
1034         completed = FALSE;
1035         cif->Delete = TRUE;
1036         if (WaitForCallsToComplete)
1037           cif->CallsCompletedEvent = event = CreateEventW(NULL, FALSE, FALSE, NULL);
1038       }
1039       found = TRUE;
1040       break;
1041     }
1042   }
1043   LeaveCriticalSection(&server_cs);
1044
1045   if (!found) {
1046     ERR("not found for object %s\n", debugstr_guid(MgrTypeUuid));
1047     return RPC_S_UNKNOWN_IF;
1048   }
1049
1050   if (completed)
1051     HeapFree(GetProcessHeap(), 0, cif);
1052   else if (event) {
1053     /* sif will be freed when the last call is completed, so be careful not to
1054      * touch that memory here as that could happen before we get here */
1055     WaitForSingleObject(event, INFINITE);
1056     CloseHandle(event);
1057   }
1058
1059   return RPC_S_OK;
1060 }
1061
1062 /***********************************************************************
1063  *             RpcServerUnregisterIfEx (RPCRT4.@)
1064  */
1065 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
1066 {
1067   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
1068     IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
1069
1070   return RPC_S_OK;
1071 }
1072
1073 /***********************************************************************
1074  *             RpcObjectSetType (RPCRT4.@)
1075  *
1076  * PARAMS
1077  *   ObjUuid  [I] "Object" UUID
1078  *   TypeUuid [I] "Type" UUID
1079  *
1080  * RETURNS
1081  *   RPC_S_OK                 The call succeeded
1082  *   RPC_S_INVALID_OBJECT     The provided object (nil) is not valid
1083  *   RPC_S_ALREADY_REGISTERED The provided object is already registered
1084  *
1085  * Maps "Object" UUIDs to "Type" UUID's.  Passing the nil UUID as the type
1086  * resets the mapping for the specified object UUID to nil (the default).
1087  * The nil object is always associated with the nil type and cannot be
1088  * reassigned.  Servers can support multiple implementations on the same
1089  * interface by registering different end-point vectors for the different
1090  * types.  There's no need to call this if a server only supports the nil
1091  * type, as is typical.
1092  */
1093 RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
1094 {
1095   RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
1096   RPC_STATUS dummy;
1097
1098   TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
1099   if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
1100     /* nil uuid cannot be remapped */
1101     return RPC_S_INVALID_OBJECT;
1102   }
1103
1104   /* find the mapping for this object if there is one ... */
1105   while (map) {
1106     if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
1107     prev = map;
1108     map = map->next;
1109   }
1110   if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
1111     /* ... and drop it from the list */
1112     if (map) {
1113       if (prev) 
1114         prev->next = map->next;
1115       else
1116         RpcObjTypeMaps = map->next;
1117       HeapFree(GetProcessHeap(), 0, map);
1118     }
1119   } else {
1120     /* ... , fail if we found it ... */
1121     if (map)
1122       return RPC_S_ALREADY_REGISTERED;
1123     /* ... otherwise create a new one and add it in. */
1124     map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
1125     map->Object = *ObjUuid;
1126     map->Type = *TypeUuid;
1127     map->next = NULL;
1128     if (prev)
1129       prev->next = map; /* prev is the last map in the linklist */
1130     else
1131       RpcObjTypeMaps = map;
1132   }
1133
1134   return RPC_S_OK;
1135 }
1136
1137 /***********************************************************************
1138  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
1139  */
1140 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1141                             LPVOID Arg )
1142 {
1143   FIXME( "(%s,%u,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
1144   
1145   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
1146 }
1147
1148 /***********************************************************************
1149  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
1150  */
1151 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1152                             LPVOID Arg )
1153 {
1154   FIXME( "(%s,%u,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
1155   
1156   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
1157 }
1158
1159 /***********************************************************************
1160  *             RpcServerListen (RPCRT4.@)
1161  */
1162 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
1163 {
1164   RPC_STATUS status = RPC_S_OK;
1165
1166   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
1167
1168   if (list_empty(&protseqs))
1169     return RPC_S_NO_PROTSEQS_REGISTERED;
1170
1171   status = RPCRT4_start_listen(FALSE);
1172
1173   if (DontWait || (status != RPC_S_OK)) return status;
1174
1175   return RpcMgmtWaitServerListen();
1176 }
1177
1178 /***********************************************************************
1179  *             RpcMgmtServerWaitListen (RPCRT4.@)
1180  */
1181 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
1182 {
1183   TRACE("()\n");
1184
1185   EnterCriticalSection(&listen_cs);
1186
1187   if (!std_listen) {
1188     LeaveCriticalSection(&listen_cs);
1189     return RPC_S_NOT_LISTENING;
1190   }
1191   
1192   LeaveCriticalSection(&listen_cs);
1193
1194   FIXME("not waiting for server calls to finish\n");
1195
1196   return RPC_S_OK;
1197 }
1198
1199 /***********************************************************************
1200  *             RpcMgmtStopServerListening (RPCRT4.@)
1201  */
1202 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
1203 {
1204   TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
1205
1206   if (Binding) {
1207     FIXME("client-side invocation not implemented.\n");
1208     return RPC_S_WRONG_KIND_OF_BINDING;
1209   }
1210   
1211   RPCRT4_stop_listen(FALSE);
1212
1213   return RPC_S_OK;
1214 }
1215
1216 /***********************************************************************
1217  *             RpcMgmtEnableIdleCleanup (RPCRT4.@)
1218  */
1219 RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void)
1220 {
1221     FIXME("(): stub\n");
1222     return RPC_S_OK;
1223 }
1224
1225 /***********************************************************************
1226  *             I_RpcServerStartListening (RPCRT4.@)
1227  */
1228 RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
1229 {
1230   FIXME( "(%p): stub\n", hWnd );
1231
1232   return RPC_S_OK;
1233 }
1234
1235 /***********************************************************************
1236  *             I_RpcServerStopListening (RPCRT4.@)
1237  */
1238 RPC_STATUS WINAPI I_RpcServerStopListening( void )
1239 {
1240   FIXME( "(): stub\n" );
1241
1242   return RPC_S_OK;
1243 }
1244
1245 /***********************************************************************
1246  *             I_RpcWindowProc (RPCRT4.@)
1247  */
1248 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1249 {
1250   FIXME( "(%p,%08x,%08x,%08x): stub\n", hWnd, Message, wParam, lParam );
1251
1252   return 0;
1253 }
1254
1255 /***********************************************************************
1256  *             RpcMgmtInqIfIds (RPCRT4.@)
1257  */
1258 RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector)
1259 {
1260   FIXME("(%p,%p): stub\n", Binding, IfIdVector);
1261   return RPC_S_INVALID_BINDING;
1262 }
1263
1264 /***********************************************************************
1265  *             RpcMgmtInqStats (RPCRT4.@)
1266  */
1267 RPC_STATUS WINAPI RpcMgmtInqStats(RPC_BINDING_HANDLE Binding, RPC_STATS_VECTOR **Statistics)
1268 {
1269   RPC_STATS_VECTOR *stats;
1270
1271   FIXME("(%p,%p)\n", Binding, Statistics);
1272
1273   if ((stats = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_STATS_VECTOR))))
1274   {
1275     stats->Count = 1;
1276     stats->Stats[0] = 0;
1277     *Statistics = stats;
1278     return RPC_S_OK;
1279   }
1280   return RPC_S_OUT_OF_RESOURCES;
1281 }
1282
1283 /***********************************************************************
1284  *             RpcMgmtStatsVectorFree (RPCRT4.@)
1285  */
1286 RPC_STATUS WINAPI RpcMgmtStatsVectorFree(RPC_STATS_VECTOR **StatsVector)
1287 {
1288   FIXME("(%p)\n", StatsVector);
1289
1290   if (StatsVector)
1291   {
1292     HeapFree(GetProcessHeap(), 0, *StatsVector);
1293     *StatsVector = NULL;
1294   }
1295   return RPC_S_OK;
1296 }
1297
1298 /***********************************************************************
1299  *             RpcMgmtEpEltInqBegin (RPCRT4.@)
1300  */
1301 RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, ULONG InquiryType,
1302     RPC_IF_ID *IfId, ULONG VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext)
1303 {
1304   FIXME("(%p,%u,%p,%u,%p,%p): stub\n",
1305         Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext);
1306   return RPC_S_INVALID_BINDING;
1307 }
1308
1309 /***********************************************************************
1310  *             RpcMgmtIsServerListening (RPCRT4.@)
1311  */
1312 RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding)
1313 {
1314   FIXME("(%p): stub\n", Binding);
1315   return RPC_S_INVALID_BINDING;
1316 }
1317
1318 /***********************************************************************
1319  *             RpcMgmtSetServerStackSize (RPCRT4.@)
1320  */
1321 RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
1322 {
1323   FIXME("(0x%x): stub\n", ThreadStackSize);
1324   return RPC_S_OK;
1325 }
1326
1327 /***********************************************************************
1328  *             I_RpcGetCurrentCallHandle (RPCRT4.@)
1329  */
1330 RPC_BINDING_HANDLE WINAPI I_RpcGetCurrentCallHandle(void)
1331 {
1332     TRACE("\n");
1333     return RPCRT4_GetThreadCurrentCallHandle();
1334 }