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