oledlg: Call the hook proc if present.
[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%08lx = %ld\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 static 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=%08lx\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 typedef struct _RpcServerProtseq_np
352 {
353     RpcServerProtseq common;
354     HANDLE mgr_event;
355 } RpcServerProtseq_np;
356
357 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
358 {
359     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
360     if (ps)
361         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
362     return &ps->common;
363 }
364
365 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
366 {
367     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
368     SetEvent(npps->mgr_event);
369 }
370
371 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
372 {
373     HANDLE *objs = prev_array;
374     RpcConnection* conn;
375     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
376
377     EnterCriticalSection(&protseq->cs);
378
379     /* open and count connections */
380     *count = 1;
381     conn = protseq->conn;
382     while (conn) {
383         RPCRT4_OpenConnection(conn);
384         if (rpcrt4_conn_get_wait_object(conn))
385             (*count)++;
386         conn = conn->Next;
387     }
388
389     /* make array of connections */
390     if (objs)
391         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
392     else
393         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
394     if (!objs)
395     {
396         ERR("couldn't allocate objs\n");
397         LeaveCriticalSection(&protseq->cs);
398         return NULL;
399     }
400     
401     objs[0] = npps->mgr_event;
402     *count = 1;
403     conn = protseq->conn;
404     while (conn) {
405         if ((objs[*count] = rpcrt4_conn_get_wait_object(conn)))
406             (*count)++;
407         conn = conn->Next;
408     }
409     LeaveCriticalSection(&protseq->cs);
410     return objs;
411 }
412
413 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
414 {
415     HeapFree(GetProcessHeap(), 0, array);
416 }
417
418 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
419 {
420     HANDLE b_handle;
421     HANDLE *objs = wait_array;
422     DWORD res;
423     RpcConnection* cconn;
424     RpcConnection* conn;
425
426     if (!objs)
427         return -1;
428
429     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
430     if (res == WAIT_OBJECT_0)
431         return 0;
432     else if (res == WAIT_FAILED)
433     {
434         ERR("wait failed with error %ld\n", GetLastError());
435         return -1;
436     }
437     else
438     {
439         b_handle = objs[res - WAIT_OBJECT_0];
440         /* find which connection got a RPC */
441         EnterCriticalSection(&protseq->cs);
442         conn = protseq->conn;
443         while (conn) {
444             if (b_handle == rpcrt4_conn_get_wait_object(conn)) break;
445             conn = conn->Next;
446         }
447         cconn = NULL;
448         if (conn)
449             RPCRT4_SpawnConnection(&cconn, conn);
450         else
451             ERR("failed to locate connection for handle %p\n", b_handle);
452         LeaveCriticalSection(&protseq->cs);
453         if (cconn)
454         {
455             RPCRT4_new_client(cconn);
456             return 1;
457         }
458         else return -1;
459     }
460 }
461
462 static const struct protseq_ops protseq_list[] =
463 {
464     {
465         "ncacn_np",
466         rpcrt4_protseq_np_alloc,
467         rpcrt4_protseq_np_signal_state_changed,
468         rpcrt4_protseq_np_get_wait_array,
469         rpcrt4_protseq_np_free_wait_array,
470         rpcrt4_protseq_np_wait_for_new_connection,
471     },
472     {
473         "ncalrpc",
474         rpcrt4_protseq_np_alloc,
475         rpcrt4_protseq_np_signal_state_changed,
476         rpcrt4_protseq_np_get_wait_array,
477         rpcrt4_protseq_np_free_wait_array,
478         rpcrt4_protseq_np_wait_for_new_connection,
479     },
480     {
481         "ncacn_ip_tcp",
482         rpcrt4_protseq_np_alloc,
483         rpcrt4_protseq_np_signal_state_changed,
484         rpcrt4_protseq_np_get_wait_array,
485         rpcrt4_protseq_np_free_wait_array,
486         rpcrt4_protseq_np_wait_for_new_connection,
487     },
488 };
489
490 static const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
491 {
492     int i;
493     for(i=0; i < sizeof(protseq_list)/sizeof(protseq_list[0]); i++)
494         if (!strcmp(protseq_list[i].name, protseq))
495             return &protseq_list[i];
496     return NULL;
497 }
498
499 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
500 {
501   int res;
502   unsigned int count;
503   void *objs = NULL;
504   RpcServerProtseq* cps = the_arg;
505   RpcConnection* conn;
506   BOOL set_ready_event = FALSE;
507
508   TRACE("(the_arg == ^%p)\n", the_arg);
509
510   for (;;) {
511     objs = cps->ops->get_wait_array(cps, objs, &count);
512
513     if (set_ready_event)
514     {
515         /* signal to function that changed state that we are now sync'ed */
516         SetEvent(cps->server_ready_event);
517         set_ready_event = FALSE;
518     }
519
520     /* start waiting */
521     res = cps->ops->wait_for_new_connection(cps, count, objs);
522     if (res == -1)
523       break;
524     else if (res == 0)
525     {
526       if (!std_listen)
527       {
528         SetEvent(cps->server_ready_event);
529         break;
530       }
531       set_ready_event = TRUE;
532     }
533   }
534   cps->ops->free_wait_array(cps, objs);
535   EnterCriticalSection(&cps->cs);
536   /* close connections */
537   conn = cps->conn;
538   while (conn) {
539     RPCRT4_CloseConnection(conn);
540     conn = conn->Next;
541   }
542   LeaveCriticalSection(&cps->cs);
543   return 0;
544 }
545
546 /* tells the server thread that the state has changed and waits for it to
547  * make the changes */
548 static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps)
549 {
550   /* make sure we are the only thread sync'ing the server state, otherwise
551    * there is a race with the server thread setting an older state and setting
552    * the server_ready_event when the new state hasn't yet been applied */
553   WaitForSingleObject(ps->mgr_mutex, INFINITE);
554
555   ps->ops->signal_state_changed(ps);
556
557   /* wait for server thread to make the requested changes before returning */
558   WaitForSingleObject(ps->server_ready_event, INFINITE);
559
560   ReleaseMutex(ps->mgr_mutex);
561 }
562
563 static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen)
564 {
565   RPC_STATUS status = RPC_S_OK;
566   HANDLE server_thread;
567
568   EnterCriticalSection(&listen_cs);
569   if (ps->is_listening) goto done;
570
571   if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
572   if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
573   server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL);
574   if (!server_thread)
575   {
576     status = RPC_S_OUT_OF_RESOURCES;
577     goto done;
578   }
579   ps->is_listening = TRUE;
580   CloseHandle(server_thread);
581
582 done:
583   LeaveCriticalSection(&listen_cs);
584   return status;
585 }
586
587 static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
588 {
589   RPC_STATUS status = RPC_S_ALREADY_LISTENING;
590   RpcServerProtseq *cps;
591
592   TRACE("\n");
593
594   EnterCriticalSection(&listen_cs);
595   if (auto_listen || (manual_listen_count++ == 0))
596   {
597     status = RPC_S_OK;
598     if (++listen_count == 1)
599       std_listen = TRUE;
600   }
601   LeaveCriticalSection(&listen_cs);
602
603   if (std_listen)
604   {
605     EnterCriticalSection(&server_cs);
606     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
607     {
608       status = RPCRT4_start_listen_protseq(cps, TRUE);
609       if (status != RPC_S_OK)
610         break;
611       
612       /* make sure server is actually listening on the interface before
613        * returning */
614       RPCRT4_sync_with_server_thread(cps);
615     }
616     LeaveCriticalSection(&server_cs);
617   }
618
619   return status;
620 }
621
622 static void RPCRT4_stop_listen(BOOL auto_listen)
623 {
624   EnterCriticalSection(&listen_cs);
625   if (auto_listen || (--manual_listen_count == 0))
626   {
627     if (listen_count != 0 && --listen_count == 0) {
628       RpcServerProtseq *cps;
629
630       std_listen = FALSE;
631       LeaveCriticalSection(&listen_cs);
632
633       LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
634         RPCRT4_sync_with_server_thread(cps);
635
636       return;
637     }
638     assert(listen_count >= 0);
639   }
640   LeaveCriticalSection(&listen_cs);
641 }
642
643 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
644 {
645   RPC_STATUS status;
646
647   status = RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL,
648                                    ps->Endpoint, NULL, NULL, NULL);
649   if (status != RPC_S_OK)
650     return status;
651
652   EnterCriticalSection(&server_cs);
653   list_add_head(&protseqs, &ps->entry);
654   LeaveCriticalSection(&server_cs);
655
656   if (std_listen)
657   {
658     status = RPCRT4_start_listen_protseq(ps, FALSE);
659     if (status == RPC_S_OK)
660       RPCRT4_sync_with_server_thread(ps);
661   }
662
663   return status;
664 }
665
666 /***********************************************************************
667  *             RpcServerInqBindings (RPCRT4.@)
668  */
669 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
670 {
671   RPC_STATUS status;
672   DWORD count;
673   RpcServerProtseq* ps;
674   RpcConnection* conn;
675
676   if (BindingVector)
677     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
678   else
679     ERR("(BindingVector == NULL!!?)\n");
680
681   EnterCriticalSection(&server_cs);
682   /* count connections */
683   count = 0;
684   LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
685     EnterCriticalSection(&ps->cs);
686     conn = ps->conn;
687     while (conn) {
688       count++;
689       conn = conn->Next;
690     }
691     LeaveCriticalSection(&ps->cs);
692   }
693   if (count) {
694     /* export bindings */
695     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
696                               sizeof(RPC_BINDING_VECTOR) +
697                               sizeof(RPC_BINDING_HANDLE)*(count-1));
698     (*BindingVector)->Count = count;
699     count = 0;
700     LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
701       EnterCriticalSection(&ps->cs);
702       conn = ps->conn;
703       while (conn) {
704        RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
705                           conn);
706        count++;
707        conn = conn->Next;
708       }
709       LeaveCriticalSection(&ps->cs);
710     }
711     status = RPC_S_OK;
712   } else {
713     *BindingVector = NULL;
714     status = RPC_S_NO_BINDINGS;
715   }
716   LeaveCriticalSection(&server_cs);
717   return status;
718 }
719
720 /***********************************************************************
721  *             RpcServerUseProtseqEpA (RPCRT4.@)
722  */
723 RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor )
724 {
725   RPC_POLICY policy;
726   
727   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
728   
729   /* This should provide the default behaviour */
730   policy.Length        = sizeof( policy );
731   policy.EndpointFlags = 0;
732   policy.NICFlags      = 0;
733   
734   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
735 }
736
737 /***********************************************************************
738  *             RpcServerUseProtseqEpW (RPCRT4.@)
739  */
740 RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor )
741 {
742   RPC_POLICY policy;
743   
744   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
745   
746   /* This should provide the default behaviour */
747   policy.Length        = sizeof( policy );
748   policy.EndpointFlags = 0;
749   policy.NICFlags      = 0;
750   
751   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
752 }
753
754 /***********************************************************************
755  *             alloc_serverprotoseq (internal)
756  */
757 static RpcServerProtseq *alloc_serverprotoseq(UINT MaxCalls, char *Protseq, char *Endpoint)
758 {
759   RpcServerProtseq* ps;
760   const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq);
761
762   if (!ops)
763     return NULL;
764
765   ps = ops->alloc();
766   if (!ps)
767     return NULL;
768   ps->MaxCalls = MaxCalls;
769   ps->Protseq = Protseq;
770   ps->Endpoint = Endpoint;
771   ps->ops = ops;
772   ps->MaxCalls = 0;
773   ps->conn = NULL;
774   InitializeCriticalSection(&ps->cs);
775   ps->is_listening = FALSE;
776   ps->mgr_mutex = NULL;
777   ps->server_ready_event = NULL;
778
779   return ps;
780 }
781
782 /***********************************************************************
783  *             RpcServerUseProtseqEpExA (RPCRT4.@)
784  */
785 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor,
786                                             PRPC_POLICY lpPolicy )
787 {
788   char *szps = (char*)Protseq, *szep = (char*)Endpoint;
789   RpcServerProtseq* ps;
790
791   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a(szps), MaxCalls,
792        debugstr_a(szep), SecurityDescriptor,
793        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
794
795   ps = alloc_serverprotoseq(MaxCalls, RPCRT4_strdupA(szps), RPCRT4_strdupA(szep));
796
797   return RPCRT4_use_protseq(ps);
798 }
799
800 /***********************************************************************
801  *             RpcServerUseProtseqEpExW (RPCRT4.@)
802  */
803 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor,
804                                             PRPC_POLICY lpPolicy )
805 {
806   RpcServerProtseq* ps;
807
808   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls,
809        debugstr_w( Endpoint ), SecurityDescriptor,
810        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
811
812   ps = alloc_serverprotoseq(MaxCalls, RPCRT4_strdupWtoA(Protseq),
813                             RPCRT4_strdupWtoA(Endpoint));
814
815   return RPCRT4_use_protseq(ps);
816 }
817
818 /***********************************************************************
819  *             RpcServerUseProtseqA (RPCRT4.@)
820  */
821 RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
822 {
823   TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor);
824   return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor);
825 }
826
827 /***********************************************************************
828  *             RpcServerUseProtseqW (RPCRT4.@)
829  */
830 RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
831 {
832   TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
833   return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor);
834 }
835
836 /***********************************************************************
837  *             RpcServerRegisterIf (RPCRT4.@)
838  */
839 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
840 {
841   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
842   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
843 }
844
845 /***********************************************************************
846  *             RpcServerRegisterIfEx (RPCRT4.@)
847  */
848 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
849                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
850 {
851   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
852   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
853 }
854
855 /***********************************************************************
856  *             RpcServerRegisterIf2 (RPCRT4.@)
857  */
858 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
859                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
860 {
861   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
862   RpcServerInterface* sif;
863   unsigned int i;
864
865   TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
866          MaxRpcSize, IfCallbackFn);
867   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
868                                      If->InterfaceId.SyntaxVersion.MajorVersion,
869                                      If->InterfaceId.SyntaxVersion.MinorVersion);
870   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
871                                         If->TransferSyntax.SyntaxVersion.MajorVersion,
872                                         If->TransferSyntax.SyntaxVersion.MinorVersion);
873   TRACE(" dispatch table: %p\n", If->DispatchTable);
874   if (If->DispatchTable) {
875     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
876     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
877       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
878     }
879     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
880   }
881   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
882   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
883   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
884
885   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
886   sif->If           = If;
887   if (MgrTypeUuid) {
888     memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
889     sif->MgrEpv       = MgrEpv;
890   } else {
891     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
892     sif->MgrEpv       = If->DefaultManagerEpv;
893   }
894   sif->Flags        = Flags;
895   sif->MaxCalls     = MaxCalls;
896   sif->MaxRpcSize   = MaxRpcSize;
897   sif->IfCallbackFn = IfCallbackFn;
898
899   EnterCriticalSection(&server_cs);
900   sif->Next = ifs;
901   ifs = sif;
902   LeaveCriticalSection(&server_cs);
903
904   if (sif->Flags & RPC_IF_AUTOLISTEN)
905       RPCRT4_start_listen(TRUE);
906
907   return RPC_S_OK;
908 }
909
910 /***********************************************************************
911  *             RpcServerUnregisterIf (RPCRT4.@)
912  */
913 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
914 {
915   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n",
916     IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
917
918   return RPC_S_OK;
919 }
920
921 /***********************************************************************
922  *             RpcServerUnregisterIfEx (RPCRT4.@)
923  */
924 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
925 {
926   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
927     IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
928
929   return RPC_S_OK;
930 }
931
932 /***********************************************************************
933  *             RpcObjectSetType (RPCRT4.@)
934  *
935  * PARAMS
936  *   ObjUuid  [I] "Object" UUID
937  *   TypeUuid [I] "Type" UUID
938  *
939  * RETURNS
940  *   RPC_S_OK                 The call succeeded
941  *   RPC_S_INVALID_OBJECT     The provided object (nil) is not valid
942  *   RPC_S_ALREADY_REGISTERED The provided object is already registered
943  *
944  * Maps "Object" UUIDs to "Type" UUID's.  Passing the nil UUID as the type
945  * resets the mapping for the specified object UUID to nil (the default).
946  * The nil object is always associated with the nil type and cannot be
947  * reassigned.  Servers can support multiple implementations on the same
948  * interface by registering different end-point vectors for the different
949  * types.  There's no need to call this if a server only supports the nil
950  * type, as is typical.
951  */
952 RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
953 {
954   RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
955   RPC_STATUS dummy;
956
957   TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
958   if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
959     /* nil uuid cannot be remapped */
960     return RPC_S_INVALID_OBJECT;
961   }
962
963   /* find the mapping for this object if there is one ... */
964   while (map) {
965     if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
966     prev = map;
967     map = map->next;
968   }
969   if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
970     /* ... and drop it from the list */
971     if (map) {
972       if (prev) 
973         prev->next = map->next;
974       else
975         RpcObjTypeMaps = map->next;
976       HeapFree(GetProcessHeap(), 0, map);
977     }
978   } else {
979     /* ... , fail if we found it ... */
980     if (map)
981       return RPC_S_ALREADY_REGISTERED;
982     /* ... otherwise create a new one and add it in. */
983     map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
984     memcpy(&map->Object, ObjUuid, sizeof(UUID));
985     memcpy(&map->Type, TypeUuid, sizeof(UUID));
986     map->next = NULL;
987     if (prev)
988       prev->next = map; /* prev is the last map in the linklist */
989     else
990       RpcObjTypeMaps = map;
991   }
992
993   return RPC_S_OK;
994 }
995
996 /***********************************************************************
997  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
998  */
999 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1000                             LPVOID Arg )
1001 {
1002   FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
1003   
1004   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
1005 }
1006
1007 /***********************************************************************
1008  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
1009  */
1010 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1011                             LPVOID Arg )
1012 {
1013   FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
1014   
1015   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
1016 }
1017
1018 /***********************************************************************
1019  *             RpcServerListen (RPCRT4.@)
1020  */
1021 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
1022 {
1023   RPC_STATUS status = RPC_S_OK;
1024
1025   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
1026
1027   if (list_empty(&protseqs))
1028     return RPC_S_NO_PROTSEQS_REGISTERED;
1029
1030   status = RPCRT4_start_listen(FALSE);
1031
1032   if (DontWait || (status != RPC_S_OK)) return status;
1033
1034   return RpcMgmtWaitServerListen();
1035 }
1036
1037 /***********************************************************************
1038  *             RpcMgmtServerWaitListen (RPCRT4.@)
1039  */
1040 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
1041 {
1042   TRACE("()\n");
1043
1044   EnterCriticalSection(&listen_cs);
1045
1046   if (!std_listen) {
1047     LeaveCriticalSection(&listen_cs);
1048     return RPC_S_NOT_LISTENING;
1049   }
1050   
1051   LeaveCriticalSection(&listen_cs);
1052
1053   FIXME("not waiting for server calls to finish\n");
1054
1055   return RPC_S_OK;
1056 }
1057
1058 /***********************************************************************
1059  *             RpcMgmtStopServerListening (RPCRT4.@)
1060  */
1061 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
1062 {
1063   TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
1064
1065   if (Binding) {
1066     FIXME("client-side invocation not implemented.\n");
1067     return RPC_S_WRONG_KIND_OF_BINDING;
1068   }
1069   
1070   RPCRT4_stop_listen(FALSE);
1071
1072   return RPC_S_OK;
1073 }
1074
1075 /***********************************************************************
1076  *             RpcMgmtEnableIdleCleanup (RPCRT4.@)
1077  */
1078 RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void)
1079 {
1080     FIXME("(): stub\n");
1081     return RPC_S_OK;
1082 }
1083
1084 /***********************************************************************
1085  *             I_RpcServerStartListening (RPCRT4.@)
1086  */
1087 RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
1088 {
1089   FIXME( "(%p): stub\n", hWnd );
1090
1091   return RPC_S_OK;
1092 }
1093
1094 /***********************************************************************
1095  *             I_RpcServerStopListening (RPCRT4.@)
1096  */
1097 RPC_STATUS WINAPI I_RpcServerStopListening( void )
1098 {
1099   FIXME( "(): stub\n" );
1100
1101   return RPC_S_OK;
1102 }
1103
1104 /***********************************************************************
1105  *             I_RpcWindowProc (RPCRT4.@)
1106  */
1107 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1108 {
1109   FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
1110
1111   return 0;
1112 }
1113
1114 /***********************************************************************
1115  *             RpcMgmtInqIfIds (RPCRT4.@)
1116  */
1117 RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector)
1118 {
1119   FIXME("(%p,%p): stub\n", Binding, IfIdVector);
1120   return RPC_S_INVALID_BINDING;
1121 }
1122
1123 /***********************************************************************
1124  *             RpcMgmtEpEltInqBegin (RPCRT4.@)
1125  */
1126 RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, unsigned long InquiryType,
1127     RPC_IF_ID *IfId, unsigned long VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext)
1128 {
1129   FIXME("(%p,%lu,%p,%lu,%p,%p): stub\n",
1130         Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext);
1131   return RPC_S_INVALID_BINDING;
1132 }
1133
1134 /***********************************************************************
1135  *             RpcMgmtIsServerListening (RPCRT4.@)
1136  */
1137 RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding)
1138 {
1139   FIXME("(%p): stub\n", Binding);
1140   return RPC_S_INVALID_BINDING;
1141 }
1142
1143 /***********************************************************************
1144  *             RpcMgmtSetServerStackSize (RPCRT4.@)
1145  */
1146 RPC_STATUS WINAPI RpcMgmtSetServerStackSize(unsigned long ThreadStackSize)
1147 {
1148   FIXME("(0x%lx): stub\n", ThreadStackSize);
1149   return RPC_S_OK;
1150 }