- Trace the argument to RPCRT4_server_thread.
[wine] / dlls / rpcrt4 / rpc_server.c
1 /*
2  * RPC server API
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * TODO:
21  *  - a whole lot
22  */
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "ntstatus.h"
34
35 #include "rpc.h"
36 #include "excpt.h"
37
38 #include "wine/debug.h"
39 #include "wine/exception.h"
40
41 #include "rpc_server.h"
42 #include "rpc_misc.h"
43 #include "rpc_defs.h"
44
45 #define MAX_THREADS 128
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48
49 typedef struct _RpcPacket
50 {
51   struct _RpcPacket* next;
52   struct _RpcConnection* conn;
53   RpcPktHdr hdr;
54   void* buf;
55 } RpcPacket;
56
57 static RpcServerProtseq* protseqs;
58 static RpcServerInterface* ifs;
59
60 static CRITICAL_SECTION server_cs;
61 static CRITICAL_SECTION_DEBUG server_cs_debug =
62 {
63     0, 0, &server_cs,
64     { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
65       0, 0, { 0, (DWORD)(__FILE__ ": server_cs") }
66 };
67 static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
68
69 static CRITICAL_SECTION listen_cs;
70 static CRITICAL_SECTION_DEBUG listen_cs_debug =
71 {
72     0, 0, &listen_cs,
73     { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
74       0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") }
75 };
76 static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
77
78 static BOOL std_listen;
79 static LONG listen_count = -1;
80 static HANDLE mgr_event, server_thread;
81
82 static CRITICAL_SECTION spacket_cs;
83 static CRITICAL_SECTION_DEBUG spacket_cs_debug =
84 {
85     0, 0, &spacket_cs,
86     { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList },
87       0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") }
88 };
89 static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 };
90
91 static RpcPacket* spacket_head;
92 static RpcPacket* spacket_tail;
93 static HANDLE server_sem;
94
95 static DWORD worker_count, worker_free, worker_tls;
96
97 static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id)
98 {
99   UUID* MgrType = NULL;
100   RpcServerInterface* cif = NULL;
101   RPC_STATUS status;
102
103   /* FIXME: object -> MgrType */
104   EnterCriticalSection(&server_cs);
105   cif = ifs;
106   while (cif) {
107     if (UuidEqual(if_id, &cif->If->InterfaceId.SyntaxGUID, &status) &&
108        UuidEqual(MgrType, &cif->MgrTypeUuid, &status) &&
109        (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break;
110     cif = cif->Next;
111   }
112   LeaveCriticalSection(&server_cs);
113   return cif;
114 }
115
116 static void RPCRT4_push_packet(RpcPacket* packet)
117 {
118   packet->next = NULL;
119   EnterCriticalSection(&spacket_cs);
120   if (spacket_tail) {
121     spacket_tail->next = packet;
122     spacket_tail = packet;
123   } else {
124     spacket_head = packet;
125     spacket_tail = packet;
126   }
127   LeaveCriticalSection(&spacket_cs);
128 }
129
130 static RpcPacket* RPCRT4_pop_packet(void)
131 {
132   RpcPacket* packet;
133   EnterCriticalSection(&spacket_cs);
134   packet = spacket_head;
135   if (packet) {
136     spacket_head = packet->next;
137     if (!spacket_head) spacket_tail = NULL;
138   }
139   LeaveCriticalSection(&spacket_cs);
140   if (packet) packet->next = NULL;
141   return packet;
142 }
143
144 static WINE_EXCEPTION_FILTER(rpc_filter)
145 {
146   PRPC_MESSAGE msg;
147   msg = TlsGetValue(worker_tls);
148   I_RpcFreeBuffer(msg);
149   msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
150   msg->BufferLength = sizeof(DWORD);
151   I_RpcGetBuffer(msg);
152   *(DWORD*)msg->Buffer = GetExceptionCode();
153   return EXCEPTION_EXECUTE_HANDLER;
154 }
155
156 static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf)
157 {
158   RpcBinding* pbind;
159   RPC_MESSAGE msg;
160   RpcServerInterface* sif;
161   RPC_DISPATCH_FUNCTION func;
162
163   TlsSetValue(worker_tls, &msg);
164   memset(&msg, 0, sizeof(msg));
165   msg.BufferLength = hdr->len;
166   msg.Buffer = buf;
167   sif = RPCRT4_find_interface(&hdr->object, &hdr->if_id);
168   if (sif) {
169     TRACE("packet received for interface %s\n", debugstr_guid(&hdr->if_id));
170     msg.RpcInterfaceInformation = sif->If;
171     /* create temporary binding for dispatch */
172     RPCRT4_MakeBinding(&pbind, conn);
173     RPCRT4_SetBindingObject(pbind, &hdr->object);
174     msg.Handle = (RPC_BINDING_HANDLE)pbind;
175     /* process packet */
176     switch (hdr->ptype) {
177     case PKT_REQUEST:
178       /* find dispatch function */
179       msg.ProcNum = hdr->opnum;
180       if (sif->Flags & RPC_IF_OLE) {
181         /* native ole32 always gives us a dispatch table with a single entry
182          * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
183         func = *sif->If->DispatchTable->DispatchTable;
184       } else {
185         if (msg.ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
186           ERR("invalid procnum\n");
187           func = NULL;
188         }
189         func = sif->If->DispatchTable->DispatchTable[msg.ProcNum];
190       }
191
192       /* put in the drep. FIXME: is this more universally applicable?
193          perhaps we should move this outward... */
194       msg.DataRepresentation = 
195         MAKELONG( MAKEWORD(hdr->drep[0], hdr->drep[1]),
196                   MAKEWORD(hdr->drep[2], 0));
197
198       /* dispatch */
199       __TRY {
200         if (func) func(&msg);
201       } __EXCEPT(rpc_filter) {
202         /* failure packet was created in rpc_filter */
203         TRACE("exception caught, returning failure packet\n");
204       } __ENDTRY
205
206       /* send response packet */
207       I_RpcSend(&msg);
208       break;
209     default:
210       ERR("unknown packet type\n");
211       break;
212     }
213
214     RPCRT4_DestroyBinding(pbind);
215     msg.Handle = 0;
216     msg.RpcInterfaceInformation = NULL;
217   }
218   else {
219     ERR("got RPC packet to unregistered interface %s\n", debugstr_guid(&hdr->if_id));
220   }
221
222   /* clean up */
223   if (msg.Buffer == buf) msg.Buffer = NULL;
224   TRACE("freeing Buffer=%p\n", buf);
225   HeapFree(GetProcessHeap(), 0, buf);
226   I_RpcFreeBuffer(&msg);
227   msg.Buffer = NULL;
228   TlsSetValue(worker_tls, NULL);
229 }
230
231 static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
232 {
233   DWORD obj;
234   RpcPacket* pkt;
235
236   for (;;) {
237     /* idle timeout after 5s */
238     obj = WaitForSingleObject(server_sem, 5000);
239     if (obj == WAIT_TIMEOUT) {
240       /* if another idle thread exist, self-destruct */
241       if (worker_free > 1) break;
242       continue;
243     }
244     pkt = RPCRT4_pop_packet();
245     if (!pkt) continue;
246     InterlockedDecrement(&worker_free);
247     for (;;) {
248       RPCRT4_process_packet(pkt->conn, &pkt->hdr, pkt->buf);
249       HeapFree(GetProcessHeap(), 0, pkt);
250       /* try to grab another packet here without waiting
251        * on the semaphore, in case it hits max */
252       pkt = RPCRT4_pop_packet();
253       if (!pkt) break;
254       /* decrement semaphore */
255       WaitForSingleObject(server_sem, 0);
256     }
257     InterlockedIncrement(&worker_free);
258   }
259   InterlockedDecrement(&worker_free);
260   InterlockedDecrement(&worker_count);
261   return 0;
262 }
263
264 static void RPCRT4_create_worker_if_needed(void)
265 {
266   if (!worker_free && worker_count < MAX_THREADS) {
267     HANDLE thread;
268     InterlockedIncrement(&worker_count);
269     InterlockedIncrement(&worker_free);
270     thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL);
271     if (thread) CloseHandle(thread);
272     else {
273       InterlockedDecrement(&worker_free);
274       InterlockedDecrement(&worker_count);
275     }
276   }
277 }
278
279 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
280 {
281   RpcConnection* conn = (RpcConnection*)the_arg;
282   RpcPktHdr hdr;
283   DWORD dwRead;
284   void* buf = NULL;
285   RpcPacket* packet;
286
287   TRACE("(%p)\n", conn);
288
289   for (;;) {
290     /* read packet header */
291 #ifdef OVERLAPPED_WORKS
292     if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, &conn->ovl)) {
293       DWORD err = GetLastError();
294       if (err != ERROR_IO_PENDING) {
295         TRACE("connection lost, error=%08lx\n", err);
296         break;
297       }
298       if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) break;
299     }
300 #else
301     if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
302       TRACE("connection lost, error=%08lx\n", GetLastError());
303       break;
304     }
305 #endif
306     if (dwRead != sizeof(hdr)) {
307       if (dwRead) TRACE("protocol error: <hdrsz == %d, dwRead == %lu>\n", sizeof(hdr), dwRead);
308       break;
309     }
310
311     /* read packet body */
312     buf = HeapAlloc(GetProcessHeap(), 0, hdr.len);
313     TRACE("receiving payload=%d\n", hdr.len);
314     if (!hdr.len) dwRead = 0; else
315 #ifdef OVERLAPPED_WORKS
316     if (!ReadFile(conn->conn, buf, hdr.len, &dwRead, &conn->ovl)) {
317       DWORD err = GetLastError();
318       if (err != ERROR_IO_PENDING) {
319         TRACE("connection lost, error=%08lx\n", err);
320         break;
321       }
322       if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) break;
323     }
324 #else
325     if (!ReadFile(conn->conn, buf, hdr.len, &dwRead, NULL)) {
326       TRACE("connection lost, error=%08lx\n", GetLastError());
327       break;
328     }
329 #endif
330     if (dwRead != hdr.len) {
331       TRACE("protocol error: <bodylen == %d, dwRead == %lu>\n", hdr.len, dwRead);
332       break;
333     }
334
335 #if 0
336     RPCRT4_process_packet(conn, &hdr, buf);
337 #else
338     packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
339     packet->conn = conn;
340     packet->hdr = hdr;
341     packet->buf = buf;
342     RPCRT4_create_worker_if_needed();
343     RPCRT4_push_packet(packet);
344     ReleaseSemaphore(server_sem, 1, NULL);
345 #endif
346     buf = NULL;
347   }
348   if (buf) HeapFree(GetProcessHeap(), 0, buf);
349   RPCRT4_DestroyConnection(conn);
350   return 0;
351 }
352
353 static void RPCRT4_new_client(RpcConnection* conn)
354 {
355   HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
356   if (!thread) {
357     DWORD err = GetLastError();
358     ERR("failed to create thread, error=%08lx\n", err);
359     RPCRT4_DestroyConnection(conn);
360   }
361   /* we could set conn->thread, but then we'd have to make the io_thread wait
362    * for that, otherwise the thread might finish, destroy the connection, and
363    * free the memory we'd write to before we did, causing crashes and stuff -
364    * so let's implement that later, when we really need conn->thread */
365
366   CloseHandle( thread );
367 }
368
369 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
370 {
371   HANDLE m_event = mgr_event, b_handle;
372   HANDLE *objs = NULL;
373   DWORD count, res;
374   RpcServerProtseq* cps;
375   RpcConnection* conn;
376   RpcConnection* cconn;
377
378   TRACE("(the_arg == ^%p)\n", the_arg);
379
380   for (;;) {
381     EnterCriticalSection(&server_cs);
382     /* open and count connections */
383     count = 1;
384     cps = protseqs;
385     while (cps) {
386       conn = cps->conn;
387       while (conn) {
388         RPCRT4_OpenConnection(conn);
389         if (conn->ovl.hEvent) count++;
390         conn = conn->Next;
391       }
392       cps = cps->Next;
393     }
394     /* make array of connections */
395     if (objs)
396         objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
397     else
398         objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE));
399
400     objs[0] = m_event;
401     count = 1;
402     cps = protseqs;
403     while (cps) {
404       conn = cps->conn;
405       while (conn) {
406         if (conn->ovl.hEvent) objs[count++] = conn->ovl.hEvent;
407         conn = conn->Next;
408       }
409       cps = cps->Next;
410     }
411     LeaveCriticalSection(&server_cs);
412
413     /* start waiting */
414     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
415     if (res == WAIT_OBJECT_0) {
416       ResetEvent(m_event);
417       if (!std_listen) break;
418     }
419     else if (res == WAIT_FAILED) {
420       ERR("wait failed\n");
421     }
422     else {
423       b_handle = objs[res - WAIT_OBJECT_0];
424       /* find which connection got a RPC */
425       EnterCriticalSection(&server_cs);
426       conn = NULL;
427       cps = protseqs;
428       while (cps) {
429         conn = cps->conn;
430         while (conn) {
431           if (conn->ovl.hEvent == b_handle) break;
432           conn = conn->Next;
433         }
434         if (conn) break;
435         cps = cps->Next;
436       }
437       cconn = NULL;
438       if (conn) RPCRT4_SpawnConnection(&cconn, conn);
439       LeaveCriticalSection(&server_cs);
440       if (!conn) {
441         ERR("failed to locate connection for handle %p\n", b_handle);
442       }
443       if (cconn) RPCRT4_new_client(cconn);
444     }
445   }
446   HeapFree(GetProcessHeap(), 0, objs);
447   EnterCriticalSection(&server_cs);
448   /* close connections */
449   cps = protseqs;
450   while (cps) {
451     conn = cps->conn;
452     while (conn) {
453       RPCRT4_CloseConnection(conn);
454       conn = conn->Next;
455     }
456     cps = cps->Next;
457   }
458   LeaveCriticalSection(&server_cs);
459   return 0;
460 }
461
462 static void RPCRT4_start_listen(void)
463 {
464   TRACE("\n");
465
466   EnterCriticalSection(&listen_cs);
467   if (! ++listen_count) {
468     if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL);
469     if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL);
470     if (!worker_tls) worker_tls = TlsAlloc();
471     std_listen = TRUE;
472     server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
473     LeaveCriticalSection(&listen_cs);
474   } else {
475     LeaveCriticalSection(&listen_cs);
476     SetEvent(mgr_event);
477   }
478 }
479
480 static void RPCRT4_stop_listen(void)
481 {
482   EnterCriticalSection(&listen_cs);
483   if (listen_count == -1)
484     LeaveCriticalSection(&listen_cs);
485   else if (--listen_count == -1) {
486     std_listen = FALSE;
487     LeaveCriticalSection(&listen_cs);
488     SetEvent(mgr_event);
489   } else
490     LeaveCriticalSection(&listen_cs);
491   assert(listen_count > -2);
492 }
493
494 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
495 {
496   RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);
497
498   EnterCriticalSection(&server_cs);
499   ps->Next = protseqs;
500   protseqs = ps;
501   LeaveCriticalSection(&server_cs);
502
503   if (std_listen) SetEvent(mgr_event);
504
505   return RPC_S_OK;
506 }
507
508 /***********************************************************************
509  *             RpcServerInqBindings (RPCRT4.@)
510  */
511 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
512 {
513   RPC_STATUS status;
514   DWORD count;
515   RpcServerProtseq* ps;
516   RpcConnection* conn;
517
518   if (BindingVector)
519     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
520   else
521     ERR("(BindingVector == NULL!!?)\n");
522
523   EnterCriticalSection(&server_cs);
524   /* count connections */
525   count = 0;
526   ps = protseqs;
527   while (ps) {
528     conn = ps->conn;
529     while (conn) {
530       count++;
531       conn = conn->Next;
532     }
533     ps = ps->Next;
534   }
535   if (count) {
536     /* export bindings */
537     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
538                               sizeof(RPC_BINDING_VECTOR) +
539                               sizeof(RPC_BINDING_HANDLE)*(count-1));
540     (*BindingVector)->Count = count;
541     count = 0;
542     ps = protseqs;
543     while (ps) {
544       conn = ps->conn;
545       while (conn) {
546        RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
547                           conn);
548        count++;
549        conn = conn->Next;
550       }
551       ps = ps->Next;
552     }
553     status = RPC_S_OK;
554   } else {
555     *BindingVector = NULL;
556     status = RPC_S_NO_BINDINGS;
557   }
558   LeaveCriticalSection(&server_cs);
559   return status;
560 }
561
562 /***********************************************************************
563  *             RpcServerUseProtseqEpA (RPCRT4.@)
564  */
565 RPC_STATUS WINAPI RpcServerUseProtseqEpA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor )
566 {
567   RPC_POLICY policy;
568   
569   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
570   
571   /* This should provide the default behaviour */
572   policy.Length        = sizeof( policy );
573   policy.EndpointFlags = 0;
574   policy.NICFlags      = 0;
575   
576   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
577 }
578
579 /***********************************************************************
580  *             RpcServerUseProtseqEpW (RPCRT4.@)
581  */
582 RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
583 {
584   RPC_POLICY policy;
585   
586   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
587   
588   /* This should provide the default behaviour */
589   policy.Length        = sizeof( policy );
590   policy.EndpointFlags = 0;
591   policy.NICFlags      = 0;
592   
593   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
594 }
595
596 /***********************************************************************
597  *             RpcServerUseProtseqEpExA (RPCRT4.@)
598  */
599 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor,
600                                             PRPC_POLICY lpPolicy )
601 {
602   RpcServerProtseq* ps;
603
604   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls,
605        debugstr_a( Endpoint ), SecurityDescriptor,
606        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
607
608   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
609   ps->MaxCalls = MaxCalls;
610   ps->Protseq = RPCRT4_strdupA(Protseq);
611   ps->Endpoint = RPCRT4_strdupA(Endpoint);
612
613   return RPCRT4_use_protseq(ps);
614 }
615
616 /***********************************************************************
617  *             RpcServerUseProtseqEpExW (RPCRT4.@)
618  */
619 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
620                                             PRPC_POLICY lpPolicy )
621 {
622   RpcServerProtseq* ps;
623
624   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls,
625        debugstr_w( Endpoint ), SecurityDescriptor,
626        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
627
628   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
629   ps->MaxCalls = MaxCalls;
630   ps->Protseq = RPCRT4_strdupWtoA(Protseq);
631   ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);
632
633   return RPCRT4_use_protseq(ps);
634 }
635
636 /***********************************************************************
637  *             RpcServerUseProtseqA (RPCRT4.@)
638  */
639 RPC_STATUS WINAPI RpcServerUseProtseqA(LPSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
640 {
641   TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)", debugstr_a(Protseq), MaxCalls, SecurityDescriptor);
642   return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor);
643 }
644
645 /***********************************************************************
646  *             RpcServerUseProtseqW (RPCRT4.@)
647  */
648 RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
649 {
650   TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
651   return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor);
652 }
653
654 /***********************************************************************
655  *             RpcServerRegisterIf (RPCRT4.@)
656  */
657 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
658 {
659   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
660   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
661 }
662
663 /***********************************************************************
664  *             RpcServerRegisterIfEx (RPCRT4.@)
665  */
666 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
667                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
668 {
669   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
670   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
671 }
672
673 /***********************************************************************
674  *             RpcServerRegisterIf2 (RPCRT4.@)
675  */
676 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
677                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
678 {
679   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
680   RpcServerInterface* sif;
681   int i;
682
683   TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
684          MaxRpcSize, IfCallbackFn);
685   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
686                                      If->InterfaceId.SyntaxVersion.MajorVersion,
687                                      If->InterfaceId.SyntaxVersion.MinorVersion);
688   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
689                                         If->TransferSyntax.SyntaxVersion.MajorVersion,
690                                         If->TransferSyntax.SyntaxVersion.MinorVersion);
691   TRACE(" dispatch table: %p\n", If->DispatchTable);
692   if (If->DispatchTable) {
693     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
694     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
695       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
696     }
697     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
698   }
699   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
700   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
701   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
702   TRACE(" flags: %08x\n", If->Flags);
703
704   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
705   sif->If           = If;
706   if (MgrTypeUuid)
707     memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
708   else
709     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
710   sif->MgrEpv       = MgrEpv;
711   sif->Flags        = Flags;
712   sif->MaxCalls     = MaxCalls;
713   sif->MaxRpcSize   = MaxRpcSize;
714   sif->IfCallbackFn = IfCallbackFn;
715
716   EnterCriticalSection(&server_cs);
717   sif->Next = ifs;
718   ifs = sif;
719   LeaveCriticalSection(&server_cs);
720
721   if (sif->Flags & RPC_IF_AUTOLISTEN) {
722     /* well, start listening, I think... */
723     RPCRT4_start_listen();
724   }
725
726   return RPC_S_OK;
727 }
728
729 /***********************************************************************
730  *             RpcServerUnregisterIf (RPCRT4.@)
731  */
732 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
733 {
734   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n",
735     IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
736
737   return RPC_S_OK;
738 }
739
740 /***********************************************************************
741  *             RpcServerUnregisterIfEx (RPCRT4.@)
742  */
743 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
744 {
745   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
746     IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
747
748   return RPC_S_OK;
749 }
750
751 /***********************************************************************
752  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
753  */
754 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( LPSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
755                             LPVOID Arg )
756 {
757   FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
758   
759   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
760 }
761
762 /***********************************************************************
763  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
764  */
765 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
766                             LPVOID Arg )
767 {
768   FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
769   
770   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
771 }
772
773 /***********************************************************************
774  *             RpcServerListen (RPCRT4.@)
775  */
776 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
777 {
778   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
779
780   if (!protseqs)
781     return RPC_S_NO_PROTSEQS_REGISTERED;
782
783   EnterCriticalSection(&listen_cs);
784
785   if (std_listen) {
786     LeaveCriticalSection(&listen_cs);
787     return RPC_S_ALREADY_LISTENING;
788   }
789
790   RPCRT4_start_listen();
791
792   LeaveCriticalSection(&listen_cs);
793
794   if (DontWait) return RPC_S_OK;
795
796   return RpcMgmtWaitServerListen();
797 }
798
799 /***********************************************************************
800  *             RpcMgmtServerWaitListen (RPCRT4.@)
801  */
802 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
803 {
804   RPC_STATUS rslt = RPC_S_OK;
805
806   TRACE("\n");
807
808   EnterCriticalSection(&listen_cs);
809
810   if (!std_listen)
811     if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK ) {
812       LeaveCriticalSection(&listen_cs);
813       return rslt;
814     }
815   
816   LeaveCriticalSection(&listen_cs);
817
818   while (std_listen) {
819     WaitForSingleObject(mgr_event, INFINITE);
820     if (!std_listen) {
821       Sleep(100); /* don't spin violently */
822       TRACE("spinning.\n");
823     }
824   }
825
826   return rslt;
827 }
828
829 /***********************************************************************
830  *             RpcMgmtStopServerListening (RPCRT4.@)
831  */
832 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
833 {
834   TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
835
836   if (Binding) {
837     FIXME("client-side invocation not implemented.\n");
838     return RPC_S_WRONG_KIND_OF_BINDING;
839   }
840   
841   /* hmm... */
842   EnterCriticalSection(&listen_cs);
843   while (std_listen)
844     RPCRT4_stop_listen();
845   LeaveCriticalSection(&listen_cs);
846
847   return RPC_S_OK;
848 }
849
850 /***********************************************************************
851  *             I_RpcServerStartListening (RPCRT4.@)
852  */
853 RPC_STATUS WINAPI I_RpcServerStartListening( void* hWnd )
854 {
855   FIXME( "(%p): stub\n", hWnd );
856
857   return RPC_S_OK;
858 }
859
860 /***********************************************************************
861  *             I_RpcServerStopListening (RPCRT4.@)
862  */
863 RPC_STATUS WINAPI I_RpcServerStopListening( void )
864 {
865   FIXME( "(): stub\n" );
866
867   return RPC_S_OK;
868 }
869
870 /***********************************************************************
871  *             I_RpcWindowProc (RPCRT4.@)
872  */
873 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
874 {
875   FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
876
877   return 0;
878 }