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