msi: Honor msidbControlAttributesSorted attribute for list box.
[wine] / dlls / rpcrt4 / rpc_transport.c
1 /*
2  * RPC transport layer
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003 Mike Hearn
6  * Copyright 2004 Filip Navara
7  * Copyright 2006 Mike McCormack
8  * Copyright 2006 Damjan Jovanovic
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  */
25
26 #include "config.h"
27
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46 #ifdef HAVE_ARPA_INET_H
47 # include <arpa/inet.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef HAVE_SYS_POLL_H
53 #include <sys/poll.h>
54 #endif
55
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winnls.h"
59 #include "winerror.h"
60 #include "winreg.h"
61 #include "winternl.h"
62 #include "wine/unicode.h"
63
64 #include "rpc.h"
65 #include "rpcndr.h"
66
67 #include "wine/debug.h"
68
69 #include "rpc_binding.h"
70 #include "rpc_message.h"
71 #include "rpc_server.h"
72 #include "epm_towers.h"
73
74 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
75
76 static CRITICAL_SECTION connection_pool_cs;
77 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
78 {
79     0, 0, &connection_pool_cs,
80     { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
81       0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
82 };
83 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
84
85 static struct list connection_pool = LIST_INIT(connection_pool);
86
87 /**** ncacn_np support ****/
88
89 typedef struct _RpcConnection_np
90 {
91   RpcConnection common;
92   HANDLE pipe;
93   OVERLAPPED ovl;
94   BOOL listening;
95 } RpcConnection_np;
96
97 static RpcConnection *rpcrt4_conn_np_alloc(void)
98 {
99   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
100   if (npc)
101   {
102     npc->pipe = NULL;
103     memset(&npc->ovl, 0, sizeof(npc->ovl));
104     npc->listening = FALSE;
105   }
106   return &npc->common;
107 }
108
109 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
110 {
111   if (npc->listening)
112     return RPC_S_OK;
113
114   npc->listening = TRUE;
115   if (ConnectNamedPipe(npc->pipe, &npc->ovl))
116     return RPC_S_OK;
117
118   if (GetLastError() == ERROR_PIPE_CONNECTED) {
119     SetEvent(npc->ovl.hEvent);
120     return RPC_S_OK;
121   }
122   if (GetLastError() == ERROR_IO_PENDING) {
123     /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
124     return RPC_S_OK;
125   }
126   npc->listening = FALSE;
127   WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
128   return RPC_S_OUT_OF_RESOURCES;
129 }
130
131 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
132 {
133   RpcConnection_np *npc = (RpcConnection_np *) Connection;
134   TRACE("listening on %s\n", pname);
135
136   npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
137                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
138                                PIPE_UNLIMITED_INSTANCES,
139                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
140   if (npc->pipe == INVALID_HANDLE_VALUE) {
141     WARN("CreateNamedPipe failed with error %d\n", GetLastError());
142     if (GetLastError() == ERROR_FILE_EXISTS)
143       return RPC_S_DUPLICATE_ENDPOINT;
144     else
145       return RPC_S_CANT_CREATE_ENDPOINT;
146   }
147
148   memset(&npc->ovl, 0, sizeof(npc->ovl));
149   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
150
151   /* Note: we don't call ConnectNamedPipe here because it must be done in the
152    * server thread as the thread must be alertable */
153   return RPC_S_OK;
154 }
155
156 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
157 {
158   RpcConnection_np *npc = (RpcConnection_np *) Connection;
159   HANDLE pipe;
160   DWORD err, dwMode;
161
162   TRACE("connecting to %s\n", pname);
163
164   while (TRUE) {
165     DWORD dwFlags = 0;
166     if (Connection->QOS)
167     {
168         dwFlags = SECURITY_SQOS_PRESENT;
169         switch (Connection->QOS->qos->ImpersonationType)
170         {
171             case RPC_C_IMP_LEVEL_DEFAULT:
172                 /* FIXME: what to do here? */
173                 break;
174             case RPC_C_IMP_LEVEL_ANONYMOUS:
175                 dwFlags |= SECURITY_ANONYMOUS;
176                 break;
177             case RPC_C_IMP_LEVEL_IDENTIFY:
178                 dwFlags |= SECURITY_IDENTIFICATION;
179                 break;
180             case RPC_C_IMP_LEVEL_IMPERSONATE:
181                 dwFlags |= SECURITY_IMPERSONATION;
182                 break;
183             case RPC_C_IMP_LEVEL_DELEGATE:
184                 dwFlags |= SECURITY_DELEGATION;
185                 break;
186         }
187         if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
188             dwFlags |= SECURITY_CONTEXT_TRACKING;
189     }
190     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
191                        OPEN_EXISTING, dwFlags, 0);
192     if (pipe != INVALID_HANDLE_VALUE) break;
193     err = GetLastError();
194     if (err == ERROR_PIPE_BUSY) {
195       TRACE("connection failed, error=%x\n", err);
196       return RPC_S_SERVER_TOO_BUSY;
197     }
198     if (!wait)
199       return RPC_S_SERVER_UNAVAILABLE;
200     if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
201       err = GetLastError();
202       WARN("connection failed, error=%x\n", err);
203       return RPC_S_SERVER_UNAVAILABLE;
204     }
205   }
206
207   /* success */
208   memset(&npc->ovl, 0, sizeof(npc->ovl));
209   /* pipe is connected; change to message-read mode. */
210   dwMode = PIPE_READMODE_MESSAGE;
211   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
212   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
213   npc->pipe = pipe;
214
215   return RPC_S_OK;
216 }
217
218 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
219 {
220   RpcConnection_np *npc = (RpcConnection_np *) Connection;
221   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
222   RPC_STATUS r;
223   LPSTR pname;
224
225   /* already connected? */
226   if (npc->pipe)
227     return RPC_S_OK;
228
229   /* protseq=ncalrpc: supposed to use NT LPC ports,
230    * but we'll implement it with named pipes for now */
231   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
232   strcat(strcpy(pname, prefix), Connection->Endpoint);
233   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
234   I_RpcFree(pname);
235
236   return r;
237 }
238
239 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
240 {
241   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
242   RPC_STATUS r;
243   LPSTR pname;
244   RpcConnection *Connection;
245
246   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
247                               endpoint, NULL, NULL, NULL, NULL);
248   if (r != RPC_S_OK)
249       return r;
250
251   /* protseq=ncalrpc: supposed to use NT LPC ports,
252    * but we'll implement it with named pipes for now */
253   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
254   strcat(strcpy(pname, prefix), Connection->Endpoint);
255   r = rpcrt4_conn_create_pipe(Connection, pname);
256   I_RpcFree(pname);
257
258   EnterCriticalSection(&protseq->cs);
259   Connection->Next = protseq->conn;
260   protseq->conn = Connection;
261   LeaveCriticalSection(&protseq->cs);
262
263   return r;
264 }
265
266 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
267 {
268   RpcConnection_np *npc = (RpcConnection_np *) Connection;
269   static const char prefix[] = "\\\\.";
270   RPC_STATUS r;
271   LPSTR pname;
272
273   /* already connected? */
274   if (npc->pipe)
275     return RPC_S_OK;
276
277   /* protseq=ncacn_np: named pipes */
278   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
279   strcat(strcpy(pname, prefix), Connection->Endpoint);
280   r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
281   I_RpcFree(pname);
282
283   return r;
284 }
285
286 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
287 {
288   static const char prefix[] = "\\\\.";
289   RPC_STATUS r;
290   LPSTR pname;
291   RpcConnection *Connection;
292
293   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
294                               endpoint, NULL, NULL, NULL, NULL);
295   if (r != RPC_S_OK)
296     return r;
297
298   /* protseq=ncacn_np: named pipes */
299   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
300   strcat(strcpy(pname, prefix), Connection->Endpoint);
301   r = rpcrt4_conn_create_pipe(Connection, pname);
302   I_RpcFree(pname);
303     
304   return r;
305 }
306
307 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
308 {    
309   /* because of the way named pipes work, we'll transfer the connected pipe
310    * to the child, then reopen the server binding to continue listening */
311
312   new_npc->pipe = old_npc->pipe;
313   new_npc->ovl = old_npc->ovl;
314   old_npc->pipe = 0;
315   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
316   old_npc->listening = FALSE;
317 }
318
319 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
320 {
321   RPC_STATUS status;
322   LPSTR pname;
323   static const char prefix[] = "\\\\.";
324
325   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
326
327   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
328   strcat(strcpy(pname, prefix), old_conn->Endpoint);
329   status = rpcrt4_conn_create_pipe(old_conn, pname);
330   I_RpcFree(pname);
331
332   return status;
333 }
334
335 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
336 {
337   RPC_STATUS status;
338   LPSTR pname;
339   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
340
341   TRACE("%s\n", old_conn->Endpoint);
342
343   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
344
345   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
346   strcat(strcpy(pname, prefix), old_conn->Endpoint);
347   status = rpcrt4_conn_create_pipe(old_conn, pname);
348   I_RpcFree(pname);
349     
350   return status;
351 }
352
353 static int rpcrt4_conn_np_read(RpcConnection *Connection,
354                         void *buffer, unsigned int count)
355 {
356   RpcConnection_np *npc = (RpcConnection_np *) Connection;
357   char *buf = buffer;
358   BOOL ret = TRUE;
359   unsigned int bytes_left = count;
360
361   while (bytes_left)
362   {
363     DWORD bytes_read;
364     ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
365     if (!ret || !bytes_read)
366         break;
367     bytes_left -= bytes_read;
368     buf += bytes_read;
369   }
370   return ret ? count : -1;
371 }
372
373 static int rpcrt4_conn_np_write(RpcConnection *Connection,
374                              const void *buffer, unsigned int count)
375 {
376   RpcConnection_np *npc = (RpcConnection_np *) Connection;
377   const char *buf = buffer;
378   BOOL ret = TRUE;
379   unsigned int bytes_left = count;
380
381   while (bytes_left)
382   {
383     DWORD bytes_written;
384     ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
385     if (!ret || !bytes_written)
386         break;
387     bytes_left -= bytes_written;
388     buf += bytes_written;
389   }
390   return ret ? count : -1;
391 }
392
393 static int rpcrt4_conn_np_close(RpcConnection *Connection)
394 {
395   RpcConnection_np *npc = (RpcConnection_np *) Connection;
396   if (npc->pipe) {
397     FlushFileBuffers(npc->pipe);
398     CloseHandle(npc->pipe);
399     npc->pipe = 0;
400   }
401   if (npc->ovl.hEvent) {
402     CloseHandle(npc->ovl.hEvent);
403     npc->ovl.hEvent = 0;
404   }
405   return 0;
406 }
407
408 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
409                                                const char *networkaddr,
410                                                const char *endpoint)
411 {
412     twr_empty_floor_t *smb_floor;
413     twr_empty_floor_t *nb_floor;
414     size_t size;
415     size_t networkaddr_size;
416     size_t endpoint_size;
417
418     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
419
420     networkaddr_size = strlen(networkaddr) + 1;
421     endpoint_size = strlen(endpoint) + 1;
422     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
423
424     if (!tower_data)
425         return size;
426
427     smb_floor = (twr_empty_floor_t *)tower_data;
428
429     tower_data += sizeof(*smb_floor);
430
431     smb_floor->count_lhs = sizeof(smb_floor->protid);
432     smb_floor->protid = EPM_PROTOCOL_SMB;
433     smb_floor->count_rhs = endpoint_size;
434
435     memcpy(tower_data, endpoint, endpoint_size);
436     tower_data += endpoint_size;
437
438     nb_floor = (twr_empty_floor_t *)tower_data;
439
440     tower_data += sizeof(*nb_floor);
441
442     nb_floor->count_lhs = sizeof(nb_floor->protid);
443     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
444     nb_floor->count_rhs = networkaddr_size;
445
446     memcpy(tower_data, networkaddr, networkaddr_size);
447     tower_data += networkaddr_size;
448
449     return size;
450 }
451
452 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
453                                                      size_t tower_size,
454                                                      char **networkaddr,
455                                                      char **endpoint)
456 {
457     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
458     const twr_empty_floor_t *nb_floor;
459
460     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
461
462     if (tower_size < sizeof(*smb_floor))
463         return EPT_S_NOT_REGISTERED;
464
465     tower_data += sizeof(*smb_floor);
466     tower_size -= sizeof(*smb_floor);
467
468     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
469         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
470         (smb_floor->count_rhs > tower_size))
471         return EPT_S_NOT_REGISTERED;
472
473     if (endpoint)
474     {
475         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
476         if (!*endpoint)
477             return RPC_S_OUT_OF_RESOURCES;
478         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
479     }
480     tower_data += smb_floor->count_rhs;
481     tower_size -= smb_floor->count_rhs;
482
483     if (tower_size < sizeof(*nb_floor))
484         return EPT_S_NOT_REGISTERED;
485
486     nb_floor = (const twr_empty_floor_t *)tower_data;
487
488     tower_data += sizeof(*nb_floor);
489     tower_size -= sizeof(*nb_floor);
490
491     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
492         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
493         (nb_floor->count_rhs > tower_size))
494         return EPT_S_NOT_REGISTERED;
495
496     if (networkaddr)
497     {
498         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
499         if (!*networkaddr)
500         {
501             if (endpoint)
502             {
503                 I_RpcFree(*endpoint);
504                 *endpoint = NULL;
505             }
506             return RPC_S_OUT_OF_RESOURCES;
507         }
508         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
509     }
510
511     return RPC_S_OK;
512 }
513
514 typedef struct _RpcServerProtseq_np
515 {
516     RpcServerProtseq common;
517     HANDLE mgr_event;
518 } RpcServerProtseq_np;
519
520 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
521 {
522     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
523     if (ps)
524         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
525     return &ps->common;
526 }
527
528 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
529 {
530     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
531     SetEvent(npps->mgr_event);
532 }
533
534 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
535 {
536     HANDLE *objs = prev_array;
537     RpcConnection_np *conn;
538     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
539     
540     EnterCriticalSection(&protseq->cs);
541     
542     /* open and count connections */
543     *count = 1;
544     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
545     while (conn) {
546         rpcrt4_conn_listen_pipe(conn);
547         if (conn->ovl.hEvent)
548             (*count)++;
549         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
550     }
551     
552     /* make array of connections */
553     if (objs)
554         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
555     else
556         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
557     if (!objs)
558     {
559         ERR("couldn't allocate objs\n");
560         LeaveCriticalSection(&protseq->cs);
561         return NULL;
562     }
563     
564     objs[0] = npps->mgr_event;
565     *count = 1;
566     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
567     while (conn) {
568         if ((objs[*count] = conn->ovl.hEvent))
569             (*count)++;
570         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
571     }
572     LeaveCriticalSection(&protseq->cs);
573     return objs;
574 }
575
576 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
577 {
578     HeapFree(GetProcessHeap(), 0, array);
579 }
580
581 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
582 {
583     HANDLE b_handle;
584     HANDLE *objs = wait_array;
585     DWORD res;
586     RpcConnection *cconn;
587     RpcConnection_np *conn;
588     
589     if (!objs)
590         return -1;
591     
592     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
593     if (res == WAIT_OBJECT_0)
594         return 0;
595     else if (res == WAIT_FAILED)
596     {
597         ERR("wait failed with error %d\n", GetLastError());
598         return -1;
599     }
600     else
601     {
602         b_handle = objs[res - WAIT_OBJECT_0];
603         /* find which connection got a RPC */
604         EnterCriticalSection(&protseq->cs);
605         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
606         while (conn) {
607             if (b_handle == conn->ovl.hEvent) break;
608             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
609         }
610         cconn = NULL;
611         if (conn)
612             RPCRT4_SpawnConnection(&cconn, &conn->common);
613         else
614             ERR("failed to locate connection for handle %p\n", b_handle);
615         LeaveCriticalSection(&protseq->cs);
616         if (cconn)
617         {
618             RPCRT4_new_client(cconn);
619             return 1;
620         }
621         else return -1;
622     }
623 }
624
625 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
626                                               const char *networkaddr,
627                                               const char *endpoint)
628 {
629     twr_empty_floor_t *pipe_floor;
630     size_t size;
631     size_t endpoint_size;
632
633     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
634
635     endpoint_size = strlen(networkaddr) + 1;
636     size = sizeof(*pipe_floor) + endpoint_size;
637
638     if (!tower_data)
639         return size;
640
641     pipe_floor = (twr_empty_floor_t *)tower_data;
642
643     tower_data += sizeof(*pipe_floor);
644
645     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
646     pipe_floor->protid = EPM_PROTOCOL_SMB;
647     pipe_floor->count_rhs = endpoint_size;
648
649     memcpy(tower_data, endpoint, endpoint_size);
650     tower_data += endpoint_size;
651
652     return size;
653 }
654
655 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
656                                                     size_t tower_size,
657                                                     char **networkaddr,
658                                                     char **endpoint)
659 {
660     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
661
662     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
663
664     *networkaddr = NULL;
665     *endpoint = NULL;
666
667     if (tower_size < sizeof(*pipe_floor))
668         return EPT_S_NOT_REGISTERED;
669
670     tower_data += sizeof(*pipe_floor);
671     tower_size -= sizeof(*pipe_floor);
672
673     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
674         (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
675         (pipe_floor->count_rhs > tower_size))
676         return EPT_S_NOT_REGISTERED;
677
678     if (endpoint)
679     {
680         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
681         if (!*endpoint)
682             return RPC_S_OUT_OF_RESOURCES;
683         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
684     }
685
686     return RPC_S_OK;
687 }
688
689 /**** ncacn_ip_tcp support ****/
690
691 typedef struct _RpcConnection_tcp
692 {
693   RpcConnection common;
694   int sock;
695 } RpcConnection_tcp;
696
697 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
698 {
699   RpcConnection_tcp *tcpc;
700   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
701   if (tcpc == NULL)
702     return NULL;
703   tcpc->sock = -1;
704   return &tcpc->common;
705 }
706
707 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
708 {
709   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
710   int sock;
711   int ret;
712   struct addrinfo *ai;
713   struct addrinfo *ai_cur;
714   struct addrinfo hints;
715
716   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
717
718   if (tcpc->sock != -1)
719     return RPC_S_OK;
720
721   hints.ai_flags          = 0;
722   hints.ai_family         = PF_UNSPEC;
723   hints.ai_socktype       = SOCK_STREAM;
724   hints.ai_protocol       = IPPROTO_TCP;
725   hints.ai_addrlen        = 0;
726   hints.ai_addr           = NULL;
727   hints.ai_canonname      = NULL;
728   hints.ai_next           = NULL;
729
730   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
731   if (ret)
732   {
733     ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
734       Connection->Endpoint, gai_strerror(ret));
735     return RPC_S_SERVER_UNAVAILABLE;
736   }
737
738   for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
739   {
740     if (TRACE_ON(rpc))
741     {
742       char host[256];
743       char service[256];
744       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
745         host, sizeof(host), service, sizeof(service),
746         NI_NUMERICHOST | NI_NUMERICSERV);
747       TRACE("trying %s:%s\n", host, service);
748     }
749
750     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
751     if (sock < 0)
752     {
753       WARN("socket() failed: %s\n", strerror(errno));
754       continue;
755     }
756
757     if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
758     {
759       WARN("connect() failed: %s\n", strerror(errno));
760       close(sock);
761       continue;
762     }
763     tcpc->sock = sock;
764
765     freeaddrinfo(ai);
766     TRACE("connected\n");
767     return RPC_S_OK;
768   }
769
770   freeaddrinfo(ai);
771   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
772   return RPC_S_SERVER_UNAVAILABLE;
773 }
774
775 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
776 {
777     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
778     int sock;
779     int ret;
780     struct addrinfo *ai;
781     struct addrinfo *ai_cur;
782     struct addrinfo hints;
783     RpcConnection *first_connection = NULL;
784
785     TRACE("(%p, %s)\n", protseq, endpoint);
786
787     hints.ai_flags          = AI_PASSIVE /* for non-localhost addresses */;
788     hints.ai_family         = PF_UNSPEC;
789     hints.ai_socktype       = SOCK_STREAM;
790     hints.ai_protocol       = IPPROTO_TCP;
791     hints.ai_addrlen        = 0;
792     hints.ai_addr           = NULL;
793     hints.ai_canonname      = NULL;
794     hints.ai_next           = NULL;
795
796     ret = getaddrinfo(NULL, endpoint, &hints, &ai);
797     if (ret)
798     {
799         ERR("getaddrinfo for port %s failed: %s\n", endpoint,
800             gai_strerror(ret));
801         if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
802             return RPC_S_INVALID_ENDPOINT_FORMAT;
803         return RPC_S_CANT_CREATE_ENDPOINT;
804     }
805
806     for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
807     {
808         RpcConnection_tcp *tcpc;
809         RPC_STATUS create_status;
810
811         if (TRACE_ON(rpc))
812         {
813             char host[256];
814             char service[256];
815             getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
816                         host, sizeof(host), service, sizeof(service),
817                         NI_NUMERICHOST | NI_NUMERICSERV);
818             TRACE("trying %s:%s\n", host, service);
819         }
820
821         sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
822         if (sock < 0)
823         {
824             WARN("socket() failed: %s\n", strerror(errno));
825             status = RPC_S_CANT_CREATE_ENDPOINT;
826             continue;
827         }
828
829         ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
830         if (ret < 0)
831         {
832             WARN("bind failed: %s\n", strerror(errno));
833             close(sock);
834             if (errno == EADDRINUSE)
835               status = RPC_S_DUPLICATE_ENDPOINT;
836             else
837               status = RPC_S_CANT_CREATE_ENDPOINT;
838             continue;
839         }
840         create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
841                                                 protseq->Protseq, NULL,
842                                                 endpoint, NULL, NULL, NULL,
843                                                 NULL);
844         if (create_status != RPC_S_OK)
845         {
846             close(sock);
847             status = create_status;
848             continue;
849         }
850
851         tcpc->sock = sock;
852         ret = listen(sock, protseq->MaxCalls);
853         if (ret < 0)
854         {
855             WARN("listen failed: %s\n", strerror(errno));
856             RPCRT4_DestroyConnection(&tcpc->common);
857             status = RPC_S_OUT_OF_RESOURCES;
858             continue;
859         }
860         /* need a non-blocking socket, otherwise accept() has a potential
861          * race-condition (poll() says it is readable, connection drops,
862          * and accept() blocks until the next connection comes...)
863          */
864         ret = fcntl(sock, F_SETFL, O_NONBLOCK);
865         if (ret < 0)
866         {
867             WARN("couldn't make socket non-blocking, error %d\n", ret);
868             RPCRT4_DestroyConnection(&tcpc->common);
869             status = RPC_S_OUT_OF_RESOURCES;
870             continue;
871         }
872
873         tcpc->common.Next = first_connection;
874         first_connection = &tcpc->common;
875     }
876
877     freeaddrinfo(ai);
878
879     /* if at least one connection was created for an endpoint then
880      * return success */
881     if (first_connection)
882     {
883         RpcConnection *conn;
884
885         /* find last element in list */
886         for (conn = first_connection; conn->Next; conn = conn->Next)
887             ;
888
889         EnterCriticalSection(&protseq->cs);
890         conn->Next = protseq->conn;
891         protseq->conn = first_connection;
892         LeaveCriticalSection(&protseq->cs);
893         
894         TRACE("listening on %s\n", endpoint);
895         return RPC_S_OK;
896     }
897
898     ERR("couldn't listen on port %s\n", endpoint);
899     return status;
900 }
901
902 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
903 {
904   int ret;
905   struct sockaddr_in address;
906   socklen_t addrsize;
907   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
908   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
909
910   addrsize = sizeof(address);
911   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
912   if (ret < 0)
913   {
914     ERR("Failed to accept a TCP connection: error %d\n", ret);
915     return RPC_S_OUT_OF_RESOURCES;
916   }
917   /* reset to blocking behaviour */
918   fcntl(ret, F_SETFL, 0);
919   client->sock = ret;
920   TRACE("Accepted a new TCP connection\n");
921   return RPC_S_OK;
922 }
923
924 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
925                                 void *buffer, unsigned int count)
926 {
927   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
928   int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
929   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
930   return r;
931 }
932
933 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
934                                  const void *buffer, unsigned int count)
935 {
936   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
937   int r = write(tcpc->sock, buffer, count);
938   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
939   return r;
940 }
941
942 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
943 {
944   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
945
946   TRACE("%d\n", tcpc->sock);
947
948   if (tcpc->sock != -1)
949     close(tcpc->sock);
950   tcpc->sock = -1;
951   return 0;
952 }
953
954 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
955                                                    const char *networkaddr,
956                                                    const char *endpoint)
957 {
958     twr_tcp_floor_t *tcp_floor;
959     twr_ipv4_floor_t *ipv4_floor;
960     struct addrinfo *ai;
961     struct addrinfo hints;
962     int ret;
963     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
964
965     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
966
967     if (!tower_data)
968         return size;
969
970     tcp_floor = (twr_tcp_floor_t *)tower_data;
971     tower_data += sizeof(*tcp_floor);
972
973     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
974
975     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
976     tcp_floor->protid = EPM_PROTOCOL_TCP;
977     tcp_floor->count_rhs = sizeof(tcp_floor->port);
978
979     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
980     ipv4_floor->protid = EPM_PROTOCOL_IP;
981     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
982
983     hints.ai_flags          = AI_NUMERICHOST;
984     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
985     hints.ai_family         = PF_INET;
986     hints.ai_socktype       = SOCK_STREAM;
987     hints.ai_protocol       = IPPROTO_TCP;
988     hints.ai_addrlen        = 0;
989     hints.ai_addr           = NULL;
990     hints.ai_canonname      = NULL;
991     hints.ai_next           = NULL;
992
993     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
994     if (ret)
995     {
996         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
997         if (ret)
998         {
999             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1000             return 0;
1001         }
1002     }
1003
1004     if (ai->ai_family == PF_INET)
1005     {
1006         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1007         tcp_floor->port = sin->sin_port;
1008         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1009     }
1010     else
1011     {
1012         ERR("unexpected protocol family %d\n", ai->ai_family);
1013         return 0;
1014     }
1015
1016     freeaddrinfo(ai);
1017
1018     return size;
1019 }
1020
1021 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1022                                                          size_t tower_size,
1023                                                          char **networkaddr,
1024                                                          char **endpoint)
1025 {
1026     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1027     const twr_ipv4_floor_t *ipv4_floor;
1028     struct in_addr in_addr;
1029
1030     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1031
1032     if (tower_size < sizeof(*tcp_floor))
1033         return EPT_S_NOT_REGISTERED;
1034
1035     tower_data += sizeof(*tcp_floor);
1036     tower_size -= sizeof(*tcp_floor);
1037
1038     if (tower_size < sizeof(*ipv4_floor))
1039         return EPT_S_NOT_REGISTERED;
1040
1041     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1042
1043     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1044         (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1045         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1046         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1047         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1048         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1049         return EPT_S_NOT_REGISTERED;
1050
1051     if (endpoint)
1052     {
1053         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1054         if (!*endpoint)
1055             return RPC_S_OUT_OF_RESOURCES;
1056         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1057     }
1058
1059     if (networkaddr)
1060     {
1061         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1062         if (!*networkaddr)
1063         {
1064             if (endpoint)
1065             {
1066                 I_RpcFree(*endpoint);
1067                 *endpoint = NULL;
1068             }
1069             return RPC_S_OUT_OF_RESOURCES;
1070         }
1071         in_addr.s_addr = ipv4_floor->ipv4addr;
1072         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1073         {
1074             ERR("inet_ntop: %s\n", strerror(errno));
1075             I_RpcFree(*networkaddr);
1076             *networkaddr = NULL;
1077             if (endpoint)
1078             {
1079                 I_RpcFree(*endpoint);
1080                 *endpoint = NULL;
1081             }
1082             return EPT_S_NOT_REGISTERED;
1083         }
1084     }
1085
1086     return RPC_S_OK;
1087 }
1088
1089 typedef struct _RpcServerProtseq_sock
1090 {
1091     RpcServerProtseq common;
1092     int mgr_event_rcv;
1093     int mgr_event_snd;
1094 } RpcServerProtseq_sock;
1095
1096 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1097 {
1098     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1099     if (ps)
1100     {
1101         int fds[2];
1102         if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1103         {
1104             fcntl(fds[0], F_SETFL, O_NONBLOCK);
1105             fcntl(fds[1], F_SETFL, O_NONBLOCK);
1106             ps->mgr_event_rcv = fds[0];
1107             ps->mgr_event_snd = fds[1];
1108         }
1109         else
1110         {
1111             ERR("socketpair failed with error %s\n", strerror(errno));
1112             HeapFree(GetProcessHeap(), 0, ps);
1113             return NULL;
1114         }
1115     }
1116     return &ps->common;
1117 }
1118
1119 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1120 {
1121     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1122     char dummy = 1;
1123     write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1124 }
1125
1126 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1127 {
1128     struct pollfd *poll_info = prev_array;
1129     RpcConnection_tcp *conn;
1130     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1131
1132     EnterCriticalSection(&protseq->cs);
1133     
1134     /* open and count connections */
1135     *count = 1;
1136     conn = (RpcConnection_tcp *)protseq->conn;
1137     while (conn) {
1138         if (conn->sock != -1)
1139             (*count)++;
1140         conn = (RpcConnection_tcp *)conn->common.Next;
1141     }
1142     
1143     /* make array of connections */
1144     if (poll_info)
1145         poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1146     else
1147         poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1148     if (!poll_info)
1149     {
1150         ERR("couldn't allocate poll_info\n");
1151         LeaveCriticalSection(&protseq->cs);
1152         return NULL;
1153     }
1154
1155     poll_info[0].fd = sockps->mgr_event_rcv;
1156     poll_info[0].events = POLLIN;
1157     *count = 1;
1158     conn =  CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1159     while (conn) {
1160         if (conn->sock != -1)
1161         {
1162             poll_info[*count].fd = conn->sock;
1163             poll_info[*count].events = POLLIN;
1164             (*count)++;
1165         }
1166         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1167     }
1168     LeaveCriticalSection(&protseq->cs);
1169     return poll_info;
1170 }
1171
1172 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1173 {
1174     HeapFree(GetProcessHeap(), 0, array);
1175 }
1176
1177 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1178 {
1179     struct pollfd *poll_info = wait_array;
1180     int ret, i;
1181     RpcConnection *cconn;
1182     RpcConnection_tcp *conn;
1183     
1184     if (!poll_info)
1185         return -1;
1186     
1187     ret = poll(poll_info, count, -1);
1188     if (ret < 0)
1189     {
1190         ERR("poll failed with error %d\n", ret);
1191         return -1;
1192     }
1193
1194     for (i = 0; i < count; i++)
1195         if (poll_info[i].revents & POLLIN)
1196         {
1197             /* RPC server event */
1198             if (i == 0)
1199             {
1200                 char dummy;
1201                 read(poll_info[0].fd, &dummy, sizeof(dummy));
1202                 return 0;
1203             }
1204
1205             /* find which connection got a RPC */
1206             EnterCriticalSection(&protseq->cs);
1207             conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1208             while (conn) {
1209                 if (poll_info[i].fd == conn->sock) break;
1210                 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1211             }
1212             cconn = NULL;
1213             if (conn)
1214                 RPCRT4_SpawnConnection(&cconn, &conn->common);
1215             else
1216                 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1217             LeaveCriticalSection(&protseq->cs);
1218             if (cconn)
1219                 RPCRT4_new_client(cconn);
1220             else
1221                 return -1;
1222         }
1223
1224     return 1;
1225 }
1226
1227 static const struct connection_ops conn_protseq_list[] = {
1228   { "ncacn_np",
1229     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1230     rpcrt4_conn_np_alloc,
1231     rpcrt4_ncacn_np_open,
1232     rpcrt4_ncacn_np_handoff,
1233     rpcrt4_conn_np_read,
1234     rpcrt4_conn_np_write,
1235     rpcrt4_conn_np_close,
1236     rpcrt4_ncacn_np_get_top_of_tower,
1237     rpcrt4_ncacn_np_parse_top_of_tower,
1238   },
1239   { "ncalrpc",
1240     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1241     rpcrt4_conn_np_alloc,
1242     rpcrt4_ncalrpc_open,
1243     rpcrt4_ncalrpc_handoff,
1244     rpcrt4_conn_np_read,
1245     rpcrt4_conn_np_write,
1246     rpcrt4_conn_np_close,
1247     rpcrt4_ncalrpc_get_top_of_tower,
1248     rpcrt4_ncalrpc_parse_top_of_tower,
1249   },
1250   { "ncacn_ip_tcp",
1251     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1252     rpcrt4_conn_tcp_alloc,
1253     rpcrt4_ncacn_ip_tcp_open,
1254     rpcrt4_conn_tcp_handoff,
1255     rpcrt4_conn_tcp_read,
1256     rpcrt4_conn_tcp_write,
1257     rpcrt4_conn_tcp_close,
1258     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1259     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1260   }
1261 };
1262
1263
1264 static const struct protseq_ops protseq_list[] =
1265 {
1266     {
1267         "ncacn_np",
1268         rpcrt4_protseq_np_alloc,
1269         rpcrt4_protseq_np_signal_state_changed,
1270         rpcrt4_protseq_np_get_wait_array,
1271         rpcrt4_protseq_np_free_wait_array,
1272         rpcrt4_protseq_np_wait_for_new_connection,
1273         rpcrt4_protseq_ncacn_np_open_endpoint,
1274     },
1275     {
1276         "ncalrpc",
1277         rpcrt4_protseq_np_alloc,
1278         rpcrt4_protseq_np_signal_state_changed,
1279         rpcrt4_protseq_np_get_wait_array,
1280         rpcrt4_protseq_np_free_wait_array,
1281         rpcrt4_protseq_np_wait_for_new_connection,
1282         rpcrt4_protseq_ncalrpc_open_endpoint,
1283     },
1284     {
1285         "ncacn_ip_tcp",
1286         rpcrt4_protseq_sock_alloc,
1287         rpcrt4_protseq_sock_signal_state_changed,
1288         rpcrt4_protseq_sock_get_wait_array,
1289         rpcrt4_protseq_sock_free_wait_array,
1290         rpcrt4_protseq_sock_wait_for_new_connection,
1291         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1292     },
1293 };
1294
1295 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1296
1297 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1298 {
1299   int i;
1300   for(i=0; i<ARRAYSIZE(protseq_list); i++)
1301     if (!strcmp(protseq_list[i].name, protseq))
1302       return &protseq_list[i];
1303   return NULL;
1304 }
1305
1306 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1307 {
1308     int i;
1309     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1310         if (!strcmp(conn_protseq_list[i].name, protseq))
1311             return &conn_protseq_list[i];
1312     return NULL;
1313 }
1314
1315 /**** interface to rest of code ****/
1316
1317 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1318 {
1319   TRACE("(Connection == ^%p)\n", Connection);
1320
1321   assert(!Connection->server);
1322   return Connection->ops->open_connection_client(Connection);
1323 }
1324
1325 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1326 {
1327   TRACE("(Connection == ^%p)\n", Connection);
1328   if (SecIsValidHandle(&Connection->ctx))
1329   {
1330     DeleteSecurityContext(&Connection->ctx);
1331     SecInvalidateHandle(&Connection->ctx);
1332   }
1333   rpcrt4_conn_close(Connection);
1334   return RPC_S_OK;
1335 }
1336
1337 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1338     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1339     LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS,
1340     RpcBinding* Binding)
1341 {
1342   const struct connection_ops *ops;
1343   RpcConnection* NewConnection;
1344
1345   ops = rpcrt4_get_conn_protseq_ops(Protseq);
1346   if (!ops)
1347   {
1348     FIXME("not supported for protseq %s\n", Protseq);
1349     return RPC_S_PROTSEQ_NOT_SUPPORTED;
1350   }
1351
1352   NewConnection = ops->alloc();
1353   NewConnection->Next = NULL;
1354   NewConnection->server = server;
1355   NewConnection->ops = ops;
1356   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1357   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1358   NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1359   NewConnection->Used = Binding;
1360   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1361   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1362   NewConnection->NextCallId = 1;
1363
1364   SecInvalidateHandle(&NewConnection->ctx);
1365   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1366   NewConnection->AuthInfo = AuthInfo;
1367   if (QOS) RpcQualityOfService_AddRef(QOS);
1368   NewConnection->QOS = QOS;
1369   list_init(&NewConnection->conn_pool_entry);
1370
1371   TRACE("connection: %p\n", NewConnection);
1372   *Connection = NewConnection;
1373
1374   return RPC_S_OK;
1375 }
1376
1377 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1378     const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1379     LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS)
1380 {
1381   RpcConnection *Connection;
1382   /* try to find a compatible connection from the connection pool */
1383   EnterCriticalSection(&connection_pool_cs);
1384   LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1385     if ((Connection->AuthInfo == AuthInfo) &&
1386         (Connection->QOS == QOS) &&
1387         !memcmp(&Connection->ActiveInterface, InterfaceId,
1388            sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1389         !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1390         !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1391         !strcmp(Connection->Endpoint, Endpoint))
1392     {
1393       list_remove(&Connection->conn_pool_entry);
1394       LeaveCriticalSection(&connection_pool_cs);
1395       TRACE("got connection from pool %p\n", Connection);
1396       return Connection;
1397     }
1398
1399   LeaveCriticalSection(&connection_pool_cs);
1400   return NULL;
1401 }
1402
1403 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1404 {
1405   assert(!Connection->server);
1406   EnterCriticalSection(&connection_pool_cs);
1407   list_add_head(&connection_pool, &Connection->conn_pool_entry);
1408   LeaveCriticalSection(&connection_pool_cs);
1409 }
1410
1411
1412 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1413 {
1414   RPC_STATUS err;
1415
1416   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1417                                 rpcrt4_conn_get_name(OldConnection),
1418                                 OldConnection->NetworkAddr,
1419                                 OldConnection->Endpoint, NULL,
1420                                 OldConnection->AuthInfo, OldConnection->QOS,
1421                                 NULL);
1422   if (err == RPC_S_OK)
1423     rpcrt4_conn_handoff(OldConnection, *Connection);
1424   return err;
1425 }
1426
1427 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1428 {
1429   TRACE("connection: %p\n", Connection);
1430
1431   RPCRT4_CloseConnection(Connection);
1432   RPCRT4_strfree(Connection->Endpoint);
1433   RPCRT4_strfree(Connection->NetworkAddr);
1434   HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
1435   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1436   if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
1437   HeapFree(GetProcessHeap(), 0, Connection);
1438   return RPC_S_OK;
1439 }
1440
1441 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1442                                       size_t *tower_size,
1443                                       const char *protseq,
1444                                       const char *networkaddr,
1445                                       const char *endpoint)
1446 {
1447     twr_empty_floor_t *protocol_floor;
1448     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1449
1450     *tower_size = 0;
1451
1452     if (!protseq_ops)
1453         return RPC_S_INVALID_RPC_PROTSEQ;
1454
1455     if (!tower_data)
1456     {
1457         *tower_size = sizeof(*protocol_floor);
1458         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1459         return RPC_S_OK;
1460     }
1461
1462     protocol_floor = (twr_empty_floor_t *)tower_data;
1463     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1464     protocol_floor->protid = protseq_ops->epm_protocols[0];
1465     protocol_floor->count_rhs = 0;
1466
1467     tower_data += sizeof(*protocol_floor);
1468
1469     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1470     if (!*tower_size)
1471         return EPT_S_NOT_REGISTERED;
1472
1473     *tower_size += sizeof(*protocol_floor);
1474
1475     return RPC_S_OK;
1476 }
1477
1478 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1479                                         size_t tower_size,
1480                                         char **protseq,
1481                                         char **networkaddr,
1482                                         char **endpoint)
1483 {
1484     const twr_empty_floor_t *protocol_floor;
1485     const twr_empty_floor_t *floor4;
1486     const struct connection_ops *protseq_ops = NULL;
1487     RPC_STATUS status;
1488     int i;
1489
1490     if (tower_size < sizeof(*protocol_floor))
1491         return EPT_S_NOT_REGISTERED;
1492
1493     protocol_floor = (const twr_empty_floor_t *)tower_data;
1494     tower_data += sizeof(*protocol_floor);
1495     tower_size -= sizeof(*protocol_floor);
1496     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1497         (protocol_floor->count_rhs > tower_size))
1498         return EPT_S_NOT_REGISTERED;
1499     tower_data += protocol_floor->count_rhs;
1500     tower_size -= protocol_floor->count_rhs;
1501
1502     floor4 = (const twr_empty_floor_t *)tower_data;
1503     if ((tower_size < sizeof(*floor4)) ||
1504         (floor4->count_lhs != sizeof(floor4->protid)))
1505         return EPT_S_NOT_REGISTERED;
1506
1507     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1508         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1509             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1510         {
1511             protseq_ops = &conn_protseq_list[i];
1512             break;
1513         }
1514
1515     if (!protseq_ops)
1516         return EPT_S_NOT_REGISTERED;
1517
1518     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1519
1520     if ((status == RPC_S_OK) && protseq)
1521     {
1522         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1523         strcpy(*protseq, protseq_ops->name);
1524     }
1525
1526     return status;
1527 }
1528
1529 /***********************************************************************
1530  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
1531  *
1532  * Checks if the given protocol sequence is known by the RPC system.
1533  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1534  *
1535  */
1536 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1537 {
1538   char ps[0x10];
1539
1540   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1541                       ps, sizeof ps, NULL, NULL);
1542   if (rpcrt4_get_conn_protseq_ops(ps))
1543     return RPC_S_OK;
1544
1545   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1546
1547   return RPC_S_INVALID_RPC_PROTSEQ;
1548 }
1549
1550 /***********************************************************************
1551  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
1552  */
1553 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1554 {
1555   UNICODE_STRING protseqW;
1556
1557   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1558   {
1559     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1560     RtlFreeUnicodeString(&protseqW);
1561     return ret;
1562   }
1563   return RPC_S_OUT_OF_MEMORY;
1564 }