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