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