rpcrt4: Factor out non-Win32 compatible parts of the ncacn_ip_tcp client code to...
[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 # undef errno
44 # define errno WSAGetLastError()
45 #else
46 # include <errno.h>
47 # ifdef HAVE_UNISTD_H
48 #  include <unistd.h>
49 # endif
50 # include <fcntl.h>
51 # ifdef HAVE_SYS_SOCKET_H
52 #  include <sys/socket.h>
53 # endif
54 # ifdef HAVE_NETINET_IN_H
55 #  include <netinet/in.h>
56 # endif
57 # ifdef HAVE_NETINET_TCP_H
58 #  include <netinet/tcp.h>
59 # endif
60 # ifdef HAVE_ARPA_INET_H
61 #  include <arpa/inet.h>
62 # endif
63 # ifdef HAVE_NETDB_H
64 #  include <netdb.h>
65 # endif
66 # ifdef HAVE_SYS_POLL_H
67 #  include <sys/poll.h>
68 # endif
69 # ifdef HAVE_SYS_FILIO_H
70 #  include <sys/filio.h>
71 # endif
72 # ifdef HAVE_SYS_IOCTL_H
73 #  include <sys/ioctl.h>
74 # endif
75 # define closesocket close
76 # define ioctlsocket ioctl
77 #endif /* defined(__MINGW32__) || defined (_MSC_VER) */
78
79 #include "windef.h"
80 #include "winbase.h"
81 #include "winnls.h"
82 #include "winerror.h"
83 #include "wininet.h"
84 #include "winternl.h"
85 #include "wine/unicode.h"
86
87 #include "rpc.h"
88 #include "rpcndr.h"
89
90 #include "wine/debug.h"
91
92 #include "rpc_binding.h"
93 #include "rpc_assoc.h"
94 #include "rpc_message.h"
95 #include "rpc_server.h"
96 #include "epm_towers.h"
97
98 #ifndef SOL_TCP
99 # define SOL_TCP IPPROTO_TCP
100 #endif
101
102 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
103
104 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
105
106 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
107
108 /**** ncacn_np support ****/
109
110 typedef struct _RpcConnection_np
111 {
112   RpcConnection common;
113   HANDLE pipe;
114   OVERLAPPED ovl;
115   BOOL listening;
116 } RpcConnection_np;
117
118 static RpcConnection *rpcrt4_conn_np_alloc(void)
119 {
120   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
121   if (npc)
122   {
123     npc->pipe = NULL;
124     memset(&npc->ovl, 0, sizeof(npc->ovl));
125     npc->listening = FALSE;
126   }
127   return &npc->common;
128 }
129
130 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
131 {
132   if (npc->listening)
133     return RPC_S_OK;
134
135   npc->listening = TRUE;
136   for (;;)
137   {
138       if (ConnectNamedPipe(npc->pipe, &npc->ovl))
139           return RPC_S_OK;
140
141       switch(GetLastError())
142       {
143       case ERROR_PIPE_CONNECTED:
144           SetEvent(npc->ovl.hEvent);
145           return RPC_S_OK;
146       case ERROR_IO_PENDING:
147           /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
148           return RPC_S_OK;
149       case ERROR_NO_DATA_DETECTED:
150           /* client has disconnected, retry */
151           DisconnectNamedPipe( npc->pipe );
152           break;
153       default:
154           npc->listening = FALSE;
155           WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
156           return RPC_S_OUT_OF_RESOURCES;
157       }
158   }
159 }
160
161 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
162 {
163   RpcConnection_np *npc = (RpcConnection_np *) Connection;
164   TRACE("listening on %s\n", pname);
165
166   npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
167                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
168                                PIPE_UNLIMITED_INSTANCES,
169                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
170   if (npc->pipe == INVALID_HANDLE_VALUE) {
171     WARN("CreateNamedPipe failed with error %d\n", GetLastError());
172     if (GetLastError() == ERROR_FILE_EXISTS)
173       return RPC_S_DUPLICATE_ENDPOINT;
174     else
175       return RPC_S_CANT_CREATE_ENDPOINT;
176   }
177
178   memset(&npc->ovl, 0, sizeof(npc->ovl));
179   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
180
181   /* Note: we don't call ConnectNamedPipe here because it must be done in the
182    * server thread as the thread must be alertable */
183   return RPC_S_OK;
184 }
185
186 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
187 {
188   RpcConnection_np *npc = (RpcConnection_np *) Connection;
189   HANDLE pipe;
190   DWORD err, dwMode;
191
192   TRACE("connecting to %s\n", pname);
193
194   while (TRUE) {
195     DWORD dwFlags = 0;
196     if (Connection->QOS)
197     {
198         dwFlags = SECURITY_SQOS_PRESENT;
199         switch (Connection->QOS->qos->ImpersonationType)
200         {
201             case RPC_C_IMP_LEVEL_DEFAULT:
202                 /* FIXME: what to do here? */
203                 break;
204             case RPC_C_IMP_LEVEL_ANONYMOUS:
205                 dwFlags |= SECURITY_ANONYMOUS;
206                 break;
207             case RPC_C_IMP_LEVEL_IDENTIFY:
208                 dwFlags |= SECURITY_IDENTIFICATION;
209                 break;
210             case RPC_C_IMP_LEVEL_IMPERSONATE:
211                 dwFlags |= SECURITY_IMPERSONATION;
212                 break;
213             case RPC_C_IMP_LEVEL_DELEGATE:
214                 dwFlags |= SECURITY_DELEGATION;
215                 break;
216         }
217         if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
218             dwFlags |= SECURITY_CONTEXT_TRACKING;
219     }
220     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
221                        OPEN_EXISTING, dwFlags, 0);
222     if (pipe != INVALID_HANDLE_VALUE) break;
223     err = GetLastError();
224     if (err == ERROR_PIPE_BUSY) {
225       TRACE("connection failed, error=%x\n", err);
226       return RPC_S_SERVER_TOO_BUSY;
227     }
228     if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
229       err = GetLastError();
230       WARN("connection failed, error=%x\n", err);
231       return RPC_S_SERVER_UNAVAILABLE;
232     }
233   }
234
235   /* success */
236   memset(&npc->ovl, 0, sizeof(npc->ovl));
237   /* pipe is connected; change to message-read mode. */
238   dwMode = PIPE_READMODE_MESSAGE;
239   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
240   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
241   npc->pipe = pipe;
242
243   return RPC_S_OK;
244 }
245
246 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
247 {
248   RpcConnection_np *npc = (RpcConnection_np *) Connection;
249   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
250   RPC_STATUS r;
251   LPSTR pname;
252
253   /* already connected? */
254   if (npc->pipe)
255     return RPC_S_OK;
256
257   /* protseq=ncalrpc: supposed to use NT LPC ports,
258    * but we'll implement it with named pipes for now */
259   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
260   strcat(strcpy(pname, prefix), Connection->Endpoint);
261   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
262   I_RpcFree(pname);
263
264   return r;
265 }
266
267 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
268 {
269   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
270   RPC_STATUS r;
271   LPSTR pname;
272   RpcConnection *Connection;
273   char generated_endpoint[22];
274
275   if (!endpoint)
276   {
277     static LONG lrpc_nameless_id;
278     DWORD process_id = GetCurrentProcessId();
279     ULONG id = InterlockedIncrement(&lrpc_nameless_id);
280     snprintf(generated_endpoint, sizeof(generated_endpoint),
281              "LRPC%08x.%08x", process_id, id);
282     endpoint = generated_endpoint;
283   }
284
285   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
286                               endpoint, NULL, NULL, NULL);
287   if (r != RPC_S_OK)
288       return r;
289
290   /* protseq=ncalrpc: supposed to use NT LPC ports,
291    * but we'll implement it with named pipes for now */
292   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
293   strcat(strcpy(pname, prefix), Connection->Endpoint);
294   r = rpcrt4_conn_create_pipe(Connection, pname);
295   I_RpcFree(pname);
296
297   EnterCriticalSection(&protseq->cs);
298   Connection->Next = protseq->conn;
299   protseq->conn = Connection;
300   LeaveCriticalSection(&protseq->cs);
301
302   return r;
303 }
304
305 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
306 {
307   RpcConnection_np *npc = (RpcConnection_np *) Connection;
308   static const char prefix[] = "\\\\.";
309   RPC_STATUS r;
310   LPSTR pname;
311
312   /* already connected? */
313   if (npc->pipe)
314     return RPC_S_OK;
315
316   /* protseq=ncacn_np: named pipes */
317   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
318   strcat(strcpy(pname, prefix), Connection->Endpoint);
319   r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
320   I_RpcFree(pname);
321
322   return r;
323 }
324
325 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
326 {
327   static const char prefix[] = "\\\\.";
328   RPC_STATUS r;
329   LPSTR pname;
330   RpcConnection *Connection;
331   char generated_endpoint[21];
332
333   if (!endpoint)
334   {
335     static LONG np_nameless_id;
336     DWORD process_id = GetCurrentProcessId();
337     ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
338     snprintf(generated_endpoint, sizeof(generated_endpoint),
339              "\\\\pipe\\\\%08x.%03x", process_id, id);
340     endpoint = generated_endpoint;
341   }
342
343   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
344                               endpoint, NULL, NULL, NULL);
345   if (r != RPC_S_OK)
346     return r;
347
348   /* protseq=ncacn_np: named pipes */
349   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
350   strcat(strcpy(pname, prefix), Connection->Endpoint);
351   r = rpcrt4_conn_create_pipe(Connection, pname);
352   I_RpcFree(pname);
353
354   EnterCriticalSection(&protseq->cs);
355   Connection->Next = protseq->conn;
356   protseq->conn = Connection;
357   LeaveCriticalSection(&protseq->cs);
358
359   return r;
360 }
361
362 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
363 {    
364   /* because of the way named pipes work, we'll transfer the connected pipe
365    * to the child, then reopen the server binding to continue listening */
366
367   new_npc->pipe = old_npc->pipe;
368   new_npc->ovl = old_npc->ovl;
369   old_npc->pipe = 0;
370   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
371   old_npc->listening = FALSE;
372 }
373
374 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
375 {
376   RPC_STATUS status;
377   LPSTR pname;
378   static const char prefix[] = "\\\\.";
379
380   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
381
382   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
383   strcat(strcpy(pname, prefix), old_conn->Endpoint);
384   status = rpcrt4_conn_create_pipe(old_conn, pname);
385   I_RpcFree(pname);
386
387   return status;
388 }
389
390 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
391 {
392   RPC_STATUS status;
393   LPSTR pname;
394   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
395
396   TRACE("%s\n", old_conn->Endpoint);
397
398   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
399
400   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
401   strcat(strcpy(pname, prefix), old_conn->Endpoint);
402   status = rpcrt4_conn_create_pipe(old_conn, pname);
403   I_RpcFree(pname);
404     
405   return status;
406 }
407
408 static int rpcrt4_conn_np_read(RpcConnection *Connection,
409                         void *buffer, unsigned int count)
410 {
411   RpcConnection_np *npc = (RpcConnection_np *) Connection;
412   char *buf = buffer;
413   BOOL ret = TRUE;
414   unsigned int bytes_left = count;
415
416   while (bytes_left)
417   {
418     DWORD bytes_read;
419     ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
420     if (!ret && GetLastError() == ERROR_MORE_DATA)
421         ret = TRUE;
422     if (!ret || !bytes_read)
423         break;
424     bytes_left -= bytes_read;
425     buf += bytes_read;
426   }
427   return ret ? count : -1;
428 }
429
430 static int rpcrt4_conn_np_write(RpcConnection *Connection,
431                              const void *buffer, unsigned int count)
432 {
433   RpcConnection_np *npc = (RpcConnection_np *) Connection;
434   const char *buf = buffer;
435   BOOL ret = TRUE;
436   unsigned int bytes_left = count;
437
438   while (bytes_left)
439   {
440     DWORD bytes_written;
441     ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, NULL);
442     if (!ret || !bytes_written)
443         break;
444     bytes_left -= bytes_written;
445     buf += bytes_written;
446   }
447   return ret ? count : -1;
448 }
449
450 static int rpcrt4_conn_np_close(RpcConnection *Connection)
451 {
452   RpcConnection_np *npc = (RpcConnection_np *) Connection;
453   if (npc->pipe) {
454     FlushFileBuffers(npc->pipe);
455     CloseHandle(npc->pipe);
456     npc->pipe = 0;
457   }
458   if (npc->ovl.hEvent) {
459     CloseHandle(npc->ovl.hEvent);
460     npc->ovl.hEvent = 0;
461   }
462   return 0;
463 }
464
465 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
466 {
467     /* FIXME: implement when named pipe writes use overlapped I/O */
468 }
469
470 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
471 {
472     /* FIXME: implement when named pipe writes use overlapped I/O */
473     return -1;
474 }
475
476 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
477                                                const char *networkaddr,
478                                                const char *endpoint)
479 {
480     twr_empty_floor_t *smb_floor;
481     twr_empty_floor_t *nb_floor;
482     size_t size;
483     size_t networkaddr_size;
484     size_t endpoint_size;
485
486     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
487
488     networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
489     endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
490     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
491
492     if (!tower_data)
493         return size;
494
495     smb_floor = (twr_empty_floor_t *)tower_data;
496
497     tower_data += sizeof(*smb_floor);
498
499     smb_floor->count_lhs = sizeof(smb_floor->protid);
500     smb_floor->protid = EPM_PROTOCOL_SMB;
501     smb_floor->count_rhs = endpoint_size;
502
503     if (endpoint)
504         memcpy(tower_data, endpoint, endpoint_size);
505     else
506         tower_data[0] = 0;
507     tower_data += endpoint_size;
508
509     nb_floor = (twr_empty_floor_t *)tower_data;
510
511     tower_data += sizeof(*nb_floor);
512
513     nb_floor->count_lhs = sizeof(nb_floor->protid);
514     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
515     nb_floor->count_rhs = networkaddr_size;
516
517     if (networkaddr)
518         memcpy(tower_data, networkaddr, networkaddr_size);
519     else
520         tower_data[0] = 0;
521
522     return size;
523 }
524
525 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
526                                                      size_t tower_size,
527                                                      char **networkaddr,
528                                                      char **endpoint)
529 {
530     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
531     const twr_empty_floor_t *nb_floor;
532
533     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
534
535     if (tower_size < sizeof(*smb_floor))
536         return EPT_S_NOT_REGISTERED;
537
538     tower_data += sizeof(*smb_floor);
539     tower_size -= sizeof(*smb_floor);
540
541     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
542         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
543         (smb_floor->count_rhs > tower_size) ||
544         (tower_data[smb_floor->count_rhs - 1] != '\0'))
545         return EPT_S_NOT_REGISTERED;
546
547     if (endpoint)
548     {
549         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
550         if (!*endpoint)
551             return RPC_S_OUT_OF_RESOURCES;
552         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
553     }
554     tower_data += smb_floor->count_rhs;
555     tower_size -= smb_floor->count_rhs;
556
557     if (tower_size < sizeof(*nb_floor))
558         return EPT_S_NOT_REGISTERED;
559
560     nb_floor = (const twr_empty_floor_t *)tower_data;
561
562     tower_data += sizeof(*nb_floor);
563     tower_size -= sizeof(*nb_floor);
564
565     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
566         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
567         (nb_floor->count_rhs > tower_size) ||
568         (tower_data[nb_floor->count_rhs - 1] != '\0'))
569         return EPT_S_NOT_REGISTERED;
570
571     if (networkaddr)
572     {
573         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
574         if (!*networkaddr)
575         {
576             if (endpoint)
577             {
578                 I_RpcFree(*endpoint);
579                 *endpoint = NULL;
580             }
581             return RPC_S_OUT_OF_RESOURCES;
582         }
583         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
584     }
585
586     return RPC_S_OK;
587 }
588
589 typedef struct _RpcServerProtseq_np
590 {
591     RpcServerProtseq common;
592     HANDLE mgr_event;
593 } RpcServerProtseq_np;
594
595 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
596 {
597     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
598     if (ps)
599         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
600     return &ps->common;
601 }
602
603 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
604 {
605     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
606     SetEvent(npps->mgr_event);
607 }
608
609 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
610 {
611     HANDLE *objs = prev_array;
612     RpcConnection_np *conn;
613     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
614     
615     EnterCriticalSection(&protseq->cs);
616     
617     /* open and count connections */
618     *count = 1;
619     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
620     while (conn) {
621         rpcrt4_conn_listen_pipe(conn);
622         if (conn->ovl.hEvent)
623             (*count)++;
624         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
625     }
626     
627     /* make array of connections */
628     if (objs)
629         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
630     else
631         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
632     if (!objs)
633     {
634         ERR("couldn't allocate objs\n");
635         LeaveCriticalSection(&protseq->cs);
636         return NULL;
637     }
638     
639     objs[0] = npps->mgr_event;
640     *count = 1;
641     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
642     while (conn) {
643         if ((objs[*count] = conn->ovl.hEvent))
644             (*count)++;
645         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
646     }
647     LeaveCriticalSection(&protseq->cs);
648     return objs;
649 }
650
651 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
652 {
653     HeapFree(GetProcessHeap(), 0, array);
654 }
655
656 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
657 {
658     HANDLE b_handle;
659     HANDLE *objs = wait_array;
660     DWORD res;
661     RpcConnection *cconn;
662     RpcConnection_np *conn;
663     
664     if (!objs)
665         return -1;
666
667     do
668     {
669         /* an alertable wait isn't strictly necessary, but due to our
670          * overlapped I/O implementation in Wine we need to free some memory
671          * by the file user APC being called, even if no completion routine was
672          * specified at the time of starting the async operation */
673         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
674     } while (res == WAIT_IO_COMPLETION);
675
676     if (res == WAIT_OBJECT_0)
677         return 0;
678     else if (res == WAIT_FAILED)
679     {
680         ERR("wait failed with error %d\n", GetLastError());
681         return -1;
682     }
683     else
684     {
685         b_handle = objs[res - WAIT_OBJECT_0];
686         /* find which connection got a RPC */
687         EnterCriticalSection(&protseq->cs);
688         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
689         while (conn) {
690             if (b_handle == conn->ovl.hEvent) break;
691             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
692         }
693         cconn = NULL;
694         if (conn)
695             RPCRT4_SpawnConnection(&cconn, &conn->common);
696         else
697             ERR("failed to locate connection for handle %p\n", b_handle);
698         LeaveCriticalSection(&protseq->cs);
699         if (cconn)
700         {
701             RPCRT4_new_client(cconn);
702             return 1;
703         }
704         else return -1;
705     }
706 }
707
708 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
709                                               const char *networkaddr,
710                                               const char *endpoint)
711 {
712     twr_empty_floor_t *pipe_floor;
713     size_t size;
714     size_t endpoint_size;
715
716     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
717
718     endpoint_size = strlen(endpoint) + 1;
719     size = sizeof(*pipe_floor) + endpoint_size;
720
721     if (!tower_data)
722         return size;
723
724     pipe_floor = (twr_empty_floor_t *)tower_data;
725
726     tower_data += sizeof(*pipe_floor);
727
728     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
729     pipe_floor->protid = EPM_PROTOCOL_PIPE;
730     pipe_floor->count_rhs = endpoint_size;
731
732     memcpy(tower_data, endpoint, endpoint_size);
733
734     return size;
735 }
736
737 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
738                                                     size_t tower_size,
739                                                     char **networkaddr,
740                                                     char **endpoint)
741 {
742     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
743
744     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
745
746     if (tower_size < sizeof(*pipe_floor))
747         return EPT_S_NOT_REGISTERED;
748
749     tower_data += sizeof(*pipe_floor);
750     tower_size -= sizeof(*pipe_floor);
751
752     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
753         (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
754         (pipe_floor->count_rhs > tower_size) ||
755         (tower_data[pipe_floor->count_rhs - 1] != '\0'))
756         return EPT_S_NOT_REGISTERED;
757
758     if (networkaddr)
759         *networkaddr = NULL;
760
761     if (endpoint)
762     {
763         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
764         if (!*endpoint)
765             return RPC_S_OUT_OF_RESOURCES;
766         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
767     }
768
769     return RPC_S_OK;
770 }
771
772 /**** ncacn_ip_tcp support ****/
773
774 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
775                                              const char *networkaddr,
776                                              unsigned char tcp_protid,
777                                              const char *endpoint)
778 {
779     twr_tcp_floor_t *tcp_floor;
780     twr_ipv4_floor_t *ipv4_floor;
781     struct addrinfo *ai;
782     struct addrinfo hints;
783     int ret;
784     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
785
786     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
787
788     if (!tower_data)
789         return size;
790
791     tcp_floor = (twr_tcp_floor_t *)tower_data;
792     tower_data += sizeof(*tcp_floor);
793
794     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
795
796     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
797     tcp_floor->protid = tcp_protid;
798     tcp_floor->count_rhs = sizeof(tcp_floor->port);
799
800     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
801     ipv4_floor->protid = EPM_PROTOCOL_IP;
802     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
803
804     hints.ai_flags          = AI_NUMERICHOST;
805     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
806     hints.ai_family         = PF_INET;
807     hints.ai_socktype       = SOCK_STREAM;
808     hints.ai_protocol       = IPPROTO_TCP;
809     hints.ai_addrlen        = 0;
810     hints.ai_addr           = NULL;
811     hints.ai_canonname      = NULL;
812     hints.ai_next           = NULL;
813
814     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
815     if (ret)
816     {
817         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
818         if (ret)
819         {
820             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
821             return 0;
822         }
823     }
824
825     if (ai->ai_family == PF_INET)
826     {
827         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
828         tcp_floor->port = sin->sin_port;
829         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
830     }
831     else
832     {
833         ERR("unexpected protocol family %d\n", ai->ai_family);
834         return 0;
835     }
836
837     freeaddrinfo(ai);
838
839     return size;
840 }
841
842 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
843                                                    size_t tower_size,
844                                                    char **networkaddr,
845                                                    unsigned char tcp_protid,
846                                                    char **endpoint)
847 {
848     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
849     const twr_ipv4_floor_t *ipv4_floor;
850     struct in_addr in_addr;
851
852     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
853
854     if (tower_size < sizeof(*tcp_floor))
855         return EPT_S_NOT_REGISTERED;
856
857     tower_data += sizeof(*tcp_floor);
858     tower_size -= sizeof(*tcp_floor);
859
860     if (tower_size < sizeof(*ipv4_floor))
861         return EPT_S_NOT_REGISTERED;
862
863     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
864
865     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
866         (tcp_floor->protid != tcp_protid) ||
867         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
868         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
869         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
870         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
871         return EPT_S_NOT_REGISTERED;
872
873     if (endpoint)
874     {
875         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
876         if (!*endpoint)
877             return RPC_S_OUT_OF_RESOURCES;
878         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
879     }
880
881     if (networkaddr)
882     {
883         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
884         if (!*networkaddr)
885         {
886             if (endpoint)
887             {
888                 I_RpcFree(*endpoint);
889                 *endpoint = NULL;
890             }
891             return RPC_S_OUT_OF_RESOURCES;
892         }
893         in_addr.s_addr = ipv4_floor->ipv4addr;
894         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
895         {
896             ERR("inet_ntop: %s\n", strerror(errno));
897             I_RpcFree(*networkaddr);
898             *networkaddr = NULL;
899             if (endpoint)
900             {
901                 I_RpcFree(*endpoint);
902                 *endpoint = NULL;
903             }
904             return EPT_S_NOT_REGISTERED;
905         }
906     }
907
908     return RPC_S_OK;
909 }
910
911 typedef struct _RpcConnection_tcp
912 {
913   RpcConnection common;
914   int sock;
915   int cancel_fds[2];
916 } RpcConnection_tcp;
917
918 #ifdef HAVE_SOCKETPAIR
919
920 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
921 {
922   if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
923   {
924     ERR("socketpair() failed: %s\n", strerror(errno));
925     return FALSE;
926   }
927   return TRUE;
928 }
929
930 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
931 {
932   struct pollfd pfds[2];
933   pfds[0].fd = tcpc->sock;
934   pfds[0].events = POLLIN;
935   pfds[1].fd = tcpc->cancel_fds[0];
936   pfds[1].events = POLLIN;
937   if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
938   {
939     ERR("poll() failed: %s\n", strerror(errno));
940     return FALSE;
941   }
942   if (pfds[1].revents & POLLIN) /* canceled */
943   {
944     char dummy;
945     read(pfds[1].fd, &dummy, sizeof(dummy));
946     return FALSE;
947   }
948   return TRUE;
949 }
950
951 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
952 {
953   struct pollfd pfd;
954   pfd.fd = tcpc->sock;
955   pfd.events = POLLOUT;
956   if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
957   {
958     ERR("poll() failed: %s\n", strerror(errno));
959     return FALSE;
960   }
961   return TRUE;
962 }
963
964 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
965 {
966   char dummy = 1;
967
968   write(tcpc->cancel_fds[1], &dummy, 1);
969 }
970
971 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
972 {
973   close(tcpc->cancel_fds[0]);
974   close(tcpc->cancel_fds[1]);
975 }
976
977 #else /* HAVE_SOCKETPAIR */
978
979 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
980 {
981   /* FIXME */
982   return FALSE;
983 }
984
985 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
986 {
987   /* FIXME */
988   return FALSE;
989 }
990
991 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
992 {
993   /* FIXME */
994   return FALSE;
995 }
996
997 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
998 {
999   /* FIXME */
1000 }
1001
1002 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1003 {
1004   /* FIXME */
1005 }
1006
1007 #endif
1008
1009 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1010 {
1011   RpcConnection_tcp *tcpc;
1012   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
1013   if (tcpc == NULL)
1014     return NULL;
1015   tcpc->sock = -1;
1016   if (!rpcrt4_sock_wait_init(tcpc))
1017   {
1018     HeapFree(GetProcessHeap(), 0, tcpc);
1019     return NULL;
1020   }
1021   return &tcpc->common;
1022 }
1023
1024 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1025 {
1026   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1027   int sock;
1028   int ret;
1029   struct addrinfo *ai;
1030   struct addrinfo *ai_cur;
1031   struct addrinfo hints;
1032
1033   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1034
1035   if (tcpc->sock != -1)
1036     return RPC_S_OK;
1037
1038   hints.ai_flags          = 0;
1039   hints.ai_family         = PF_UNSPEC;
1040   hints.ai_socktype       = SOCK_STREAM;
1041   hints.ai_protocol       = IPPROTO_TCP;
1042   hints.ai_addrlen        = 0;
1043   hints.ai_addr           = NULL;
1044   hints.ai_canonname      = NULL;
1045   hints.ai_next           = NULL;
1046
1047   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1048   if (ret)
1049   {
1050     ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1051       Connection->Endpoint, gai_strerror(ret));
1052     return RPC_S_SERVER_UNAVAILABLE;
1053   }
1054
1055   for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1056   {
1057     int val;
1058     u_long nonblocking;
1059
1060     if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1061     {
1062       TRACE("skipping non-IP/IPv6 address family\n");
1063       continue;
1064     }
1065
1066     if (TRACE_ON(rpc))
1067     {
1068       char host[256];
1069       char service[256];
1070       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1071         host, sizeof(host), service, sizeof(service),
1072         NI_NUMERICHOST | NI_NUMERICSERV);
1073       TRACE("trying %s:%s\n", host, service);
1074     }
1075
1076     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1077     if (sock == -1)
1078     {
1079       WARN("socket() failed: %s\n", strerror(errno));
1080       continue;
1081     }
1082
1083     if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1084     {
1085       WARN("connect() failed: %s\n", strerror(errno));
1086       closesocket(sock);
1087       continue;
1088     }
1089
1090     /* RPC depends on having minimal latency so disable the Nagle algorithm */
1091     val = 1;
1092     setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1093     nonblocking = 1;
1094     ioctlsocket(sock, FIONBIO, &nonblocking);
1095
1096     tcpc->sock = sock;
1097
1098     freeaddrinfo(ai);
1099     TRACE("connected\n");
1100     return RPC_S_OK;
1101   }
1102
1103   freeaddrinfo(ai);
1104   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1105   return RPC_S_SERVER_UNAVAILABLE;
1106 }
1107
1108 #ifdef HAVE_SOCKETPAIR
1109
1110 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1111 {
1112     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1113     int sock;
1114     int ret;
1115     struct addrinfo *ai;
1116     struct addrinfo *ai_cur;
1117     struct addrinfo hints;
1118     RpcConnection *first_connection = NULL;
1119
1120     TRACE("(%p, %s)\n", protseq, endpoint);
1121
1122     hints.ai_flags          = AI_PASSIVE /* for non-localhost addresses */;
1123     hints.ai_family         = PF_UNSPEC;
1124     hints.ai_socktype       = SOCK_STREAM;
1125     hints.ai_protocol       = IPPROTO_TCP;
1126     hints.ai_addrlen        = 0;
1127     hints.ai_addr           = NULL;
1128     hints.ai_canonname      = NULL;
1129     hints.ai_next           = NULL;
1130
1131     ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1132     if (ret)
1133     {
1134         ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1135             gai_strerror(ret));
1136         if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1137             return RPC_S_INVALID_ENDPOINT_FORMAT;
1138         return RPC_S_CANT_CREATE_ENDPOINT;
1139     }
1140
1141     for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1142     {
1143         RpcConnection_tcp *tcpc;
1144         RPC_STATUS create_status;
1145         struct sockaddr_storage sa;
1146         socklen_t sa_len;
1147         char service[NI_MAXSERV];
1148         u_long nonblocking;
1149
1150         if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1151         {
1152             TRACE("skipping non-IP/IPv6 address family\n");
1153             continue;
1154         }
1155
1156         if (TRACE_ON(rpc))
1157         {
1158             char host[256];
1159             getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1160                         host, sizeof(host), service, sizeof(service),
1161                         NI_NUMERICHOST | NI_NUMERICSERV);
1162             TRACE("trying %s:%s\n", host, service);
1163         }
1164
1165         sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1166         if (sock == -1)
1167         {
1168             WARN("socket() failed: %s\n", strerror(errno));
1169             status = RPC_S_CANT_CREATE_ENDPOINT;
1170             continue;
1171         }
1172
1173         ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1174         if (ret < 0)
1175         {
1176             WARN("bind failed: %s\n", strerror(errno));
1177             closesocket(sock);
1178             if (errno == EADDRINUSE)
1179               status = RPC_S_DUPLICATE_ENDPOINT;
1180             else
1181               status = RPC_S_CANT_CREATE_ENDPOINT;
1182             continue;
1183         }
1184
1185         sa_len = sizeof(sa);
1186         if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1187         {
1188             WARN("getsockname() failed: %s\n", strerror(errno));
1189             status = RPC_S_CANT_CREATE_ENDPOINT;
1190             continue;
1191         }
1192
1193         ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1194                           NULL, 0, service, sizeof(service),
1195                           NI_NUMERICSERV);
1196         if (ret)
1197         {
1198             WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1199             status = RPC_S_CANT_CREATE_ENDPOINT;
1200             continue;
1201         }
1202
1203         create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1204                                                 protseq->Protseq, NULL,
1205                                                 service, NULL, NULL, NULL);
1206         if (create_status != RPC_S_OK)
1207         {
1208             closesocket(sock);
1209             status = create_status;
1210             continue;
1211         }
1212
1213         tcpc->sock = sock;
1214         ret = listen(sock, protseq->MaxCalls);
1215         if (ret < 0)
1216         {
1217             WARN("listen failed: %s\n", strerror(errno));
1218             RPCRT4_DestroyConnection(&tcpc->common);
1219             status = RPC_S_OUT_OF_RESOURCES;
1220             continue;
1221         }
1222         /* need a non-blocking socket, otherwise accept() has a potential
1223          * race-condition (poll() says it is readable, connection drops,
1224          * and accept() blocks until the next connection comes...)
1225          */
1226         nonblocking = 1;
1227         ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1228         if (ret < 0)
1229         {
1230             WARN("couldn't make socket non-blocking, error %d\n", ret);
1231             RPCRT4_DestroyConnection(&tcpc->common);
1232             status = RPC_S_OUT_OF_RESOURCES;
1233             continue;
1234         }
1235
1236         tcpc->common.Next = first_connection;
1237         first_connection = &tcpc->common;
1238
1239         /* since IPv4 and IPv6 share the same port space, we only need one
1240          * successful bind to listen for both */
1241         break;
1242     }
1243
1244     freeaddrinfo(ai);
1245
1246     /* if at least one connection was created for an endpoint then
1247      * return success */
1248     if (first_connection)
1249     {
1250         RpcConnection *conn;
1251
1252         /* find last element in list */
1253         for (conn = first_connection; conn->Next; conn = conn->Next)
1254             ;
1255
1256         EnterCriticalSection(&protseq->cs);
1257         conn->Next = protseq->conn;
1258         protseq->conn = first_connection;
1259         LeaveCriticalSection(&protseq->cs);
1260         
1261         TRACE("listening on %s\n", endpoint);
1262         return RPC_S_OK;
1263     }
1264
1265     ERR("couldn't listen on port %s\n", endpoint);
1266     return status;
1267 }
1268
1269 #endif
1270
1271 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1272 {
1273   int ret;
1274   struct sockaddr_in address;
1275   socklen_t addrsize;
1276   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1277   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1278   u_long nonblocking;
1279
1280   addrsize = sizeof(address);
1281   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1282   if (ret < 0)
1283   {
1284     ERR("Failed to accept a TCP connection: error %d\n", ret);
1285     return RPC_S_OUT_OF_RESOURCES;
1286   }
1287   nonblocking = 1;
1288   ioctlsocket(ret, FIONBIO, &nonblocking);
1289   client->sock = ret;
1290   TRACE("Accepted a new TCP connection\n");
1291   return RPC_S_OK;
1292 }
1293
1294 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1295                                 void *buffer, unsigned int count)
1296 {
1297   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1298   int bytes_read = 0;
1299   do
1300   {
1301     int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1302     if (!r)
1303       return -1;
1304     else if (r > 0)
1305       bytes_read += r;
1306     else if (errno != EAGAIN)
1307     {
1308       WARN("recv() failed: %s\n", strerror(errno));
1309       return -1;
1310     }
1311     else
1312     {
1313       if (!rpcrt4_sock_wait_for_recv(tcpc))
1314         return -1;
1315     }
1316   } while (bytes_read != count);
1317   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1318   return bytes_read;
1319 }
1320
1321 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1322                                  const void *buffer, unsigned int count)
1323 {
1324   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1325   int bytes_written = 0;
1326   do
1327   {
1328     int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1329     if (r >= 0)
1330       bytes_written += r;
1331     else if (errno != EAGAIN)
1332       return -1;
1333     else
1334     {
1335       if (!rpcrt4_sock_wait_for_send(tcpc))
1336         return -1;
1337     }
1338   } while (bytes_written != count);
1339   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1340   return bytes_written;
1341 }
1342
1343 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1344 {
1345   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1346
1347   TRACE("%d\n", tcpc->sock);
1348
1349   if (tcpc->sock != -1)
1350     closesocket(tcpc->sock);
1351   tcpc->sock = -1;
1352   rpcrt4_sock_wait_destroy(tcpc);
1353   return 0;
1354 }
1355
1356 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1357 {
1358     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1359     TRACE("%p\n", Connection);
1360     rpcrt4_sock_wait_cancel(tcpc);
1361 }
1362
1363 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1364 {
1365     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1366
1367     TRACE("%p\n", Connection);
1368
1369     if (!rpcrt4_sock_wait_for_recv(tcpc))
1370         return -1;
1371     return 0;
1372 }
1373
1374 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1375                                                    const char *networkaddr,
1376                                                    const char *endpoint)
1377 {
1378     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1379                                           EPM_PROTOCOL_TCP, endpoint);
1380 }
1381
1382 #ifdef HAVE_SOCKETPAIR
1383
1384 typedef struct _RpcServerProtseq_sock
1385 {
1386     RpcServerProtseq common;
1387     int mgr_event_rcv;
1388     int mgr_event_snd;
1389 } RpcServerProtseq_sock;
1390
1391 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1392 {
1393     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1394     if (ps)
1395     {
1396         int fds[2];
1397         if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1398         {
1399             fcntl(fds[0], F_SETFL, O_NONBLOCK);
1400             fcntl(fds[1], F_SETFL, O_NONBLOCK);
1401             ps->mgr_event_rcv = fds[0];
1402             ps->mgr_event_snd = fds[1];
1403         }
1404         else
1405         {
1406             ERR("socketpair failed with error %s\n", strerror(errno));
1407             HeapFree(GetProcessHeap(), 0, ps);
1408             return NULL;
1409         }
1410     }
1411     return &ps->common;
1412 }
1413
1414 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1415 {
1416     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1417     char dummy = 1;
1418     write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1419 }
1420
1421 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1422 {
1423     struct pollfd *poll_info = prev_array;
1424     RpcConnection_tcp *conn;
1425     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1426
1427     EnterCriticalSection(&protseq->cs);
1428     
1429     /* open and count connections */
1430     *count = 1;
1431     conn = (RpcConnection_tcp *)protseq->conn;
1432     while (conn) {
1433         if (conn->sock != -1)
1434             (*count)++;
1435         conn = (RpcConnection_tcp *)conn->common.Next;
1436     }
1437     
1438     /* make array of connections */
1439     if (poll_info)
1440         poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1441     else
1442         poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1443     if (!poll_info)
1444     {
1445         ERR("couldn't allocate poll_info\n");
1446         LeaveCriticalSection(&protseq->cs);
1447         return NULL;
1448     }
1449
1450     poll_info[0].fd = sockps->mgr_event_rcv;
1451     poll_info[0].events = POLLIN;
1452     *count = 1;
1453     conn =  CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1454     while (conn) {
1455         if (conn->sock != -1)
1456         {
1457             poll_info[*count].fd = conn->sock;
1458             poll_info[*count].events = POLLIN;
1459             (*count)++;
1460         }
1461         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1462     }
1463     LeaveCriticalSection(&protseq->cs);
1464     return poll_info;
1465 }
1466
1467 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1468 {
1469     HeapFree(GetProcessHeap(), 0, array);
1470 }
1471
1472 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1473 {
1474     struct pollfd *poll_info = wait_array;
1475     int ret;
1476     unsigned int i;
1477     RpcConnection *cconn;
1478     RpcConnection_tcp *conn;
1479     
1480     if (!poll_info)
1481         return -1;
1482     
1483     ret = poll(poll_info, count, -1);
1484     if (ret < 0)
1485     {
1486         ERR("poll failed with error %d\n", ret);
1487         return -1;
1488     }
1489
1490     for (i = 0; i < count; i++)
1491         if (poll_info[i].revents & POLLIN)
1492         {
1493             /* RPC server event */
1494             if (i == 0)
1495             {
1496                 char dummy;
1497                 read(poll_info[0].fd, &dummy, sizeof(dummy));
1498                 return 0;
1499             }
1500
1501             /* find which connection got a RPC */
1502             EnterCriticalSection(&protseq->cs);
1503             conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1504             while (conn) {
1505                 if (poll_info[i].fd == conn->sock) break;
1506                 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1507             }
1508             cconn = NULL;
1509             if (conn)
1510                 RPCRT4_SpawnConnection(&cconn, &conn->common);
1511             else
1512                 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1513             LeaveCriticalSection(&protseq->cs);
1514             if (cconn)
1515                 RPCRT4_new_client(cconn);
1516             else
1517                 return -1;
1518         }
1519
1520     return 1;
1521 }
1522
1523 #endif  /* HAVE_SOCKETPAIR */
1524
1525 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1526                                                          size_t tower_size,
1527                                                          char **networkaddr,
1528                                                          char **endpoint)
1529 {
1530     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1531                                             networkaddr, EPM_PROTOCOL_TCP,
1532                                             endpoint);
1533 }
1534
1535 /**** ncacn_http support ****/
1536
1537 /* 60 seconds is the period native uses */
1538 #define HTTP_IDLE_TIME 60000
1539
1540 /* reference counted to avoid a race between a cancelled call's connection
1541  * being destroyed and the asynchronous InternetReadFileEx call being
1542  * completed */
1543 typedef struct _RpcHttpAsyncData
1544 {
1545     LONG refs;
1546     HANDLE completion_event;
1547     INTERNET_BUFFERSA inet_buffers;
1548     void *destination_buffer; /* the address that inet_buffers.lpvBuffer will be
1549                                * copied into when the call completes */
1550     CRITICAL_SECTION cs;
1551 } RpcHttpAsyncData;
1552
1553 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1554 {
1555     return InterlockedIncrement(&data->refs);
1556 }
1557
1558 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1559 {
1560     ULONG refs = InterlockedDecrement(&data->refs);
1561     if (!refs)
1562     {
1563         TRACE("destroying async data %p\n", data);
1564         CloseHandle(data->completion_event);
1565         HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1566         DeleteCriticalSection(&data->cs);
1567         HeapFree(GetProcessHeap(), 0, data);
1568     }
1569     return refs;
1570 }
1571
1572 typedef struct _RpcConnection_http
1573 {
1574     RpcConnection common;
1575     HINTERNET app_info;
1576     HINTERNET session;
1577     HINTERNET in_request;
1578     HINTERNET out_request;
1579     HANDLE timer_cancelled;
1580     HANDLE cancel_event;
1581     DWORD last_sent_time;
1582     ULONG bytes_received;
1583     ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1584     ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1585     UUID connection_uuid;
1586     UUID in_pipe_uuid;
1587     UUID out_pipe_uuid;
1588     RpcHttpAsyncData *async_data;
1589 } RpcConnection_http;
1590
1591 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1592 {
1593     RpcConnection_http *httpc;
1594     httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1595     if (!httpc) return NULL;
1596     httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1597     if (!httpc->async_data)
1598     {
1599         HeapFree(GetProcessHeap(), 0, httpc);
1600         return NULL;
1601     }
1602     TRACE("async data = %p\n", httpc->async_data);
1603     httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1604     httpc->async_data->refs = 1;
1605     httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
1606     httpc->async_data->inet_buffers.lpvBuffer = NULL;
1607     httpc->async_data->destination_buffer = NULL;
1608     InitializeCriticalSection(&httpc->async_data->cs);
1609     return &httpc->common;
1610 }
1611
1612 typedef struct _HttpTimerThreadData
1613 {
1614     PVOID timer_param;
1615     DWORD *last_sent_time;
1616     HANDLE timer_cancelled;
1617 } HttpTimerThreadData;
1618
1619 static VOID CALLBACK rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1620 {
1621     HINTERNET in_request = param;
1622     RpcPktHdr *idle_pkt;
1623
1624     idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1625                                       0, 0);
1626     if (idle_pkt)
1627     {
1628         DWORD bytes_written;
1629         InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1630         RPCRT4_FreeHeader(idle_pkt);
1631     }
1632 }
1633
1634 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1635 {
1636     DWORD cur_time = GetTickCount();
1637     DWORD cached_last_sent_time = *last_sent_time;
1638     return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1639 }
1640
1641 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1642 {
1643     HttpTimerThreadData *data_in = param;
1644     HttpTimerThreadData data;
1645     DWORD timeout;
1646
1647     data = *data_in;
1648     HeapFree(GetProcessHeap(), 0, data_in);
1649
1650     for (timeout = HTTP_IDLE_TIME;
1651          WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1652          timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1653     {
1654         /* are we too soon after last send? */
1655         if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time)
1656             continue;
1657         rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1658     }
1659
1660     CloseHandle(data.timer_cancelled);
1661     return 0;
1662 }
1663
1664 static VOID WINAPI rpcrt4_http_internet_callback(
1665      HINTERNET hInternet,
1666      DWORD_PTR dwContext,
1667      DWORD dwInternetStatus,
1668      LPVOID lpvStatusInformation,
1669      DWORD dwStatusInformationLength)
1670 {
1671     RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1672
1673     switch (dwInternetStatus)
1674     {
1675     case INTERNET_STATUS_REQUEST_COMPLETE:
1676         TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1677         if (async_data)
1678         {
1679             if (async_data->inet_buffers.lpvBuffer)
1680             {
1681                 EnterCriticalSection(&async_data->cs);
1682                 if (async_data->destination_buffer)
1683                 {
1684                     memcpy(async_data->destination_buffer,
1685                            async_data->inet_buffers.lpvBuffer,
1686                            async_data->inet_buffers.dwBufferLength);
1687                     async_data->destination_buffer = NULL;
1688                 }
1689                 LeaveCriticalSection(&async_data->cs);
1690             }
1691             HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
1692             async_data->inet_buffers.lpvBuffer = NULL;
1693             SetEvent(async_data->completion_event);
1694             RpcHttpAsyncData_Release(async_data);
1695         }
1696         break;
1697     }
1698 }
1699
1700 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1701 {
1702     BOOL ret;
1703     DWORD status_code;
1704     DWORD size;
1705     DWORD index;
1706     WCHAR buf[32];
1707     WCHAR *status_text = buf;
1708     TRACE("\n");
1709
1710     index = 0;
1711     size = sizeof(status_code);
1712     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1713     if (!ret)
1714         return GetLastError();
1715     if (status_code < 400)
1716         return RPC_S_OK;
1717     index = 0;
1718     size = sizeof(buf);
1719     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1720     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1721     {
1722         status_text = HeapAlloc(GetProcessHeap(), 0, size);
1723         ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1724     }
1725
1726     ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
1727     if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
1728
1729     if (status_code == HTTP_STATUS_DENIED)
1730         return ERROR_ACCESS_DENIED;
1731     return RPC_S_SERVER_UNAVAILABLE;
1732 }
1733
1734 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
1735 {
1736     static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
1737     LPWSTR proxy = NULL;
1738     LPWSTR user = NULL;
1739     LPWSTR password = NULL;
1740     LPWSTR servername = NULL;
1741     const WCHAR *option;
1742     INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */
1743
1744     if (httpc->common.QOS &&
1745         (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1746     {
1747         const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1748         if (http_cred->TransportCredentials)
1749         {
1750             WCHAR *p;
1751             const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1752             ULONG len = cred->DomainLength + 1 + cred->UserLength;
1753             user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1754             if (!user)
1755                 return RPC_S_OUT_OF_RESOURCES;
1756             p = user;
1757             if (cred->DomainLength)
1758             {
1759                 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1760                 p += cred->DomainLength;
1761                 *p = '\\';
1762                 p++;
1763             }
1764             memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1765             p[cred->UserLength] = 0;
1766
1767             password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1768         }
1769     }
1770
1771     for (option = httpc->common.NetworkOptions; option;
1772          option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
1773     {
1774         static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
1775         static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
1776
1777         if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
1778         {
1779             const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
1780             const WCHAR *value_end;
1781             const WCHAR *p;
1782
1783             value_end = strchrW(option, ',');
1784             if (!value_end)
1785                 value_end = value_start + strlenW(value_start);
1786             for (p = value_start; p < value_end; p++)
1787                 if (*p == ':')
1788                 {
1789                     port = atoiW(p+1);
1790                     value_end = p;
1791                     break;
1792                 }
1793             TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1794             servername = RPCRT4_strndupW(value_start, value_end-value_start);
1795         }
1796         else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
1797         {
1798             const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
1799             const WCHAR *value_end;
1800
1801             value_end = strchrW(option, ',');
1802             if (!value_end)
1803                 value_end = value_start + strlenW(value_start);
1804             TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1805             proxy = RPCRT4_strndupW(value_start, value_end-value_start);
1806         }
1807         else
1808             FIXME("unhandled option %s\n", debugstr_w(option));
1809     }
1810
1811     httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
1812                                     NULL, NULL, INTERNET_FLAG_ASYNC);
1813     if (!httpc->app_info)
1814     {
1815         HeapFree(GetProcessHeap(), 0, password);
1816         HeapFree(GetProcessHeap(), 0, user);
1817         ERR("InternetOpenW failed with error %d\n", GetLastError());
1818         return RPC_S_SERVER_UNAVAILABLE;
1819     }
1820     InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
1821
1822     /* if no RpcProxy option specified, set the HTTP server address to the
1823      * RPC server address */
1824     if (!servername)
1825     {
1826         servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
1827         if (!servername)
1828         {
1829             HeapFree(GetProcessHeap(), 0, password);
1830             HeapFree(GetProcessHeap(), 0, user);
1831             return RPC_S_OUT_OF_RESOURCES;
1832         }
1833         MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
1834     }
1835
1836     httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
1837                                       INTERNET_SERVICE_HTTP, 0, 0);
1838
1839     HeapFree(GetProcessHeap(), 0, password);
1840     HeapFree(GetProcessHeap(), 0, user);
1841     HeapFree(GetProcessHeap(), 0, servername);
1842
1843     if (!httpc->session)
1844     {
1845         ERR("InternetConnectW failed with error %d\n", GetLastError());
1846         return RPC_S_SERVER_UNAVAILABLE;
1847     }
1848
1849     return RPC_S_OK;
1850 }
1851
1852 /* prepare the in pipe for use by RPC packets */
1853 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data,
1854                                               const UUID *connection_uuid,
1855                                               const UUID *in_pipe_uuid,
1856                                               const UUID *association_uuid)
1857 {
1858     BYTE packet[44];
1859     BOOL ret;
1860     RPC_STATUS status;
1861     RpcPktHdr *hdr;
1862     INTERNET_BUFFERSW buffers_in;
1863     DWORD bytes_read, bytes_written;
1864
1865     /* prepare in pipe */
1866     ResetEvent(async_data->completion_event);
1867     RpcHttpAsyncData_AddRef(async_data);
1868     ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0);
1869     if (!ret)
1870     {
1871         if (GetLastError() == ERROR_IO_PENDING)
1872             WaitForSingleObject(async_data->completion_event, INFINITE);
1873         else
1874         {
1875             RpcHttpAsyncData_Release(async_data);
1876             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
1877             return RPC_S_SERVER_UNAVAILABLE;
1878         }
1879     }
1880     status = rpcrt4_http_check_response(in_request);
1881     if (status != RPC_S_OK) return status;
1882
1883     InternetReadFile(in_request, packet, 20, &bytes_read);
1884     /* FIXME: do something with retrieved data */
1885
1886     memset(&buffers_in, 0, sizeof(buffers_in));
1887     buffers_in.dwStructSize = sizeof(buffers_in);
1888     /* FIXME: get this from the registry */
1889     buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
1890     ResetEvent(async_data->completion_event);
1891     RpcHttpAsyncData_AddRef(async_data);
1892     ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
1893     if (!ret)
1894     {
1895         if (GetLastError() == ERROR_IO_PENDING)
1896             WaitForSingleObject(async_data->completion_event, INFINITE);
1897         else
1898         {
1899             RpcHttpAsyncData_Release(async_data);
1900             ERR("HttpSendRequestExW failed with error %d\n", GetLastError());
1901             return RPC_S_SERVER_UNAVAILABLE;
1902         }
1903     }
1904
1905     TRACE("sending HTTP connect header to server\n");
1906     hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid, association_uuid);
1907     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
1908     ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
1909     RPCRT4_FreeHeader(hdr);
1910     if (!ret)
1911     {
1912         ERR("InternetWriteFile failed with error %d\n", GetLastError());
1913         return RPC_S_SERVER_UNAVAILABLE;
1914     }
1915
1916     return RPC_S_OK;
1917 }
1918
1919 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data)
1920 {
1921     BOOL ret;
1922     DWORD bytes_read;
1923     unsigned short data_len;
1924
1925     ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read);
1926     if (!ret)
1927         return RPC_S_SERVER_UNAVAILABLE;
1928     if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
1929     {
1930         ERR("wrong packet type received %d or wrong frag_len %d\n",
1931             hdr->common.ptype, hdr->common.frag_len);
1932         return RPC_S_PROTOCOL_ERROR;
1933     }
1934
1935     ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read);
1936     if (!ret)
1937         return RPC_S_SERVER_UNAVAILABLE;
1938
1939     data_len = hdr->common.frag_len - sizeof(hdr->http);
1940     if (data_len)
1941     {
1942         *data = HeapAlloc(GetProcessHeap(), 0, data_len);
1943         if (!*data)
1944             return RPC_S_OUT_OF_RESOURCES;
1945         ret = InternetReadFile(request, *data, data_len, &bytes_read);
1946         if (!ret)
1947         {
1948             HeapFree(GetProcessHeap(), 0, *data);
1949             return RPC_S_SERVER_UNAVAILABLE;
1950         }
1951     }
1952     else
1953         *data = NULL;
1954
1955     if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
1956     {
1957         ERR("invalid http packet\n");
1958         return RPC_S_PROTOCOL_ERROR;
1959     }
1960
1961     return RPC_S_OK;
1962 }
1963
1964 /* prepare the out pipe for use by RPC packets */
1965 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
1966                                                RpcHttpAsyncData *async_data,
1967                                                const UUID *connection_uuid,
1968                                                const UUID *out_pipe_uuid,
1969                                                ULONG *flow_control_increment)
1970 {
1971     BYTE packet[20];
1972     BOOL ret;
1973     RPC_STATUS status;
1974     RpcPktHdr *hdr;
1975     DWORD bytes_read;
1976     BYTE *data_from_server;
1977     RpcPktHdr pkt_from_server;
1978     ULONG field1, field3;
1979
1980     ResetEvent(async_data->completion_event);
1981     RpcHttpAsyncData_AddRef(async_data);
1982     ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0);
1983     if (!ret)
1984     {
1985         if (GetLastError() == ERROR_IO_PENDING)
1986             WaitForSingleObject(async_data->completion_event, INFINITE);
1987         else
1988         {
1989             RpcHttpAsyncData_Release(async_data);
1990             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
1991             return RPC_S_SERVER_UNAVAILABLE;
1992         }
1993     }
1994     status = rpcrt4_http_check_response(out_request);
1995     if (status != RPC_S_OK) return status;
1996
1997     InternetReadFile(out_request, packet, 20, &bytes_read);
1998     /* FIXME: do something with retrieved data */
1999
2000     hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid, NULL);
2001     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2002     ResetEvent(async_data->completion_event);
2003     RpcHttpAsyncData_AddRef(async_data);
2004     ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2005     if (!ret)
2006     {
2007         if (GetLastError() == ERROR_IO_PENDING)
2008             WaitForSingleObject(async_data->completion_event, INFINITE);
2009         else
2010         {
2011             RpcHttpAsyncData_Release(async_data);
2012             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2013             RPCRT4_FreeHeader(hdr);
2014             return RPC_S_SERVER_UNAVAILABLE;
2015         }
2016     }
2017     RPCRT4_FreeHeader(hdr);
2018     status = rpcrt4_http_check_response(out_request);
2019     if (status != RPC_S_OK) return status;
2020
2021     status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2022                                           &data_from_server);
2023     if (status != RPC_S_OK) return status;
2024     status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2025                                             &field1);
2026     HeapFree(GetProcessHeap(), 0, data_from_server);
2027     if (status != RPC_S_OK) return status;
2028     TRACE("received (%d) from first prepare header\n", field1);
2029
2030     status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2031                                           &data_from_server);
2032     if (status != RPC_S_OK) return status;
2033     status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2034                                             &field1, flow_control_increment,
2035                                             &field3);
2036     HeapFree(GetProcessHeap(), 0, data_from_server);
2037     if (status != RPC_S_OK) return status;
2038     TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2039
2040     return RPC_S_OK;
2041 }
2042
2043 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2044 {
2045     RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2046     static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2047     static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2048     static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2049     static const WCHAR wszColon[] = {':',0};
2050     static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2051     LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2052     WCHAR *url;
2053     RPC_STATUS status;
2054     BOOL secure;
2055     HttpTimerThreadData *timer_data;
2056     HANDLE thread;
2057
2058     TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2059
2060     if (Connection->server)
2061     {
2062         ERR("ncacn_http servers not supported yet\n");
2063         return RPC_S_SERVER_UNAVAILABLE;
2064     }
2065
2066     if (httpc->in_request)
2067         return RPC_S_OK;
2068
2069     httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2070
2071     status = UuidCreate(&httpc->connection_uuid);
2072     status = UuidCreate(&httpc->in_pipe_uuid);
2073     status = UuidCreate(&httpc->out_pipe_uuid);
2074
2075     status = rpcrt4_http_internet_connect(httpc);
2076     if (status != RPC_S_OK)
2077         return status;
2078
2079     url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2080     if (!url)
2081         return RPC_S_OUT_OF_MEMORY;
2082     memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2083     MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
2084     strcatW(url, wszColon);
2085     MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
2086
2087     secure = httpc->common.QOS &&
2088              (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2089              (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2090
2091     httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL,
2092                                          wszAcceptTypes,
2093                                          (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2094                                          (DWORD_PTR)httpc->async_data);
2095     if (!httpc->in_request)
2096     {
2097         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2098         return RPC_S_SERVER_UNAVAILABLE;
2099     }
2100     httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL,
2101                                           wszAcceptTypes,
2102                                           (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2103                                           (DWORD_PTR)httpc->async_data);
2104     if (!httpc->out_request)
2105     {
2106         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2107         return RPC_S_SERVER_UNAVAILABLE;
2108     }
2109
2110     status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
2111                                          httpc->async_data,
2112                                          &httpc->connection_uuid,
2113                                          &httpc->in_pipe_uuid,
2114                                          &Connection->assoc->http_uuid);
2115     if (status != RPC_S_OK)
2116         return status;
2117
2118     status = rpcrt4_http_prepare_out_pipe(httpc->out_request,
2119                                           httpc->async_data,
2120                                           &httpc->connection_uuid,
2121                                           &httpc->out_pipe_uuid,
2122                                           &httpc->flow_control_increment);
2123     if (status != RPC_S_OK)
2124         return status;
2125
2126     httpc->flow_control_mark = httpc->flow_control_increment / 2;
2127     httpc->last_sent_time = GetTickCount();
2128     httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2129
2130     timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2131     if (!timer_data)
2132         return ERROR_OUTOFMEMORY;
2133     timer_data->timer_param = httpc->in_request;
2134     timer_data->last_sent_time = &httpc->last_sent_time;
2135     timer_data->timer_cancelled = httpc->timer_cancelled;
2136     /* FIXME: should use CreateTimerQueueTimer when implemented */
2137     thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2138     if (!thread)
2139     {
2140         HeapFree(GetProcessHeap(), 0, timer_data);
2141         return GetLastError();
2142     }
2143     CloseHandle(thread);
2144
2145     return RPC_S_OK;
2146 }
2147
2148 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2149 {
2150     assert(0);
2151     return RPC_S_SERVER_UNAVAILABLE;
2152 }
2153
2154 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2155                                 void *buffer, unsigned int count)
2156 {
2157   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2158   char *buf = buffer;
2159   BOOL ret = TRUE;
2160   unsigned int bytes_left = count;
2161
2162   ResetEvent(httpc->async_data->completion_event);
2163   while (bytes_left)
2164   {
2165     RpcHttpAsyncData_AddRef(httpc->async_data);
2166     httpc->async_data->inet_buffers.dwBufferLength = bytes_left;
2167     httpc->async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, bytes_left);
2168     httpc->async_data->destination_buffer = buf;
2169     ret = InternetReadFileExA(httpc->out_request, &httpc->async_data->inet_buffers, IRF_ASYNC, 0);
2170     if (ret)
2171     {
2172         /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2173          * async ref now */
2174         RpcHttpAsyncData_Release(httpc->async_data);
2175         memcpy(buf, httpc->async_data->inet_buffers.lpvBuffer,
2176                httpc->async_data->inet_buffers.dwBufferLength);
2177         HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2178         httpc->async_data->inet_buffers.lpvBuffer = NULL;
2179         httpc->async_data->destination_buffer = NULL;
2180     }
2181     else
2182     {
2183         if (GetLastError() == ERROR_IO_PENDING)
2184         {
2185             HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2186             DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2187             if (result == WAIT_OBJECT_0)
2188                 ret = TRUE;
2189             else
2190             {
2191                 TRACE("call cancelled\n");
2192                 EnterCriticalSection(&httpc->async_data->cs);
2193                 httpc->async_data->destination_buffer = NULL;
2194                 LeaveCriticalSection(&httpc->async_data->cs);
2195                 break;
2196             }
2197         }
2198         else
2199         {
2200             HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2201             httpc->async_data->inet_buffers.lpvBuffer = NULL;
2202             httpc->async_data->destination_buffer = NULL;
2203             RpcHttpAsyncData_Release(httpc->async_data);
2204             break;
2205         }
2206     }
2207     if (!httpc->async_data->inet_buffers.dwBufferLength)
2208         break;
2209     bytes_left -= httpc->async_data->inet_buffers.dwBufferLength;
2210     buf += httpc->async_data->inet_buffers.dwBufferLength;
2211   }
2212   TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE");
2213   return ret ? count : -1;
2214 }
2215
2216 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2217 {
2218   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2219   RPC_STATUS status;
2220   DWORD hdr_length;
2221   LONG dwRead;
2222   RpcPktCommonHdr common_hdr;
2223
2224   *Header = NULL;
2225
2226   TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2227
2228 again:
2229   /* read packet common header */
2230   dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2231   if (dwRead != sizeof(common_hdr)) {
2232     WARN("Short read of header, %d bytes\n", dwRead);
2233     status = RPC_S_PROTOCOL_ERROR;
2234     goto fail;
2235   }
2236   if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2237       !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2238   {
2239     FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2240     status = RPC_S_PROTOCOL_ERROR;
2241     goto fail;
2242   }
2243
2244   status = RPCRT4_ValidateCommonHeader(&common_hdr);
2245   if (status != RPC_S_OK) goto fail;
2246
2247   hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
2248   if (hdr_length == 0) {
2249     WARN("header length == 0\n");
2250     status = RPC_S_PROTOCOL_ERROR;
2251     goto fail;
2252   }
2253
2254   *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
2255   if (!*Header)
2256   {
2257     status = RPC_S_OUT_OF_RESOURCES;
2258     goto fail;
2259   }
2260   memcpy(*Header, &common_hdr, sizeof(common_hdr));
2261
2262   /* read the rest of packet header */
2263   dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
2264   if (dwRead != hdr_length - sizeof(common_hdr)) {
2265     WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
2266     status = RPC_S_PROTOCOL_ERROR;
2267     goto fail;
2268   }
2269
2270   if (common_hdr.frag_len - hdr_length)
2271   {
2272     *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
2273     if (!*Payload)
2274     {
2275       status = RPC_S_OUT_OF_RESOURCES;
2276       goto fail;
2277     }
2278
2279     dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
2280     if (dwRead != common_hdr.frag_len - hdr_length)
2281     {
2282       WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
2283       status = RPC_S_PROTOCOL_ERROR;
2284       goto fail;
2285     }
2286   }
2287   else
2288     *Payload = NULL;
2289
2290   if ((*Header)->common.ptype == PKT_HTTP)
2291   {
2292     if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
2293     {
2294       ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
2295       status = RPC_S_PROTOCOL_ERROR;
2296       goto fail;
2297     }
2298     if ((*Header)->http.flags == 0x0001)
2299     {
2300       TRACE("http idle packet, waiting for real packet\n");
2301       if ((*Header)->http.num_data_items != 0)
2302       {
2303         ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
2304         status = RPC_S_PROTOCOL_ERROR;
2305         goto fail;
2306       }
2307     }
2308     else if ((*Header)->http.flags == 0x0002)
2309     {
2310       ULONG bytes_transmitted;
2311       ULONG flow_control_increment;
2312       UUID pipe_uuid;
2313       status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
2314                                                  Connection->server,
2315                                                  &bytes_transmitted,
2316                                                  &flow_control_increment,
2317                                                  &pipe_uuid);
2318       if (status != RPC_S_OK)
2319         goto fail;
2320       TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
2321             bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
2322       /* FIXME: do something with parsed data */
2323     }
2324     else
2325     {
2326       FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
2327       status = RPC_S_PROTOCOL_ERROR;
2328       goto fail;
2329     }
2330     RPCRT4_FreeHeader(*Header);
2331     *Header = NULL;
2332     HeapFree(GetProcessHeap(), 0, *Payload);
2333     *Payload = NULL;
2334     goto again;
2335   }
2336
2337   /* success */
2338   status = RPC_S_OK;
2339
2340   httpc->bytes_received += common_hdr.frag_len;
2341
2342   TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
2343
2344   if (httpc->bytes_received > httpc->flow_control_mark)
2345   {
2346     RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
2347                                                        httpc->bytes_received,
2348                                                        httpc->flow_control_increment,
2349                                                        &httpc->out_pipe_uuid);
2350     if (hdr)
2351     {
2352       DWORD bytes_written;
2353       BOOL ret2;
2354       TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
2355       ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
2356       RPCRT4_FreeHeader(hdr);
2357       if (ret2)
2358         httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
2359     }
2360   }
2361
2362 fail:
2363   if (status != RPC_S_OK) {
2364     RPCRT4_FreeHeader(*Header);
2365     *Header = NULL;
2366     HeapFree(GetProcessHeap(), 0, *Payload);
2367     *Payload = NULL;
2368   }
2369   return status;
2370 }
2371
2372 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
2373                                  const void *buffer, unsigned int count)
2374 {
2375   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2376   DWORD bytes_written;
2377   BOOL ret;
2378
2379   httpc->last_sent_time = ~0UL; /* disable idle packet sending */
2380   ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
2381   httpc->last_sent_time = GetTickCount();
2382   TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
2383   return ret ? bytes_written : -1;
2384 }
2385
2386 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
2387 {
2388   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2389
2390   TRACE("\n");
2391
2392   SetEvent(httpc->timer_cancelled);
2393   if (httpc->in_request)
2394     InternetCloseHandle(httpc->in_request);
2395   httpc->in_request = NULL;
2396   if (httpc->out_request)
2397     InternetCloseHandle(httpc->out_request);
2398   httpc->out_request = NULL;
2399   if (httpc->app_info)
2400     InternetCloseHandle(httpc->app_info);
2401   httpc->app_info = NULL;
2402   if (httpc->session)
2403     InternetCloseHandle(httpc->session);
2404   httpc->session = NULL;
2405   RpcHttpAsyncData_Release(httpc->async_data);
2406   if (httpc->cancel_event)
2407     CloseHandle(httpc->cancel_event);
2408
2409   return 0;
2410 }
2411
2412 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
2413 {
2414   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2415
2416   SetEvent(httpc->cancel_event);
2417 }
2418
2419 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
2420 {
2421   BOOL ret;
2422   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2423
2424   RpcHttpAsyncData_AddRef(httpc->async_data);
2425   ret = InternetQueryDataAvailable(httpc->out_request,
2426     &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
2427   if (ret)
2428   {
2429       /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2430        * async ref now */
2431       RpcHttpAsyncData_Release(httpc->async_data);
2432   }
2433   else
2434   {
2435     if (GetLastError() == ERROR_IO_PENDING)
2436     {
2437       HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2438       DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2439       if (result != WAIT_OBJECT_0)
2440       {
2441         TRACE("call cancelled\n");
2442         return -1;
2443       }
2444     }
2445     else
2446     {
2447       RpcHttpAsyncData_Release(httpc->async_data);
2448       return -1;
2449     }
2450   }
2451
2452   /* success */
2453   return 0;
2454 }
2455
2456 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
2457                                                  const char *networkaddr,
2458                                                  const char *endpoint)
2459 {
2460     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
2461                                           EPM_PROTOCOL_HTTP, endpoint);
2462 }
2463
2464 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
2465                                                        size_t tower_size,
2466                                                        char **networkaddr,
2467                                                        char **endpoint)
2468 {
2469     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
2470                                             networkaddr, EPM_PROTOCOL_HTTP,
2471                                             endpoint);
2472 }
2473
2474 static const struct connection_ops conn_protseq_list[] = {
2475   { "ncacn_np",
2476     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
2477     rpcrt4_conn_np_alloc,
2478     rpcrt4_ncacn_np_open,
2479     rpcrt4_ncacn_np_handoff,
2480     rpcrt4_conn_np_read,
2481     rpcrt4_conn_np_write,
2482     rpcrt4_conn_np_close,
2483     rpcrt4_conn_np_cancel_call,
2484     rpcrt4_conn_np_wait_for_incoming_data,
2485     rpcrt4_ncacn_np_get_top_of_tower,
2486     rpcrt4_ncacn_np_parse_top_of_tower,
2487     NULL,
2488   },
2489   { "ncalrpc",
2490     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
2491     rpcrt4_conn_np_alloc,
2492     rpcrt4_ncalrpc_open,
2493     rpcrt4_ncalrpc_handoff,
2494     rpcrt4_conn_np_read,
2495     rpcrt4_conn_np_write,
2496     rpcrt4_conn_np_close,
2497     rpcrt4_conn_np_cancel_call,
2498     rpcrt4_conn_np_wait_for_incoming_data,
2499     rpcrt4_ncalrpc_get_top_of_tower,
2500     rpcrt4_ncalrpc_parse_top_of_tower,
2501     NULL,
2502   },
2503   { "ncacn_ip_tcp",
2504     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
2505     rpcrt4_conn_tcp_alloc,
2506     rpcrt4_ncacn_ip_tcp_open,
2507     rpcrt4_conn_tcp_handoff,
2508     rpcrt4_conn_tcp_read,
2509     rpcrt4_conn_tcp_write,
2510     rpcrt4_conn_tcp_close,
2511     rpcrt4_conn_tcp_cancel_call,
2512     rpcrt4_conn_tcp_wait_for_incoming_data,
2513     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
2514     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
2515     NULL,
2516   },
2517   { "ncacn_http",
2518     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
2519     rpcrt4_ncacn_http_alloc,
2520     rpcrt4_ncacn_http_open,
2521     rpcrt4_ncacn_http_handoff,
2522     rpcrt4_ncacn_http_read,
2523     rpcrt4_ncacn_http_write,
2524     rpcrt4_ncacn_http_close,
2525     rpcrt4_ncacn_http_cancel_call,
2526     rpcrt4_ncacn_http_wait_for_incoming_data,
2527     rpcrt4_ncacn_http_get_top_of_tower,
2528     rpcrt4_ncacn_http_parse_top_of_tower,
2529     rpcrt4_ncacn_http_receive_fragment,
2530   },
2531 };
2532
2533
2534 static const struct protseq_ops protseq_list[] =
2535 {
2536     {
2537         "ncacn_np",
2538         rpcrt4_protseq_np_alloc,
2539         rpcrt4_protseq_np_signal_state_changed,
2540         rpcrt4_protseq_np_get_wait_array,
2541         rpcrt4_protseq_np_free_wait_array,
2542         rpcrt4_protseq_np_wait_for_new_connection,
2543         rpcrt4_protseq_ncacn_np_open_endpoint,
2544     },
2545     {
2546         "ncalrpc",
2547         rpcrt4_protseq_np_alloc,
2548         rpcrt4_protseq_np_signal_state_changed,
2549         rpcrt4_protseq_np_get_wait_array,
2550         rpcrt4_protseq_np_free_wait_array,
2551         rpcrt4_protseq_np_wait_for_new_connection,
2552         rpcrt4_protseq_ncalrpc_open_endpoint,
2553     },
2554 #ifdef HAVE_SOCKETPAIR
2555     {
2556         "ncacn_ip_tcp",
2557         rpcrt4_protseq_sock_alloc,
2558         rpcrt4_protseq_sock_signal_state_changed,
2559         rpcrt4_protseq_sock_get_wait_array,
2560         rpcrt4_protseq_sock_free_wait_array,
2561         rpcrt4_protseq_sock_wait_for_new_connection,
2562         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
2563     },
2564 #endif
2565 };
2566
2567 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
2568
2569 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
2570 {
2571   unsigned int i;
2572   for(i=0; i<ARRAYSIZE(protseq_list); i++)
2573     if (!strcmp(protseq_list[i].name, protseq))
2574       return &protseq_list[i];
2575   return NULL;
2576 }
2577
2578 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
2579 {
2580     unsigned int i;
2581     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
2582         if (!strcmp(conn_protseq_list[i].name, protseq))
2583             return &conn_protseq_list[i];
2584     return NULL;
2585 }
2586
2587 /**** interface to rest of code ****/
2588
2589 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
2590 {
2591   TRACE("(Connection == ^%p)\n", Connection);
2592
2593   assert(!Connection->server);
2594   return Connection->ops->open_connection_client(Connection);
2595 }
2596
2597 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
2598 {
2599   TRACE("(Connection == ^%p)\n", Connection);
2600   if (SecIsValidHandle(&Connection->ctx))
2601   {
2602     DeleteSecurityContext(&Connection->ctx);
2603     SecInvalidateHandle(&Connection->ctx);
2604   }
2605   rpcrt4_conn_close(Connection);
2606   return RPC_S_OK;
2607 }
2608
2609 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
2610     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
2611     LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
2612 {
2613   const struct connection_ops *ops;
2614   RpcConnection* NewConnection;
2615
2616   ops = rpcrt4_get_conn_protseq_ops(Protseq);
2617   if (!ops)
2618   {
2619     FIXME("not supported for protseq %s\n", Protseq);
2620     return RPC_S_PROTSEQ_NOT_SUPPORTED;
2621   }
2622
2623   NewConnection = ops->alloc();
2624   NewConnection->Next = NULL;
2625   NewConnection->server_binding = NULL;
2626   NewConnection->server = server;
2627   NewConnection->ops = ops;
2628   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
2629   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
2630   NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
2631   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
2632   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
2633   NewConnection->NextCallId = 1;
2634
2635   SecInvalidateHandle(&NewConnection->ctx);
2636   memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
2637   NewConnection->attr = 0;
2638   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
2639   NewConnection->AuthInfo = AuthInfo;
2640   NewConnection->encryption_auth_len = 0;
2641   NewConnection->signature_auth_len = 0;
2642   if (QOS) RpcQualityOfService_AddRef(QOS);
2643   NewConnection->QOS = QOS;
2644
2645   list_init(&NewConnection->conn_pool_entry);
2646   NewConnection->async_state = NULL;
2647
2648   TRACE("connection: %p\n", NewConnection);
2649   *Connection = NewConnection;
2650
2651   return RPC_S_OK;
2652 }
2653
2654 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
2655 {
2656   RPC_STATUS err;
2657
2658   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
2659                                 rpcrt4_conn_get_name(OldConnection),
2660                                 OldConnection->NetworkAddr,
2661                                 OldConnection->Endpoint, NULL,
2662                                 OldConnection->AuthInfo, OldConnection->QOS);
2663   if (err == RPC_S_OK)
2664     rpcrt4_conn_handoff(OldConnection, *Connection);
2665   return err;
2666 }
2667
2668 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
2669 {
2670   TRACE("connection: %p\n", Connection);
2671
2672   RPCRT4_CloseConnection(Connection);
2673   RPCRT4_strfree(Connection->Endpoint);
2674   RPCRT4_strfree(Connection->NetworkAddr);
2675   HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
2676   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
2677   if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
2678
2679   /* server-only */
2680   if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
2681
2682   HeapFree(GetProcessHeap(), 0, Connection);
2683   return RPC_S_OK;
2684 }
2685
2686 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
2687                                       size_t *tower_size,
2688                                       const char *protseq,
2689                                       const char *networkaddr,
2690                                       const char *endpoint)
2691 {
2692     twr_empty_floor_t *protocol_floor;
2693     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
2694
2695     *tower_size = 0;
2696
2697     if (!protseq_ops)
2698         return RPC_S_INVALID_RPC_PROTSEQ;
2699
2700     if (!tower_data)
2701     {
2702         *tower_size = sizeof(*protocol_floor);
2703         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
2704         return RPC_S_OK;
2705     }
2706
2707     protocol_floor = (twr_empty_floor_t *)tower_data;
2708     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
2709     protocol_floor->protid = protseq_ops->epm_protocols[0];
2710     protocol_floor->count_rhs = 0;
2711
2712     tower_data += sizeof(*protocol_floor);
2713
2714     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
2715     if (!*tower_size)
2716         return EPT_S_NOT_REGISTERED;
2717
2718     *tower_size += sizeof(*protocol_floor);
2719
2720     return RPC_S_OK;
2721 }
2722
2723 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
2724                                         size_t tower_size,
2725                                         char **protseq,
2726                                         char **networkaddr,
2727                                         char **endpoint)
2728 {
2729     const twr_empty_floor_t *protocol_floor;
2730     const twr_empty_floor_t *floor4;
2731     const struct connection_ops *protseq_ops = NULL;
2732     RPC_STATUS status;
2733     unsigned int i;
2734
2735     if (tower_size < sizeof(*protocol_floor))
2736         return EPT_S_NOT_REGISTERED;
2737
2738     protocol_floor = (const twr_empty_floor_t *)tower_data;
2739     tower_data += sizeof(*protocol_floor);
2740     tower_size -= sizeof(*protocol_floor);
2741     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
2742         (protocol_floor->count_rhs > tower_size))
2743         return EPT_S_NOT_REGISTERED;
2744     tower_data += protocol_floor->count_rhs;
2745     tower_size -= protocol_floor->count_rhs;
2746
2747     floor4 = (const twr_empty_floor_t *)tower_data;
2748     if ((tower_size < sizeof(*floor4)) ||
2749         (floor4->count_lhs != sizeof(floor4->protid)))
2750         return EPT_S_NOT_REGISTERED;
2751
2752     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
2753         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
2754             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
2755         {
2756             protseq_ops = &conn_protseq_list[i];
2757             break;
2758         }
2759
2760     if (!protseq_ops)
2761         return EPT_S_NOT_REGISTERED;
2762
2763     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
2764
2765     if ((status == RPC_S_OK) && protseq)
2766     {
2767         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
2768         strcpy(*protseq, protseq_ops->name);
2769     }
2770
2771     return status;
2772 }
2773
2774 /***********************************************************************
2775  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
2776  *
2777  * Checks if the given protocol sequence is known by the RPC system.
2778  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
2779  *
2780  */
2781 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
2782 {
2783   char ps[0x10];
2784
2785   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
2786                       ps, sizeof ps, NULL, NULL);
2787   if (rpcrt4_get_conn_protseq_ops(ps))
2788     return RPC_S_OK;
2789
2790   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
2791
2792   return RPC_S_INVALID_RPC_PROTSEQ;
2793 }
2794
2795 /***********************************************************************
2796  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
2797  */
2798 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
2799 {
2800   UNICODE_STRING protseqW;
2801
2802   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
2803   {
2804     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
2805     RtlFreeUnicodeString(&protseqW);
2806     return ret;
2807   }
2808   return RPC_S_OUT_OF_MEMORY;
2809 }