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