Get rid of the non-standard ICOM_VFIELD macro.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "ntstatus.h"
38
39 #include "rpc.h"
40 #include "rpcndr.h"
41 #include "excpt.h"
42
43 #include "wine/debug.h"
44 #include "wine/exception.h"
45
46 #include "rpc_server.h"
47 #include "rpc_misc.h"
48 #include "rpc_message.h"
49 #include "rpc_defs.h"
50
51 #define MAX_THREADS 128
52
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54
55 typedef struct _RpcPacket
56 {
57   struct _RpcPacket* next;
58   struct _RpcConnection* conn;
59   RpcPktHdr* hdr;
60   RPC_MESSAGE* msg;
61 } RpcPacket;
62
63 typedef struct _RpcObjTypeMap
64 {
65   /* FIXME: a hash table would be better. */
66   struct _RpcObjTypeMap *next;
67   UUID Object;
68   UUID Type;
69 } RpcObjTypeMap;
70
71 static RpcObjTypeMap *RpcObjTypeMaps;
72
73 static RpcServerProtseq* protseqs;
74 static RpcServerInterface* ifs;
75
76 static CRITICAL_SECTION server_cs;
77 static CRITICAL_SECTION_DEBUG server_cs_debug =
78 {
79     0, 0, &server_cs,
80     { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
81       0, 0, { 0, (DWORD)(__FILE__ ": server_cs") }
82 };
83 static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
84
85 static CRITICAL_SECTION listen_cs;
86 static CRITICAL_SECTION_DEBUG listen_cs_debug =
87 {
88     0, 0, &listen_cs,
89     { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
90       0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") }
91 };
92 static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
93
94 static BOOL std_listen;
95 static LONG listen_count = -1;
96 static HANDLE mgr_event, server_thread;
97
98 static CRITICAL_SECTION spacket_cs;
99 static CRITICAL_SECTION_DEBUG spacket_cs_debug =
100 {
101     0, 0, &spacket_cs,
102     { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList },
103       0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") }
104 };
105 static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 };
106
107 static RpcPacket* spacket_head;
108 static RpcPacket* spacket_tail;
109 static HANDLE server_sem;
110
111 static DWORD worker_count, worker_free, worker_tls;
112
113 static UUID uuid_nil;
114
115 inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
116 {
117   RpcObjTypeMap *rslt = RpcObjTypeMaps;
118   RPC_STATUS dummy;
119
120   while (rslt) {
121     if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
122     rslt = rslt->next;
123   }
124
125   return rslt;
126 }
127
128 inline static UUID *LookupObjType(UUID *ObjUuid)
129 {
130   RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
131   if (map)
132     return &map->Type;
133   else
134     return &uuid_nil;
135 }
136
137 static RpcServerInterface* RPCRT4_find_interface(UUID* object,
138                                                  RPC_SYNTAX_IDENTIFIER* if_id,
139                                                  BOOL check_object)
140 {
141   UUID* MgrType = NULL;
142   RpcServerInterface* cif = NULL;
143   RPC_STATUS status;
144
145   if (check_object)
146     MgrType = LookupObjType(object);
147   EnterCriticalSection(&server_cs);
148   cif = ifs;
149   while (cif) {
150     if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
151         (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
152         (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break;
153     cif = cif->Next;
154   }
155   LeaveCriticalSection(&server_cs);
156   TRACE("returning %p for %s\n", cif, debugstr_guid(object));
157   return cif;
158 }
159
160 static void RPCRT4_push_packet(RpcPacket* packet)
161 {
162   packet->next = NULL;
163   EnterCriticalSection(&spacket_cs);
164   if (spacket_tail) {
165     spacket_tail->next = packet;
166     spacket_tail = packet;
167   } else {
168     spacket_head = packet;
169     spacket_tail = packet;
170   }
171   LeaveCriticalSection(&spacket_cs);
172 }
173
174 static RpcPacket* RPCRT4_pop_packet(void)
175 {
176   RpcPacket* packet;
177   EnterCriticalSection(&spacket_cs);
178   packet = spacket_head;
179   if (packet) {
180     spacket_head = packet->next;
181     if (!spacket_head) spacket_tail = NULL;
182   }
183   LeaveCriticalSection(&spacket_cs);
184   if (packet) packet->next = NULL;
185   return packet;
186 }
187
188 typedef struct {
189   PRPC_MESSAGE msg;
190   void* buf;
191 } packet_state;
192
193 static WINE_EXCEPTION_FILTER(rpc_filter)
194 {
195   packet_state* state;
196   PRPC_MESSAGE msg;
197   state = TlsGetValue(worker_tls);
198   msg = state->msg;
199   if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg);
200   msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
201   msg->BufferLength = sizeof(DWORD);
202   I_RpcGetBuffer(msg);
203   *(DWORD*)msg->Buffer = GetExceptionCode();
204   WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer);
205   TRACE("returning failure packet\n");
206   return EXCEPTION_EXECUTE_HANDLER;
207 }
208
209 static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg)
210 {
211   RpcServerInterface* sif;
212   RPC_DISPATCH_FUNCTION func;
213   packet_state state;
214   UUID *object_uuid;
215   RpcPktHdr *response;
216   void *buf = msg->Buffer;
217   RPC_STATUS status;
218
219   state.msg = msg;
220   state.buf = buf;
221   TlsSetValue(worker_tls, &state);
222
223   switch (hdr->common.ptype) {
224     case PKT_BIND:
225       TRACE("got bind packet\n");
226
227       /* FIXME: do more checks! */
228       if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||
229           !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
230         TRACE("packet size less than min size, or active interface syntax guid non-null\n");
231         sif = NULL;
232       } else {
233         sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);
234       }
235       if (sif == NULL) {
236         TRACE("rejecting bind request on connection %p\n", conn);
237         /* Report failure to client. */
238         response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
239                                               RPC_VER_MAJOR, RPC_VER_MINOR);
240       } else {
241         TRACE("accepting bind request on connection %p\n", conn);
242
243         /* accept. */
244         response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
245                                              RPC_MAX_PACKET_SIZE,
246                                              RPC_MAX_PACKET_SIZE,
247                                              conn->Endpoint,
248                                              RESULT_ACCEPT, NO_REASON,
249                                              &sif->If->TransferSyntax);
250
251         /* save the interface for later use */
252         conn->ActiveInterface = hdr->bind.abstract;
253         conn->MaxTransmissionSize = hdr->bind.max_tsize;
254       }
255
256       if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK)
257         goto fail;
258
259       break;
260
261     case PKT_REQUEST:
262       TRACE("got request packet\n");
263
264       /* fail if the connection isn't bound with an interface */
265       if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
266         response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
267                                            status);
268
269         RPCRT4_Send(conn, response, NULL, 0);
270         break;
271       }
272
273       if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
274         object_uuid = (UUID*)(&hdr->request + 1);
275       } else {
276         object_uuid = NULL;
277       }
278
279       sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE);
280       msg->RpcInterfaceInformation = sif->If;
281       /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
282       msg->ManagerEpv = sif->MgrEpv;
283       if (object_uuid != NULL) {
284         RPCRT4_SetBindingObject(msg->Handle, object_uuid);
285       }
286
287       /* find dispatch function */
288       msg->ProcNum = hdr->request.opnum;
289       if (sif->Flags & RPC_IF_OLE) {
290         /* native ole32 always gives us a dispatch table with a single entry
291          * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
292         func = *sif->If->DispatchTable->DispatchTable;
293       } else {
294         if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
295           ERR("invalid procnum\n");
296           func = NULL;
297         }
298         func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
299       }
300
301       /* put in the drep. FIXME: is this more universally applicable?
302          perhaps we should move this outward... */
303       msg->DataRepresentation = 
304         MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
305                   MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));
306
307       /* dispatch */
308       __TRY {
309         if (func) func(msg);
310       } __EXCEPT(rpc_filter) {
311         /* failure packet was created in rpc_filter */
312       } __ENDTRY
313
314       /* send response packet */
315       I_RpcSend(msg);
316
317       msg->RpcInterfaceInformation = NULL;
318
319       break;
320
321     default:
322       FIXME("unhandled packet type\n");
323       break;
324   }
325
326 fail:
327   /* clean up */
328   if (msg->Buffer == buf) msg->Buffer = NULL;
329   TRACE("freeing Buffer=%p\n", buf);
330   HeapFree(GetProcessHeap(), 0, buf);
331   RPCRT4_DestroyBinding(msg->Handle);
332   msg->Handle = 0;
333   I_RpcFreeBuffer(msg);
334   msg->Buffer = NULL;
335   RPCRT4_FreeHeader(hdr);
336   TlsSetValue(worker_tls, NULL);
337 }
338
339 static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
340 {
341   DWORD obj;
342   RpcPacket* pkt;
343
344   for (;;) {
345     /* idle timeout after 5s */
346     obj = WaitForSingleObject(server_sem, 5000);
347     if (obj == WAIT_TIMEOUT) {
348       /* if another idle thread exist, self-destruct */
349       if (worker_free > 1) break;
350       continue;
351     }
352     pkt = RPCRT4_pop_packet();
353     if (!pkt) continue;
354     InterlockedDecrement(&worker_free);
355     for (;;) {
356       RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg);
357       HeapFree(GetProcessHeap(), 0, pkt);
358       /* try to grab another packet here without waiting
359        * on the semaphore, in case it hits max */
360       pkt = RPCRT4_pop_packet();
361       if (!pkt) break;
362       /* decrement semaphore */
363       WaitForSingleObject(server_sem, 0);
364     }
365     InterlockedIncrement(&worker_free);
366   }
367   InterlockedDecrement(&worker_free);
368   InterlockedDecrement(&worker_count);
369   return 0;
370 }
371
372 static void RPCRT4_create_worker_if_needed(void)
373 {
374   if (!worker_free && worker_count < MAX_THREADS) {
375     HANDLE thread;
376     InterlockedIncrement(&worker_count);
377     InterlockedIncrement(&worker_free);
378     thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL);
379     if (thread) CloseHandle(thread);
380     else {
381       InterlockedDecrement(&worker_free);
382       InterlockedDecrement(&worker_count);
383     }
384   }
385 }
386
387 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
388 {
389   RpcConnection* conn = (RpcConnection*)the_arg;
390   RpcPktHdr *hdr;
391   RpcBinding *pbind;
392   RPC_MESSAGE *msg;
393   RPC_STATUS status;
394   RpcPacket *packet;
395
396   TRACE("(%p)\n", conn);
397
398   for (;;) {
399     msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
400
401     /* create temporary binding for dispatch, it will be freed in
402      * RPCRT4_process_packet */
403     RPCRT4_MakeBinding(&pbind, conn);
404     msg->Handle = (RPC_BINDING_HANDLE)pbind;
405
406     status = RPCRT4_Receive(conn, &hdr, msg);
407     if (status != RPC_S_OK) {
408       WARN("receive failed with error %lx\n", status);
409       break;
410     }
411
412 #if 0
413     RPCRT4_process_packet(conn, hdr, msg);
414 #else
415     packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
416     packet->conn = conn;
417     packet->hdr = hdr;
418     packet->msg = msg;
419     RPCRT4_create_worker_if_needed();
420     RPCRT4_push_packet(packet);
421     ReleaseSemaphore(server_sem, 1, NULL);
422 #endif
423     msg = NULL;
424   }
425   if (msg) HeapFree(GetProcessHeap(), 0, msg);
426   RPCRT4_DestroyConnection(conn);
427   return 0;
428 }
429
430 static void RPCRT4_new_client(RpcConnection* conn)
431 {
432   HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
433   if (!thread) {
434     DWORD err = GetLastError();
435     ERR("failed to create thread, error=%08lx\n", err);
436     RPCRT4_DestroyConnection(conn);
437   }
438   /* we could set conn->thread, but then we'd have to make the io_thread wait
439    * for that, otherwise the thread might finish, destroy the connection, and
440    * free the memory we'd write to before we did, causing crashes and stuff -
441    * so let's implement that later, when we really need conn->thread */
442
443   CloseHandle( thread );
444 }
445
446 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
447 {
448   HANDLE m_event = mgr_event, b_handle;
449   HANDLE *objs = NULL;
450   DWORD count, res;
451   RpcServerProtseq* cps;
452   RpcConnection* conn;
453   RpcConnection* cconn;
454
455   TRACE("(the_arg == ^%p)\n", the_arg);
456
457   for (;;) {
458     EnterCriticalSection(&server_cs);
459     /* open and count connections */
460     count = 1;
461     cps = protseqs;
462     while (cps) {
463       conn = cps->conn;
464       while (conn) {
465         RPCRT4_OpenConnection(conn);
466         if (conn->ovl.hEvent) count++;
467         conn = conn->Next;
468       }
469       cps = cps->Next;
470     }
471     /* make array of connections */
472     if (objs)
473         objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
474     else
475         objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE));
476
477     objs[0] = m_event;
478     count = 1;
479     cps = protseqs;
480     while (cps) {
481       conn = cps->conn;
482       while (conn) {
483         if (conn->ovl.hEvent) objs[count++] = conn->ovl.hEvent;
484         conn = conn->Next;
485       }
486       cps = cps->Next;
487     }
488     LeaveCriticalSection(&server_cs);
489
490     /* start waiting */
491     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
492     if (res == WAIT_OBJECT_0) {
493       ResetEvent(m_event);
494       if (!std_listen) break;
495     }
496     else if (res == WAIT_FAILED) {
497       ERR("wait failed\n");
498     }
499     else {
500       b_handle = objs[res - WAIT_OBJECT_0];
501       /* find which connection got a RPC */
502       EnterCriticalSection(&server_cs);
503       conn = NULL;
504       cps = protseqs;
505       while (cps) {
506         conn = cps->conn;
507         while (conn) {
508           if (conn->ovl.hEvent == b_handle) break;
509           conn = conn->Next;
510         }
511         if (conn) break;
512         cps = cps->Next;
513       }
514       cconn = NULL;
515       if (conn) RPCRT4_SpawnConnection(&cconn, conn);
516       LeaveCriticalSection(&server_cs);
517       if (!conn) {
518         ERR("failed to locate connection for handle %p\n", b_handle);
519       }
520       if (cconn) RPCRT4_new_client(cconn);
521     }
522   }
523   HeapFree(GetProcessHeap(), 0, objs);
524   EnterCriticalSection(&server_cs);
525   /* close connections */
526   cps = protseqs;
527   while (cps) {
528     conn = cps->conn;
529     while (conn) {
530       RPCRT4_CloseConnection(conn);
531       conn = conn->Next;
532     }
533     cps = cps->Next;
534   }
535   LeaveCriticalSection(&server_cs);
536   return 0;
537 }
538
539 static void RPCRT4_start_listen(void)
540 {
541   TRACE("\n");
542
543   EnterCriticalSection(&listen_cs);
544   if (! ++listen_count) {
545     if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL);
546     if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL);
547     if (!worker_tls) worker_tls = TlsAlloc();
548     std_listen = TRUE;
549     server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
550     LeaveCriticalSection(&listen_cs);
551   } else {
552     LeaveCriticalSection(&listen_cs);
553     SetEvent(mgr_event);
554   }
555 }
556
557 static void RPCRT4_stop_listen(void)
558 {
559   EnterCriticalSection(&listen_cs);
560   if (listen_count == -1)
561     LeaveCriticalSection(&listen_cs);
562   else if (--listen_count == -1) {
563     std_listen = FALSE;
564     LeaveCriticalSection(&listen_cs);
565     SetEvent(mgr_event);
566   } else
567     LeaveCriticalSection(&listen_cs);
568   assert(listen_count > -2);
569 }
570
571 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
572 {
573   RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);
574
575   EnterCriticalSection(&server_cs);
576   ps->Next = protseqs;
577   protseqs = ps;
578   LeaveCriticalSection(&server_cs);
579
580   if (std_listen) SetEvent(mgr_event);
581
582   return RPC_S_OK;
583 }
584
585 /***********************************************************************
586  *             RpcServerInqBindings (RPCRT4.@)
587  */
588 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
589 {
590   RPC_STATUS status;
591   DWORD count;
592   RpcServerProtseq* ps;
593   RpcConnection* conn;
594
595   if (BindingVector)
596     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
597   else
598     ERR("(BindingVector == NULL!!?)\n");
599
600   EnterCriticalSection(&server_cs);
601   /* count connections */
602   count = 0;
603   ps = protseqs;
604   while (ps) {
605     conn = ps->conn;
606     while (conn) {
607       count++;
608       conn = conn->Next;
609     }
610     ps = ps->Next;
611   }
612   if (count) {
613     /* export bindings */
614     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
615                               sizeof(RPC_BINDING_VECTOR) +
616                               sizeof(RPC_BINDING_HANDLE)*(count-1));
617     (*BindingVector)->Count = count;
618     count = 0;
619     ps = protseqs;
620     while (ps) {
621       conn = ps->conn;
622       while (conn) {
623        RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
624                           conn);
625        count++;
626        conn = conn->Next;
627       }
628       ps = ps->Next;
629     }
630     status = RPC_S_OK;
631   } else {
632     *BindingVector = NULL;
633     status = RPC_S_NO_BINDINGS;
634   }
635   LeaveCriticalSection(&server_cs);
636   return status;
637 }
638
639 /***********************************************************************
640  *             RpcServerUseProtseqEpA (RPCRT4.@)
641  */
642 RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor )
643 {
644   RPC_POLICY policy;
645   
646   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
647   
648   /* This should provide the default behaviour */
649   policy.Length        = sizeof( policy );
650   policy.EndpointFlags = 0;
651   policy.NICFlags      = 0;
652   
653   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
654 }
655
656 /***********************************************************************
657  *             RpcServerUseProtseqEpW (RPCRT4.@)
658  */
659 RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
660 {
661   RPC_POLICY policy;
662   
663   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
664   
665   /* This should provide the default behaviour */
666   policy.Length        = sizeof( policy );
667   policy.EndpointFlags = 0;
668   policy.NICFlags      = 0;
669   
670   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
671 }
672
673 /***********************************************************************
674  *             RpcServerUseProtseqEpExA (RPCRT4.@)
675  */
676 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor,
677                                             PRPC_POLICY lpPolicy )
678 {
679   RpcServerProtseq* ps;
680
681   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls,
682        debugstr_a( Endpoint ), SecurityDescriptor,
683        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
684
685   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
686   ps->MaxCalls = MaxCalls;
687   ps->Protseq = RPCRT4_strdupA(Protseq);
688   ps->Endpoint = RPCRT4_strdupA(Endpoint);
689
690   return RPCRT4_use_protseq(ps);
691 }
692
693 /***********************************************************************
694  *             RpcServerUseProtseqEpExW (RPCRT4.@)
695  */
696 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
697                                             PRPC_POLICY lpPolicy )
698 {
699   RpcServerProtseq* ps;
700
701   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls,
702        debugstr_w( Endpoint ), SecurityDescriptor,
703        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
704
705   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
706   ps->MaxCalls = MaxCalls;
707   ps->Protseq = RPCRT4_strdupWtoA(Protseq);
708   ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);
709
710   return RPCRT4_use_protseq(ps);
711 }
712
713 /***********************************************************************
714  *             RpcServerUseProtseqA (RPCRT4.@)
715  */
716 RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
717 {
718   TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a(Protseq), MaxCalls, SecurityDescriptor);
719   return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor);
720 }
721
722 /***********************************************************************
723  *             RpcServerUseProtseqW (RPCRT4.@)
724  */
725 RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
726 {
727   TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
728   return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor);
729 }
730
731 /***********************************************************************
732  *             RpcServerRegisterIf (RPCRT4.@)
733  */
734 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
735 {
736   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
737   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
738 }
739
740 /***********************************************************************
741  *             RpcServerRegisterIfEx (RPCRT4.@)
742  */
743 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
744                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
745 {
746   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
747   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
748 }
749
750 /***********************************************************************
751  *             RpcServerRegisterIf2 (RPCRT4.@)
752  */
753 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
754                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
755 {
756   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
757   RpcServerInterface* sif;
758   int i;
759
760   TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
761          MaxRpcSize, IfCallbackFn);
762   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
763                                      If->InterfaceId.SyntaxVersion.MajorVersion,
764                                      If->InterfaceId.SyntaxVersion.MinorVersion);
765   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
766                                         If->TransferSyntax.SyntaxVersion.MajorVersion,
767                                         If->TransferSyntax.SyntaxVersion.MinorVersion);
768   TRACE(" dispatch table: %p\n", If->DispatchTable);
769   if (If->DispatchTable) {
770     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
771     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
772       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
773     }
774     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
775   }
776   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
777   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
778   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
779
780   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
781   sif->If           = If;
782   if (MgrTypeUuid) {
783     memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
784     sif->MgrEpv       = MgrEpv;
785   } else {
786     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
787     sif->MgrEpv       = If->DefaultManagerEpv;
788   }
789   sif->Flags        = Flags;
790   sif->MaxCalls     = MaxCalls;
791   sif->MaxRpcSize   = MaxRpcSize;
792   sif->IfCallbackFn = IfCallbackFn;
793
794   EnterCriticalSection(&server_cs);
795   sif->Next = ifs;
796   ifs = sif;
797   LeaveCriticalSection(&server_cs);
798
799   if (sif->Flags & RPC_IF_AUTOLISTEN) {
800     /* well, start listening, I think... */
801     RPCRT4_start_listen();
802   }
803
804   return RPC_S_OK;
805 }
806
807 /***********************************************************************
808  *             RpcServerUnregisterIf (RPCRT4.@)
809  */
810 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
811 {
812   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n",
813     IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
814
815   return RPC_S_OK;
816 }
817
818 /***********************************************************************
819  *             RpcServerUnregisterIfEx (RPCRT4.@)
820  */
821 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
822 {
823   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
824     IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
825
826   return RPC_S_OK;
827 }
828
829 /***********************************************************************
830  *             RpcObjectSetType (RPCRT4.@)
831  *
832  * PARAMS
833  *   ObjUuid  [I] "Object" UUID
834  *   TypeUuid [I] "Type" UUID
835  *
836  * RETURNS
837  *   RPC_S_OK                 The call succeeded
838  *   RPC_S_INVALID_OBJECT     The provided object (nil) is not valid
839  *   RPC_S_ALREADY_REGISTERED The provided object is already registered
840  *
841  * Maps "Object" UUIDs to "Type" UUID's.  Passing the nil UUID as the type
842  * resets the mapping for the specified object UUID to nil (the default).
843  * The nil object is always associated with the nil type and cannot be
844  * reassigned.  Servers can support multiple implementations on the same
845  * interface by registering different end-point vectors for the different
846  * types.  There's no need to call this if a server only supports the nil
847  * type, as is typical.
848  */
849 RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
850 {
851   RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
852   RPC_STATUS dummy;
853
854   TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
855   if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
856     /* nil uuid cannot be remapped */
857     return RPC_S_INVALID_OBJECT;
858   }
859
860   /* find the mapping for this object if there is one ... */
861   while (map) {
862     if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
863     prev = map;
864     map = map->next;
865   }
866   if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
867     /* ... and drop it from the list */
868     if (map) {
869       if (prev) 
870         prev->next = map->next;
871       else
872         RpcObjTypeMaps = map->next;
873       HeapFree(GetProcessHeap(), 0, map);
874     }
875   } else {
876     /* ... , fail if we found it ... */
877     if (map)
878       return RPC_S_ALREADY_REGISTERED;
879     /* ... otherwise create a new one and add it in. */
880     map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
881     memcpy(&map->Object, ObjUuid, sizeof(UUID));
882     memcpy(&map->Type, TypeUuid, sizeof(UUID));
883     map->next = NULL;
884     if (prev)
885       prev->next = map; /* prev is the last map in the linklist */
886     else
887       RpcObjTypeMaps = map;
888   }
889
890   return RPC_S_OK;
891 }
892
893 /***********************************************************************
894  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
895  */
896 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
897                             LPVOID Arg )
898 {
899   FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
900   
901   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
902 }
903
904 /***********************************************************************
905  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
906  */
907 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
908                             LPVOID Arg )
909 {
910   FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
911   
912   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
913 }
914
915 /***********************************************************************
916  *             RpcServerListen (RPCRT4.@)
917  */
918 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
919 {
920   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
921
922   if (!protseqs)
923     return RPC_S_NO_PROTSEQS_REGISTERED;
924
925   EnterCriticalSection(&listen_cs);
926
927   if (std_listen) {
928     LeaveCriticalSection(&listen_cs);
929     return RPC_S_ALREADY_LISTENING;
930   }
931
932   RPCRT4_start_listen();
933
934   LeaveCriticalSection(&listen_cs);
935
936   if (DontWait) return RPC_S_OK;
937
938   return RpcMgmtWaitServerListen();
939 }
940
941 /***********************************************************************
942  *             RpcMgmtServerWaitListen (RPCRT4.@)
943  */
944 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
945 {
946   RPC_STATUS rslt = RPC_S_OK;
947
948   TRACE("\n");
949
950   EnterCriticalSection(&listen_cs);
951
952   if (!std_listen)
953     if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK ) {
954       LeaveCriticalSection(&listen_cs);
955       return rslt;
956     }
957   
958   LeaveCriticalSection(&listen_cs);
959
960   while (std_listen) {
961     WaitForSingleObject(mgr_event, INFINITE);
962     if (!std_listen) {
963       Sleep(100); /* don't spin violently */
964       TRACE("spinning.\n");
965     }
966   }
967
968   return rslt;
969 }
970
971 /***********************************************************************
972  *             RpcMgmtStopServerListening (RPCRT4.@)
973  */
974 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
975 {
976   TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
977
978   if (Binding) {
979     FIXME("client-side invocation not implemented.\n");
980     return RPC_S_WRONG_KIND_OF_BINDING;
981   }
982   
983   /* hmm... */
984   EnterCriticalSection(&listen_cs);
985   while (std_listen)
986     RPCRT4_stop_listen();
987   LeaveCriticalSection(&listen_cs);
988
989   return RPC_S_OK;
990 }
991
992 /***********************************************************************
993  *             I_RpcServerStartListening (RPCRT4.@)
994  */
995 RPC_STATUS WINAPI I_RpcServerStartListening( void* hWnd )
996 {
997   FIXME( "(%p): stub\n", hWnd );
998
999   return RPC_S_OK;
1000 }
1001
1002 /***********************************************************************
1003  *             I_RpcServerStopListening (RPCRT4.@)
1004  */
1005 RPC_STATUS WINAPI I_RpcServerStopListening( void )
1006 {
1007   FIXME( "(): stub\n" );
1008
1009   return RPC_S_OK;
1010 }
1011
1012 /***********************************************************************
1013  *             I_RpcWindowProc (RPCRT4.@)
1014  */
1015 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1016 {
1017   FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
1018
1019   return 0;
1020 }