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