xref: /reactos/dll/win32/rpcrt4/rpc_transport.c (revision 37b2c145)
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 "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #ifdef __REACTOS__
29 #define NONAMELESSUNION
30 #endif
31 #include "ws2tcpip.h"
32 
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <assert.h>
37 
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winnls.h"
41 #include "winerror.h"
42 #include "wininet.h"
43 #include "wine/winternl.h"
44 #include "winioctl.h"
45 
46 #include "rpc.h"
47 #include "rpcndr.h"
48 
49 #include "wine/debug.h"
50 
51 #include "rpc_binding.h"
52 #include "rpc_assoc.h"
53 #include "rpc_message.h"
54 #include "rpc_server.h"
55 #include "epm_towers.h"
56 
57 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
58 
59 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
60 
61 #ifdef __REACTOS__ /* FIXME: Inspect */
62 BOOL WINAPI CancelIoEx(HANDLE handle, LPOVERLAPPED lpOverlapped)
63 {
64      IO_STATUS_BLOCK    io_status;
65 
66     NtCancelIoFile(handle, &io_status);
67     if (io_status.u.Status)
68     {
69         SetLastError( RtlNtStatusToDosError( io_status.u.Status ) );
70         return FALSE;
71     }
72     return TRUE;
73 }
74 #endif
75 
76 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection);
77 
78 /**** ncacn_np support ****/
79 
80 typedef struct _RpcConnection_np
81 {
82     RpcConnection common;
83     HANDLE pipe;
84     HANDLE listen_event;
85     char *listen_pipe;
86     IO_STATUS_BLOCK io_status;
87     HANDLE event_cache;
88     BOOL read_closed;
89 } RpcConnection_np;
90 
91 static RpcConnection *rpcrt4_conn_np_alloc(void)
92 {
93   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
94   return &npc->common;
95 }
96 
97 static HANDLE get_np_event(RpcConnection_np *connection)
98 {
99     HANDLE event = InterlockedExchangePointer(&connection->event_cache, NULL);
100     return event ? event : CreateEventW(NULL, TRUE, FALSE, NULL);
101 }
102 
103 static void release_np_event(RpcConnection_np *connection, HANDLE event)
104 {
105     event = InterlockedExchangePointer(&connection->event_cache, event);
106     if (event)
107         CloseHandle(event);
108 }
109 
110 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *conn)
111 {
112     RpcConnection_np *connection = (RpcConnection_np *) conn;
113 
114     TRACE("listening on %s\n", connection->listen_pipe);
115 
116     connection->pipe = CreateNamedPipeA(connection->listen_pipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
117                                         PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
118                                         PIPE_UNLIMITED_INSTANCES,
119                                         RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
120     if (connection->pipe == INVALID_HANDLE_VALUE)
121     {
122         WARN("CreateNamedPipe failed with error %d\n", GetLastError());
123         if (GetLastError() == ERROR_FILE_EXISTS)
124             return RPC_S_DUPLICATE_ENDPOINT;
125         else
126             return RPC_S_CANT_CREATE_ENDPOINT;
127     }
128 
129     return RPC_S_OK;
130 }
131 
132 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
133 {
134   RpcConnection_np *npc = (RpcConnection_np *) Connection;
135   HANDLE pipe;
136   DWORD err, dwMode;
137 
138   TRACE("connecting to %s\n", pname);
139 
140   while (TRUE) {
141     DWORD dwFlags = 0;
142     if (Connection->QOS)
143     {
144         dwFlags = SECURITY_SQOS_PRESENT;
145         switch (Connection->QOS->qos->ImpersonationType)
146         {
147             case RPC_C_IMP_LEVEL_DEFAULT:
148                 /* FIXME: what to do here? */
149                 break;
150             case RPC_C_IMP_LEVEL_ANONYMOUS:
151                 dwFlags |= SECURITY_ANONYMOUS;
152                 break;
153             case RPC_C_IMP_LEVEL_IDENTIFY:
154                 dwFlags |= SECURITY_IDENTIFICATION;
155                 break;
156             case RPC_C_IMP_LEVEL_IMPERSONATE:
157                 dwFlags |= SECURITY_IMPERSONATION;
158                 break;
159             case RPC_C_IMP_LEVEL_DELEGATE:
160                 dwFlags |= SECURITY_DELEGATION;
161                 break;
162         }
163         if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
164             dwFlags |= SECURITY_CONTEXT_TRACKING;
165     }
166     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
167                        OPEN_EXISTING, dwFlags | FILE_FLAG_OVERLAPPED, 0);
168     if (pipe != INVALID_HANDLE_VALUE) break;
169     err = GetLastError();
170     if (err == ERROR_PIPE_BUSY) {
171       if (WaitNamedPipeA(pname, NMPWAIT_USE_DEFAULT_WAIT)) {
172         TRACE("retrying busy server\n");
173         continue;
174       }
175       TRACE("connection failed, error=%x\n", err);
176       return RPC_S_SERVER_TOO_BUSY;
177 #ifdef __REACTOS__
178     } else if (err == ERROR_BAD_NETPATH) {
179       TRACE("connection failed, error=%x\n", err);
180       return RPC_S_SERVER_UNAVAILABLE;
181 #endif
182     }
183     if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
184       err = GetLastError();
185       WARN("connection failed, error=%x\n", err);
186       return RPC_S_SERVER_UNAVAILABLE;
187     }
188   }
189 
190   /* success */
191   /* pipe is connected; change to message-read mode. */
192   dwMode = PIPE_READMODE_MESSAGE;
193   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
194   npc->pipe = pipe;
195 
196   return RPC_S_OK;
197 }
198 
199 static char *ncalrpc_pipe_name(const char *endpoint)
200 {
201   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
202   char *pipe_name;
203 
204   /* protseq=ncalrpc: supposed to use NT LPC ports,
205    * but we'll implement it with named pipes for now */
206   pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
207   strcat(strcpy(pipe_name, prefix), endpoint);
208   return pipe_name;
209 }
210 
211 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
212 {
213   RpcConnection_np *npc = (RpcConnection_np *) Connection;
214   RPC_STATUS r;
215   LPSTR pname;
216 
217   /* already connected? */
218   if (npc->pipe)
219     return RPC_S_OK;
220 
221   pname = ncalrpc_pipe_name(Connection->Endpoint);
222   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
223   I_RpcFree(pname);
224 
225   return r;
226 }
227 
228 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
229 {
230   RPC_STATUS r;
231   RpcConnection *Connection;
232   char generated_endpoint[22];
233 
234   if (!endpoint)
235   {
236     static LONG lrpc_nameless_id;
237     DWORD process_id = GetCurrentProcessId();
238     ULONG id = InterlockedIncrement(&lrpc_nameless_id);
239     snprintf(generated_endpoint, sizeof(generated_endpoint),
240              "LRPC%08x.%08x", process_id, id);
241     endpoint = generated_endpoint;
242   }
243 
244   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
245                               endpoint, NULL, NULL, NULL, NULL);
246   if (r != RPC_S_OK)
247       return r;
248 
249   ((RpcConnection_np*)Connection)->listen_pipe = ncalrpc_pipe_name(Connection->Endpoint);
250   r = rpcrt4_conn_create_pipe(Connection);
251 
252   EnterCriticalSection(&protseq->cs);
253   list_add_head(&protseq->listeners, &Connection->protseq_entry);
254   Connection->protseq = protseq;
255   LeaveCriticalSection(&protseq->cs);
256 
257   return r;
258 }
259 
260 #ifdef __REACTOS__
261 static char *ncacn_pipe_name(const char *server, const char *endpoint)
262 #else
263 static char *ncacn_pipe_name(const char *endpoint)
264 #endif
265 {
266 #ifdef __REACTOS__
267   static const char prefix[] = "\\\\";
268   static const char local[] = ".";
269   char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
270   DWORD bufLen = ARRAY_SIZE(ComputerName);
271 #else
272   static const char prefix[] = "\\\\.";
273 #endif
274   char *pipe_name;
275 
276 #ifdef __REACTOS__
277   if (server != NULL && *server != 0)
278   {
279     /* Trim any leading UNC server prefix. */
280     if (server[0] == '\\' && server[1] == '\\')
281       server += 2;
282 
283     /* If the server represents the local computer, use instead
284      * the local prefix to avoid a round in UNC name resolution. */
285     if (GetComputerNameA(ComputerName, &bufLen) &&
286         (stricmp(ComputerName, server) == 0))
287     {
288       server = local;
289     }
290   }
291   else
292   {
293     server = local;
294   }
295 #endif
296 
297   /* protseq=ncacn_np: named pipes */
298 #ifdef __REACTOS__
299   pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(server) + strlen(endpoint));
300   strcpy(pipe_name, prefix);
301   strcat(pipe_name, server);
302   strcat(pipe_name, endpoint);
303 #else
304   pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
305   strcat(strcpy(pipe_name, prefix), endpoint);
306 #endif
307   return pipe_name;
308 }
309 
310 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
311 {
312   RpcConnection_np *npc = (RpcConnection_np *) Connection;
313   RPC_STATUS r;
314   LPSTR pname;
315 
316   /* already connected? */
317   if (npc->pipe)
318     return RPC_S_OK;
319 
320 #ifdef __REACTOS__
321   pname = ncacn_pipe_name(Connection->NetworkAddr, Connection->Endpoint);
322 #else
323   pname = ncacn_pipe_name(Connection->Endpoint);
324 #endif
325   r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
326   I_RpcFree(pname);
327 
328   return r;
329 }
330 
331 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
332 {
333   RPC_STATUS r;
334   RpcConnection *Connection;
335   char generated_endpoint[26];
336 
337   if (!endpoint)
338   {
339     static LONG np_nameless_id;
340     DWORD process_id = GetCurrentProcessId();
341     ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
342     snprintf(generated_endpoint, sizeof(generated_endpoint),
343              "\\\\pipe\\\\%08x.%03x", process_id, id);
344     endpoint = generated_endpoint;
345   }
346 
347   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
348                               endpoint, NULL, NULL, NULL, NULL);
349   if (r != RPC_S_OK)
350     return r;
351 
352 #ifdef __REACTOS__
353   ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(NULL, Connection->Endpoint);
354 #else
355   ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(Connection->Endpoint);
356 #endif
357   r = rpcrt4_conn_create_pipe(Connection);
358 
359   EnterCriticalSection(&protseq->cs);
360   list_add_head(&protseq->listeners, &Connection->protseq_entry);
361   Connection->protseq = protseq;
362   LeaveCriticalSection(&protseq->cs);
363 
364   return r;
365 }
366 
367 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
368 {
369     /* because of the way named pipes work, we'll transfer the connected pipe
370      * to the child, then reopen the server binding to continue listening */
371 
372     new_npc->pipe = old_npc->pipe;
373     old_npc->pipe = 0;
374     assert(!old_npc->listen_event);
375 }
376 
377 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
378 {
379   DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
380   RPC_STATUS status;
381 
382   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
383   status = rpcrt4_conn_create_pipe(old_conn);
384 
385   /* Store the local computer name as the NetworkAddr for ncacn_np as long as
386    * we don't support named pipes over the network. */
387   new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
388   if (!GetComputerNameA(new_conn->NetworkAddr, &len))
389   {
390     ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
391     return RPC_S_OUT_OF_RESOURCES;
392   }
393 
394   return status;
395 }
396 
397 static RPC_STATUS is_pipe_listening(const char *pipe_name)
398 {
399   return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING;
400 }
401 
402 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint)
403 {
404   char *pipe_name;
405   RPC_STATUS status;
406 
407 #ifdef __REACTOS__
408   pipe_name = ncacn_pipe_name(NULL, endpoint);
409 #else
410   pipe_name = ncacn_pipe_name(endpoint);
411 #endif
412   status = is_pipe_listening(pipe_name);
413   I_RpcFree(pipe_name);
414   return status;
415 }
416 
417 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint)
418 {
419   char *pipe_name;
420   RPC_STATUS status;
421 
422   pipe_name = ncalrpc_pipe_name(endpoint);
423   status = is_pipe_listening(pipe_name);
424   I_RpcFree(pipe_name);
425   return status;
426 }
427 
428 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
429 {
430   DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
431   RPC_STATUS status;
432 
433   TRACE("%s\n", old_conn->Endpoint);
434 
435   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
436   status = rpcrt4_conn_create_pipe(old_conn);
437 
438   /* Store the local computer name as the NetworkAddr for ncalrpc. */
439   new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
440   if (!GetComputerNameA(new_conn->NetworkAddr, &len))
441   {
442     ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
443     return RPC_S_OUT_OF_RESOURCES;
444   }
445 
446   return status;
447 }
448 
449 static int rpcrt4_conn_np_read(RpcConnection *conn, void *buffer, unsigned int count)
450 {
451     RpcConnection_np *connection = (RpcConnection_np *) conn;
452     HANDLE event;
453     NTSTATUS status;
454 
455     event = get_np_event(connection);
456     if (!event)
457         return -1;
458 
459     if (connection->read_closed)
460         status = STATUS_CANCELLED;
461     else
462         status = NtReadFile(connection->pipe, event, NULL, NULL, &connection->io_status, buffer, count, NULL, NULL);
463     if (status == STATUS_PENDING)
464     {
465         /* check read_closed again before waiting to avoid a race */
466         if (connection->read_closed)
467         {
468             IO_STATUS_BLOCK io_status;
469 #ifdef __REACTOS__ /* FIXME: We should also cancel I/O for other threads */
470             NtCancelIoFile(connection->pipe, &io_status);
471 #else
472             NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
473 #endif
474         }
475         WaitForSingleObject(event, INFINITE);
476         status = connection->io_status.u.Status;
477     }
478     release_np_event(connection, event);
479     return status && status != STATUS_BUFFER_OVERFLOW ? -1 : connection->io_status.Information;
480 }
481 
482 static int rpcrt4_conn_np_write(RpcConnection *conn, const void *buffer, unsigned int count)
483 {
484     RpcConnection_np *connection = (RpcConnection_np *) conn;
485     IO_STATUS_BLOCK io_status;
486     HANDLE event;
487     NTSTATUS status;
488 
489     event = get_np_event(connection);
490     if (!event)
491         return -1;
492 
493     status = NtWriteFile(connection->pipe, event, NULL, NULL, &io_status, buffer, count, NULL, NULL);
494     if (status == STATUS_PENDING)
495     {
496         WaitForSingleObject(event, INFINITE);
497         status = io_status.u.Status;
498     }
499     release_np_event(connection, event);
500     if (status)
501         return -1;
502 
503     assert(io_status.Information == count);
504     return count;
505 }
506 
507 static int rpcrt4_conn_np_close(RpcConnection *conn)
508 {
509     RpcConnection_np *connection = (RpcConnection_np *) conn;
510     if (connection->pipe)
511     {
512         FlushFileBuffers(connection->pipe);
513         CloseHandle(connection->pipe);
514         connection->pipe = 0;
515     }
516     if (connection->listen_event)
517     {
518         CloseHandle(connection->listen_event);
519         connection->listen_event = 0;
520     }
521     if (connection->event_cache)
522     {
523         CloseHandle(connection->event_cache);
524         connection->event_cache = 0;
525     }
526     return 0;
527 }
528 
529 static void rpcrt4_conn_np_close_read(RpcConnection *conn)
530 {
531     RpcConnection_np *connection = (RpcConnection_np*)conn;
532     IO_STATUS_BLOCK io_status;
533 
534     connection->read_closed = TRUE;
535 #ifdef __REACTOS__ /* FIXME: We should also cancel I/O for other threads */
536     NtCancelIoFile(connection->pipe, &io_status);
537 #else
538     NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
539 #endif
540 }
541 
542 static void rpcrt4_conn_np_cancel_call(RpcConnection *conn)
543 {
544     RpcConnection_np *connection = (RpcConnection_np *)conn;
545     CancelIoEx(connection->pipe, NULL);
546 }
547 
548 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *conn)
549 {
550     return rpcrt4_conn_np_read(conn, NULL, 0);
551 }
552 
553 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
554                                                const char *networkaddr,
555                                                const char *endpoint)
556 {
557     twr_empty_floor_t *smb_floor;
558     twr_empty_floor_t *nb_floor;
559     size_t size;
560     size_t networkaddr_size;
561     size_t endpoint_size;
562 
563     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
564 
565     networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
566     endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
567     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
568 
569     if (!tower_data)
570         return size;
571 
572     smb_floor = (twr_empty_floor_t *)tower_data;
573 
574     tower_data += sizeof(*smb_floor);
575 
576     smb_floor->count_lhs = sizeof(smb_floor->protid);
577     smb_floor->protid = EPM_PROTOCOL_SMB;
578     smb_floor->count_rhs = endpoint_size;
579 
580     if (endpoint)
581         memcpy(tower_data, endpoint, endpoint_size);
582     else
583         tower_data[0] = 0;
584     tower_data += endpoint_size;
585 
586     nb_floor = (twr_empty_floor_t *)tower_data;
587 
588     tower_data += sizeof(*nb_floor);
589 
590     nb_floor->count_lhs = sizeof(nb_floor->protid);
591     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
592     nb_floor->count_rhs = networkaddr_size;
593 
594     if (networkaddr)
595         memcpy(tower_data, networkaddr, networkaddr_size);
596     else
597         tower_data[0] = 0;
598 
599     return size;
600 }
601 
602 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
603                                                      size_t tower_size,
604                                                      char **networkaddr,
605                                                      char **endpoint)
606 {
607     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
608     const twr_empty_floor_t *nb_floor;
609 
610     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
611 
612     if (tower_size < sizeof(*smb_floor))
613         return EPT_S_NOT_REGISTERED;
614 
615     tower_data += sizeof(*smb_floor);
616     tower_size -= sizeof(*smb_floor);
617 
618     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
619         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
620         (smb_floor->count_rhs > tower_size) ||
621         (tower_data[smb_floor->count_rhs - 1] != '\0'))
622         return EPT_S_NOT_REGISTERED;
623 
624     if (endpoint)
625     {
626         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
627         if (!*endpoint)
628             return RPC_S_OUT_OF_RESOURCES;
629         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
630     }
631     tower_data += smb_floor->count_rhs;
632     tower_size -= smb_floor->count_rhs;
633 
634     if (tower_size < sizeof(*nb_floor))
635         return EPT_S_NOT_REGISTERED;
636 
637     nb_floor = (const twr_empty_floor_t *)tower_data;
638 
639     tower_data += sizeof(*nb_floor);
640     tower_size -= sizeof(*nb_floor);
641 
642     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
643         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
644         (nb_floor->count_rhs > tower_size) ||
645         (tower_data[nb_floor->count_rhs - 1] != '\0'))
646         return EPT_S_NOT_REGISTERED;
647 
648     if (networkaddr)
649     {
650         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
651         if (!*networkaddr)
652         {
653             if (endpoint)
654             {
655                 I_RpcFree(*endpoint);
656                 *endpoint = NULL;
657             }
658             return RPC_S_OUT_OF_RESOURCES;
659         }
660         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
661     }
662 
663     return RPC_S_OK;
664 }
665 
666 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
667 {
668     RpcConnection_np *npc = (RpcConnection_np *)conn;
669     BOOL ret;
670 
671     TRACE("(%p)\n", conn);
672 
673     if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
674         return RPCRT4_default_impersonate_client(conn);
675 
676     ret = ImpersonateNamedPipeClient(npc->pipe);
677     if (!ret)
678     {
679         DWORD error = GetLastError();
680         WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
681         switch (error)
682         {
683         case ERROR_CANNOT_IMPERSONATE:
684             return RPC_S_NO_CONTEXT_AVAILABLE;
685         }
686     }
687     return RPC_S_OK;
688 }
689 
690 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
691 {
692     BOOL ret;
693 
694     TRACE("(%p)\n", conn);
695 
696     if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
697         return RPCRT4_default_revert_to_self(conn);
698 
699     ret = RevertToSelf();
700     if (!ret)
701     {
702         WARN("RevertToSelf failed with error %u\n", GetLastError());
703         return RPC_S_NO_CONTEXT_AVAILABLE;
704     }
705     return RPC_S_OK;
706 }
707 
708 typedef struct _RpcServerProtseq_np
709 {
710     RpcServerProtseq common;
711     HANDLE mgr_event;
712 } RpcServerProtseq_np;
713 
714 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
715 {
716     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
717     if (ps)
718         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
719     return &ps->common;
720 }
721 
722 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
723 {
724     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
725     SetEvent(npps->mgr_event);
726 }
727 
728 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
729 {
730     HANDLE *objs = prev_array;
731     RpcConnection_np *conn;
732     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
733 
734     EnterCriticalSection(&protseq->cs);
735 
736     /* open and count connections */
737     *count = 1;
738     LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
739     {
740         if (!conn->pipe && rpcrt4_conn_create_pipe(&conn->common) != RPC_S_OK)
741             continue;
742         if (!conn->listen_event)
743         {
744             NTSTATUS status;
745             HANDLE event;
746 
747             event = get_np_event(conn);
748             if (!event)
749                 continue;
750 
751             status = NtFsControlFile(conn->pipe, event, NULL, NULL, &conn->io_status, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
752             switch (status)
753             {
754             case STATUS_SUCCESS:
755             case STATUS_PIPE_CONNECTED:
756                 conn->io_status.u.Status = status;
757                 SetEvent(event);
758                 break;
759             case STATUS_PENDING:
760                 break;
761             default:
762                 ERR("pipe listen error %x\n", status);
763                 continue;
764             }
765 
766             conn->listen_event = event;
767         }
768         (*count)++;
769     }
770 
771     /* make array of connections */
772     if (objs)
773         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
774     else
775         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
776     if (!objs)
777     {
778         ERR("couldn't allocate objs\n");
779         LeaveCriticalSection(&protseq->cs);
780         return NULL;
781     }
782 
783     objs[0] = npps->mgr_event;
784     *count = 1;
785     LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
786     {
787         if (conn->listen_event)
788             objs[(*count)++] = conn->listen_event;
789     }
790     LeaveCriticalSection(&protseq->cs);
791     return objs;
792 }
793 
794 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
795 {
796     HeapFree(GetProcessHeap(), 0, array);
797 }
798 
799 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
800 {
801     HANDLE b_handle;
802     HANDLE *objs = wait_array;
803     DWORD res;
804     RpcConnection *cconn = NULL;
805     RpcConnection_np *conn;
806 
807     if (!objs)
808         return -1;
809 
810     do
811     {
812         /* an alertable wait isn't strictly necessary, but due to our
813          * overlapped I/O implementation in Wine we need to free some memory
814          * by the file user APC being called, even if no completion routine was
815          * specified at the time of starting the async operation */
816         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
817     } while (res == WAIT_IO_COMPLETION);
818 
819     if (res == WAIT_OBJECT_0)
820         return 0;
821     else if (res == WAIT_FAILED)
822     {
823         ERR("wait failed with error %d\n", GetLastError());
824         return -1;
825     }
826     else
827     {
828         b_handle = objs[res - WAIT_OBJECT_0];
829         /* find which connection got a RPC */
830         EnterCriticalSection(&protseq->cs);
831         LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
832         {
833             if (b_handle == conn->listen_event)
834             {
835                 release_np_event(conn, conn->listen_event);
836                 conn->listen_event = NULL;
837                 if (conn->io_status.u.Status == STATUS_SUCCESS || conn->io_status.u.Status == STATUS_PIPE_CONNECTED)
838                     cconn = rpcrt4_spawn_connection(&conn->common);
839                 else
840                     ERR("listen failed %x\n", conn->io_status.u.Status);
841                 break;
842             }
843         }
844         LeaveCriticalSection(&protseq->cs);
845         if (!cconn)
846         {
847             ERR("failed to locate connection for handle %p\n", b_handle);
848             return -1;
849         }
850         RPCRT4_new_client(cconn);
851         return 1;
852     }
853 }
854 
855 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
856                                               const char *networkaddr,
857                                               const char *endpoint)
858 {
859     twr_empty_floor_t *pipe_floor;
860     size_t size;
861     size_t endpoint_size;
862 
863     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
864 
865     endpoint_size = strlen(endpoint) + 1;
866     size = sizeof(*pipe_floor) + endpoint_size;
867 
868     if (!tower_data)
869         return size;
870 
871     pipe_floor = (twr_empty_floor_t *)tower_data;
872 
873     tower_data += sizeof(*pipe_floor);
874 
875     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
876     pipe_floor->protid = EPM_PROTOCOL_PIPE;
877     pipe_floor->count_rhs = endpoint_size;
878 
879     memcpy(tower_data, endpoint, endpoint_size);
880 
881     return size;
882 }
883 
884 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
885                                                     size_t tower_size,
886                                                     char **networkaddr,
887                                                     char **endpoint)
888 {
889     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
890 
891     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
892 
893     if (tower_size < sizeof(*pipe_floor))
894         return EPT_S_NOT_REGISTERED;
895 
896     tower_data += sizeof(*pipe_floor);
897     tower_size -= sizeof(*pipe_floor);
898 
899     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
900         (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
901         (pipe_floor->count_rhs > tower_size) ||
902         (tower_data[pipe_floor->count_rhs - 1] != '\0'))
903         return EPT_S_NOT_REGISTERED;
904 
905     if (networkaddr)
906         *networkaddr = NULL;
907 
908     if (endpoint)
909     {
910         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
911         if (!*endpoint)
912             return RPC_S_OUT_OF_RESOURCES;
913         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
914     }
915 
916     return RPC_S_OK;
917 }
918 
919 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
920 {
921     return FALSE;
922 }
923 
924 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
925                                            unsigned char *in_buffer,
926                                            unsigned int in_size,
927                                            unsigned char *out_buffer,
928                                            unsigned int *out_size)
929 {
930     /* since this protocol is local to the machine there is no need to
931      * authenticate the caller */
932     *out_size = 0;
933     return RPC_S_OK;
934 }
935 
936 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
937     enum secure_packet_direction dir,
938     RpcPktHdr *hdr, unsigned int hdr_size,
939     unsigned char *stub_data, unsigned int stub_data_size,
940     RpcAuthVerifier *auth_hdr,
941     unsigned char *auth_value, unsigned int auth_value_size)
942 {
943     /* since this protocol is local to the machine there is no need to secure
944      * the packet */
945     return RPC_S_OK;
946 }
947 
948 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
949     RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
950     ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
951 {
952     TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
953           server_princ_name, authn_level, authn_svc, authz_svc, flags);
954 
955     if (privs)
956     {
957         FIXME("privs not implemented\n");
958         *privs = NULL;
959     }
960     if (server_princ_name)
961     {
962         FIXME("server_princ_name not implemented\n");
963         *server_princ_name = NULL;
964     }
965     if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
966     if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
967     if (authz_svc)
968     {
969         FIXME("authorization service not implemented\n");
970         *authz_svc = RPC_C_AUTHZ_NONE;
971     }
972     if (flags)
973         FIXME("flags 0x%x not implemented\n", flags);
974 
975     return RPC_S_OK;
976 }
977 
978 /**** ncacn_ip_tcp support ****/
979 
980 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
981                                              const char *networkaddr,
982                                              unsigned char tcp_protid,
983                                              const char *endpoint)
984 {
985     twr_tcp_floor_t *tcp_floor;
986     twr_ipv4_floor_t *ipv4_floor;
987     struct addrinfo *ai;
988     struct addrinfo hints;
989     int ret;
990     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
991 
992     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
993 
994     if (!tower_data)
995         return size;
996 
997     tcp_floor = (twr_tcp_floor_t *)tower_data;
998     tower_data += sizeof(*tcp_floor);
999 
1000     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
1001 
1002     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
1003     tcp_floor->protid = tcp_protid;
1004     tcp_floor->count_rhs = sizeof(tcp_floor->port);
1005 
1006     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
1007     ipv4_floor->protid = EPM_PROTOCOL_IP;
1008     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
1009 
1010     hints.ai_flags          = AI_NUMERICHOST;
1011     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
1012     hints.ai_family         = PF_INET;
1013     hints.ai_socktype       = SOCK_STREAM;
1014     hints.ai_protocol       = IPPROTO_TCP;
1015     hints.ai_addrlen        = 0;
1016     hints.ai_addr           = NULL;
1017     hints.ai_canonname      = NULL;
1018     hints.ai_next           = NULL;
1019 
1020     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
1021     if (ret)
1022     {
1023         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
1024         if (ret)
1025         {
1026             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1027             return 0;
1028         }
1029     }
1030 
1031     if (ai->ai_family == PF_INET)
1032     {
1033         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1034         tcp_floor->port = sin->sin_port;
1035         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1036     }
1037     else
1038     {
1039         ERR("unexpected protocol family %d\n", ai->ai_family);
1040         freeaddrinfo(ai);
1041         return 0;
1042     }
1043 
1044     freeaddrinfo(ai);
1045 
1046     return size;
1047 }
1048 
1049 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1050                                                    size_t tower_size,
1051                                                    char **networkaddr,
1052                                                    unsigned char tcp_protid,
1053                                                    char **endpoint)
1054 {
1055     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1056     const twr_ipv4_floor_t *ipv4_floor;
1057     struct in_addr in_addr;
1058 
1059     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1060 
1061     if (tower_size < sizeof(*tcp_floor))
1062         return EPT_S_NOT_REGISTERED;
1063 
1064     tower_data += sizeof(*tcp_floor);
1065     tower_size -= sizeof(*tcp_floor);
1066 
1067     if (tower_size < sizeof(*ipv4_floor))
1068         return EPT_S_NOT_REGISTERED;
1069 
1070     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1071 
1072     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1073         (tcp_floor->protid != tcp_protid) ||
1074         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1075         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1076         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1077         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1078         return EPT_S_NOT_REGISTERED;
1079 
1080     if (endpoint)
1081     {
1082         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1083         if (!*endpoint)
1084             return RPC_S_OUT_OF_RESOURCES;
1085         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1086     }
1087 
1088     if (networkaddr)
1089     {
1090         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1091         if (!*networkaddr)
1092         {
1093             if (endpoint)
1094             {
1095                 I_RpcFree(*endpoint);
1096                 *endpoint = NULL;
1097             }
1098             return RPC_S_OUT_OF_RESOURCES;
1099         }
1100         in_addr.s_addr = ipv4_floor->ipv4addr;
1101         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1102         {
1103             ERR("inet_ntop: %u\n", WSAGetLastError());
1104             I_RpcFree(*networkaddr);
1105             *networkaddr = NULL;
1106             if (endpoint)
1107             {
1108                 I_RpcFree(*endpoint);
1109                 *endpoint = NULL;
1110             }
1111             return EPT_S_NOT_REGISTERED;
1112         }
1113     }
1114 
1115     return RPC_S_OK;
1116 }
1117 
1118 typedef struct _RpcConnection_tcp
1119 {
1120   RpcConnection common;
1121   int sock;
1122   HANDLE sock_event;
1123   HANDLE cancel_event;
1124 } RpcConnection_tcp;
1125 
1126 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1127 {
1128   static BOOL wsa_inited;
1129   if (!wsa_inited)
1130   {
1131     WSADATA wsadata;
1132     WSAStartup(MAKEWORD(2, 2), &wsadata);
1133     /* Note: WSAStartup can be called more than once so we don't bother with
1134      * making accesses to wsa_inited thread-safe */
1135     wsa_inited = TRUE;
1136   }
1137   tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1138   tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1139   if (!tcpc->sock_event || !tcpc->cancel_event)
1140   {
1141     ERR("event creation failed\n");
1142     if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1143     return FALSE;
1144   }
1145   return TRUE;
1146 }
1147 
1148 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1149 {
1150   HANDLE wait_handles[2];
1151   DWORD res;
1152   if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1153   {
1154     ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1155     return FALSE;
1156   }
1157   wait_handles[0] = tcpc->sock_event;
1158   wait_handles[1] = tcpc->cancel_event;
1159   res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1160   switch (res)
1161   {
1162   case WAIT_OBJECT_0:
1163     return TRUE;
1164   case WAIT_OBJECT_0 + 1:
1165     return FALSE;
1166   default:
1167     ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1168     return FALSE;
1169   }
1170 }
1171 
1172 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1173 {
1174   DWORD res;
1175   if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1176   {
1177     ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1178     return FALSE;
1179   }
1180   res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1181   switch (res)
1182   {
1183   case WAIT_OBJECT_0:
1184     return TRUE;
1185   default:
1186     ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1187     return FALSE;
1188   }
1189 }
1190 
1191 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1192 {
1193   RpcConnection_tcp *tcpc;
1194   tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
1195   if (tcpc == NULL)
1196     return NULL;
1197   tcpc->sock = -1;
1198   if (!rpcrt4_sock_wait_init(tcpc))
1199   {
1200     HeapFree(GetProcessHeap(), 0, tcpc);
1201     return NULL;
1202   }
1203   return &tcpc->common;
1204 }
1205 
1206 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1207 {
1208   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1209   int sock;
1210   int ret;
1211   struct addrinfo *ai;
1212   struct addrinfo *ai_cur;
1213   struct addrinfo hints;
1214 
1215   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1216 
1217   if (tcpc->sock != -1)
1218     return RPC_S_OK;
1219 
1220   hints.ai_flags          = 0;
1221   hints.ai_family         = PF_UNSPEC;
1222   hints.ai_socktype       = SOCK_STREAM;
1223   hints.ai_protocol       = IPPROTO_TCP;
1224   hints.ai_addrlen        = 0;
1225   hints.ai_addr           = NULL;
1226   hints.ai_canonname      = NULL;
1227   hints.ai_next           = NULL;
1228 
1229   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1230   if (ret)
1231   {
1232     ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1233       Connection->Endpoint, gai_strerror(ret));
1234     return RPC_S_SERVER_UNAVAILABLE;
1235   }
1236 
1237   for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1238   {
1239     int val;
1240     u_long nonblocking;
1241 
1242     if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1243     {
1244       TRACE("skipping non-IP/IPv6 address family\n");
1245       continue;
1246     }
1247 
1248     if (TRACE_ON(rpc))
1249     {
1250       char host[256];
1251       char service[256];
1252       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1253         host, sizeof(host), service, sizeof(service),
1254         NI_NUMERICHOST | NI_NUMERICSERV);
1255       TRACE("trying %s:%s\n", host, service);
1256     }
1257 
1258     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1259     if (sock == -1)
1260     {
1261       WARN("socket() failed: %u\n", WSAGetLastError());
1262       continue;
1263     }
1264 
1265     if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1266     {
1267       WARN("connect() failed: %u\n", WSAGetLastError());
1268       closesocket(sock);
1269       continue;
1270     }
1271 
1272     /* RPC depends on having minimal latency so disable the Nagle algorithm */
1273     val = 1;
1274     setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1275     nonblocking = 1;
1276     ioctlsocket(sock, FIONBIO, &nonblocking);
1277 
1278     tcpc->sock = sock;
1279 
1280     freeaddrinfo(ai);
1281     TRACE("connected\n");
1282     return RPC_S_OK;
1283   }
1284 
1285   freeaddrinfo(ai);
1286   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1287   return RPC_S_SERVER_UNAVAILABLE;
1288 }
1289 
1290 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1291 {
1292     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1293     int sock;
1294     int ret;
1295     struct addrinfo *ai;
1296     struct addrinfo *ai_cur;
1297     struct addrinfo hints;
1298 
1299     TRACE("(%p, %s)\n", protseq, endpoint);
1300 
1301     hints.ai_flags          = AI_PASSIVE /* for non-localhost addresses */;
1302     hints.ai_family         = PF_UNSPEC;
1303     hints.ai_socktype       = SOCK_STREAM;
1304     hints.ai_protocol       = IPPROTO_TCP;
1305     hints.ai_addrlen        = 0;
1306     hints.ai_addr           = NULL;
1307     hints.ai_canonname      = NULL;
1308     hints.ai_next           = NULL;
1309 
1310     ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1311     if (ret)
1312     {
1313         ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1314             gai_strerror(ret));
1315         if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1316             return RPC_S_INVALID_ENDPOINT_FORMAT;
1317         return RPC_S_CANT_CREATE_ENDPOINT;
1318     }
1319 
1320     for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1321     {
1322         RpcConnection_tcp *tcpc;
1323         RPC_STATUS create_status;
1324         struct sockaddr_storage sa;
1325         socklen_t sa_len;
1326         char service[NI_MAXSERV];
1327         u_long nonblocking;
1328 
1329         if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1330         {
1331             TRACE("skipping non-IP/IPv6 address family\n");
1332             continue;
1333         }
1334 
1335         if (TRACE_ON(rpc))
1336         {
1337             char host[256];
1338             getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1339                         host, sizeof(host), service, sizeof(service),
1340                         NI_NUMERICHOST | NI_NUMERICSERV);
1341             TRACE("trying %s:%s\n", host, service);
1342         }
1343 
1344         sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1345         if (sock == -1)
1346         {
1347             WARN("socket() failed: %u\n", WSAGetLastError());
1348             status = RPC_S_CANT_CREATE_ENDPOINT;
1349             continue;
1350         }
1351 
1352         ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1353         if (ret < 0)
1354         {
1355             WARN("bind failed: %u\n", WSAGetLastError());
1356             closesocket(sock);
1357             if (WSAGetLastError() == WSAEADDRINUSE)
1358               status = RPC_S_DUPLICATE_ENDPOINT;
1359             else
1360               status = RPC_S_CANT_CREATE_ENDPOINT;
1361             continue;
1362         }
1363 
1364         sa_len = sizeof(sa);
1365         if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1366         {
1367             WARN("getsockname() failed: %u\n", WSAGetLastError());
1368             closesocket(sock);
1369             status = RPC_S_CANT_CREATE_ENDPOINT;
1370             continue;
1371         }
1372 
1373         ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1374                           NULL, 0, service, sizeof(service),
1375                           NI_NUMERICSERV);
1376         if (ret)
1377         {
1378             WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1379             closesocket(sock);
1380             status = RPC_S_CANT_CREATE_ENDPOINT;
1381             continue;
1382         }
1383 
1384         create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1385                                                 protseq->Protseq, NULL,
1386                                                 service, NULL, NULL, NULL, NULL);
1387         if (create_status != RPC_S_OK)
1388         {
1389             closesocket(sock);
1390             status = create_status;
1391             continue;
1392         }
1393 
1394         tcpc->sock = sock;
1395         ret = listen(sock, protseq->MaxCalls);
1396         if (ret < 0)
1397         {
1398             WARN("listen failed: %u\n", WSAGetLastError());
1399             RPCRT4_ReleaseConnection(&tcpc->common);
1400             status = RPC_S_OUT_OF_RESOURCES;
1401             continue;
1402         }
1403         /* need a non-blocking socket, otherwise accept() has a potential
1404          * race-condition (poll() says it is readable, connection drops,
1405          * and accept() blocks until the next connection comes...)
1406          */
1407         nonblocking = 1;
1408         ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1409         if (ret < 0)
1410         {
1411             WARN("couldn't make socket non-blocking, error %d\n", ret);
1412             RPCRT4_ReleaseConnection(&tcpc->common);
1413             status = RPC_S_OUT_OF_RESOURCES;
1414             continue;
1415         }
1416 
1417         EnterCriticalSection(&protseq->cs);
1418         list_add_tail(&protseq->listeners, &tcpc->common.protseq_entry);
1419         tcpc->common.protseq = protseq;
1420         LeaveCriticalSection(&protseq->cs);
1421 
1422         freeaddrinfo(ai);
1423 
1424         /* since IPv4 and IPv6 share the same port space, we only need one
1425          * successful bind to listen for both */
1426         TRACE("listening on %s\n", endpoint);
1427         return RPC_S_OK;
1428     }
1429 
1430     freeaddrinfo(ai);
1431     ERR("couldn't listen on port %s\n", endpoint);
1432     return status;
1433 }
1434 
1435 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1436 {
1437   int ret;
1438   struct sockaddr_in address;
1439   socklen_t addrsize;
1440   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1441   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1442   u_long nonblocking;
1443 
1444   addrsize = sizeof(address);
1445   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1446   if (ret < 0)
1447   {
1448     ERR("Failed to accept a TCP connection: error %d\n", ret);
1449     return RPC_S_OUT_OF_RESOURCES;
1450   }
1451 
1452   nonblocking = 1;
1453   ioctlsocket(ret, FIONBIO, &nonblocking);
1454   client->sock = ret;
1455 
1456   client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN);
1457   ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
1458   if (ret != 0)
1459   {
1460     ERR("Failed to retrieve the IP address, error %d\n", ret);
1461     return RPC_S_OUT_OF_RESOURCES;
1462   }
1463 
1464   TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr);
1465   return RPC_S_OK;
1466 }
1467 
1468 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1469                                 void *buffer, unsigned int count)
1470 {
1471   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1472   int bytes_read = 0;
1473   while (bytes_read != count)
1474   {
1475     int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1476     if (!r)
1477       return -1;
1478     else if (r > 0)
1479       bytes_read += r;
1480     else if (WSAGetLastError() == WSAEINTR)
1481       continue;
1482     else if (WSAGetLastError() != WSAEWOULDBLOCK)
1483     {
1484       WARN("recv() failed: %u\n", WSAGetLastError());
1485       return -1;
1486     }
1487     else
1488     {
1489       if (!rpcrt4_sock_wait_for_recv(tcpc))
1490         return -1;
1491     }
1492   }
1493   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1494   return bytes_read;
1495 }
1496 
1497 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1498                                  const void *buffer, unsigned int count)
1499 {
1500   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1501   int bytes_written = 0;
1502   while (bytes_written != count)
1503   {
1504     int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1505     if (r >= 0)
1506       bytes_written += r;
1507     else if (WSAGetLastError() == WSAEINTR)
1508       continue;
1509     else if (WSAGetLastError() != WSAEWOULDBLOCK)
1510       return -1;
1511     else
1512     {
1513       if (!rpcrt4_sock_wait_for_send(tcpc))
1514         return -1;
1515     }
1516   }
1517   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1518   return bytes_written;
1519 }
1520 
1521 static int rpcrt4_conn_tcp_close(RpcConnection *conn)
1522 {
1523     RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1524 
1525     TRACE("%d\n", connection->sock);
1526 
1527     if (connection->sock != -1)
1528         closesocket(connection->sock);
1529     connection->sock = -1;
1530     CloseHandle(connection->sock_event);
1531     CloseHandle(connection->cancel_event);
1532     return 0;
1533 }
1534 
1535 static void rpcrt4_conn_tcp_close_read(RpcConnection *conn)
1536 {
1537     RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1538     shutdown(connection->sock, SD_RECEIVE);
1539 }
1540 
1541 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *conn)
1542 {
1543     RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1544 
1545     TRACE("%p\n", connection);
1546 
1547     SetEvent(connection->cancel_event);
1548 }
1549 
1550 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint)
1551 {
1552     FIXME("\n");
1553     return RPC_S_ACCESS_DENIED;
1554 }
1555 
1556 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1557 {
1558     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1559 
1560     TRACE("%p\n", Connection);
1561 
1562     if (!rpcrt4_sock_wait_for_recv(tcpc))
1563         return -1;
1564     return 0;
1565 }
1566 
1567 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1568                                                    const char *networkaddr,
1569                                                    const char *endpoint)
1570 {
1571     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1572                                           EPM_PROTOCOL_TCP, endpoint);
1573 }
1574 
1575 typedef struct _RpcServerProtseq_sock
1576 {
1577     RpcServerProtseq common;
1578     HANDLE mgr_event;
1579 } RpcServerProtseq_sock;
1580 
1581 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1582 {
1583     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
1584     if (ps)
1585     {
1586         static BOOL wsa_inited;
1587         if (!wsa_inited)
1588         {
1589             WSADATA wsadata;
1590             WSAStartup(MAKEWORD(2, 2), &wsadata);
1591             /* Note: WSAStartup can be called more than once so we don't bother with
1592              * making accesses to wsa_inited thread-safe */
1593             wsa_inited = TRUE;
1594         }
1595         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1596     }
1597     return &ps->common;
1598 }
1599 
1600 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1601 {
1602     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1603     SetEvent(sockps->mgr_event);
1604 }
1605 
1606 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1607 {
1608     HANDLE *objs = prev_array;
1609     RpcConnection_tcp *conn;
1610     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1611 
1612     EnterCriticalSection(&protseq->cs);
1613 
1614     /* open and count connections */
1615     *count = 1;
1616     LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1617     {
1618         if (conn->sock != -1)
1619             (*count)++;
1620     }
1621 
1622     /* make array of connections */
1623     if (objs)
1624         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1625     else
1626         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1627     if (!objs)
1628     {
1629         ERR("couldn't allocate objs\n");
1630         LeaveCriticalSection(&protseq->cs);
1631         return NULL;
1632     }
1633 
1634     objs[0] = sockps->mgr_event;
1635     *count = 1;
1636     LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1637     {
1638         if (conn->sock != -1)
1639         {
1640             int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1641             if (res == SOCKET_ERROR)
1642                 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1643             else
1644             {
1645                 objs[*count] = conn->sock_event;
1646                 (*count)++;
1647             }
1648         }
1649     }
1650     LeaveCriticalSection(&protseq->cs);
1651     return objs;
1652 }
1653 
1654 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1655 {
1656     HeapFree(GetProcessHeap(), 0, array);
1657 }
1658 
1659 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1660 {
1661     HANDLE b_handle;
1662     HANDLE *objs = wait_array;
1663     DWORD res;
1664     RpcConnection *cconn = NULL;
1665     RpcConnection_tcp *conn;
1666 
1667     if (!objs)
1668         return -1;
1669 
1670     do
1671     {
1672         /* an alertable wait isn't strictly necessary, but due to our
1673          * overlapped I/O implementation in Wine we need to free some memory
1674          * by the file user APC being called, even if no completion routine was
1675          * specified at the time of starting the async operation */
1676         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1677     } while (res == WAIT_IO_COMPLETION);
1678 
1679     if (res == WAIT_OBJECT_0)
1680         return 0;
1681     if (res == WAIT_FAILED)
1682     {
1683         ERR("wait failed with error %d\n", GetLastError());
1684         return -1;
1685     }
1686 
1687     b_handle = objs[res - WAIT_OBJECT_0];
1688 
1689     /* find which connection got a RPC */
1690     EnterCriticalSection(&protseq->cs);
1691     LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1692     {
1693         if (b_handle == conn->sock_event)
1694         {
1695             cconn = rpcrt4_spawn_connection(&conn->common);
1696             break;
1697         }
1698     }
1699     LeaveCriticalSection(&protseq->cs);
1700     if (!cconn)
1701     {
1702         ERR("failed to locate connection for handle %p\n", b_handle);
1703         return -1;
1704     }
1705 
1706     RPCRT4_new_client(cconn);
1707     return 1;
1708 }
1709 
1710 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1711                                                          size_t tower_size,
1712                                                          char **networkaddr,
1713                                                          char **endpoint)
1714 {
1715     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1716                                             networkaddr, EPM_PROTOCOL_TCP,
1717                                             endpoint);
1718 }
1719 
1720 /**** ncacn_http support ****/
1721 
1722 /* 60 seconds is the period native uses */
1723 #define HTTP_IDLE_TIME 60000
1724 
1725 /* reference counted to avoid a race between a cancelled call's connection
1726  * being destroyed and the asynchronous InternetReadFileEx call being
1727  * completed */
1728 typedef struct _RpcHttpAsyncData
1729 {
1730     LONG refs;
1731     HANDLE completion_event;
1732     WORD async_result;
1733     INTERNET_BUFFERSW inet_buffers;
1734     CRITICAL_SECTION cs;
1735 } RpcHttpAsyncData;
1736 
1737 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1738 {
1739     return InterlockedIncrement(&data->refs);
1740 }
1741 
1742 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1743 {
1744     ULONG refs = InterlockedDecrement(&data->refs);
1745     if (!refs)
1746     {
1747         TRACE("destroying async data %p\n", data);
1748         CloseHandle(data->completion_event);
1749         HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1750         data->cs.DebugInfo->Spare[0] = 0;
1751         DeleteCriticalSection(&data->cs);
1752         HeapFree(GetProcessHeap(), 0, data);
1753     }
1754     return refs;
1755 }
1756 
1757 static void prepare_async_request(RpcHttpAsyncData *async_data)
1758 {
1759     ResetEvent(async_data->completion_event);
1760     RpcHttpAsyncData_AddRef(async_data);
1761 }
1762 
1763 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event)
1764 {
1765     HANDLE handles[2] = { async_data->completion_event, cancel_event };
1766     DWORD res;
1767 
1768     if(call_ret) {
1769         RpcHttpAsyncData_Release(async_data);
1770         return RPC_S_OK;
1771     }
1772 
1773     if(GetLastError() != ERROR_IO_PENDING) {
1774         RpcHttpAsyncData_Release(async_data);
1775         ERR("Request failed with error %d\n", GetLastError());
1776         return RPC_S_SERVER_UNAVAILABLE;
1777     }
1778 
1779     res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
1780     if(res != WAIT_OBJECT_0) {
1781         TRACE("Cancelled\n");
1782         return RPC_S_CALL_CANCELLED;
1783     }
1784 
1785     if(async_data->async_result) {
1786         ERR("Async request failed with error %d\n", async_data->async_result);
1787         return RPC_S_SERVER_UNAVAILABLE;
1788     }
1789 
1790     return RPC_S_OK;
1791 }
1792 
1793 struct authinfo
1794 {
1795     DWORD        scheme;
1796     CredHandle   cred;
1797     CtxtHandle   ctx;
1798     TimeStamp    exp;
1799     ULONG        attr;
1800     ULONG        max_token;
1801     char        *data;
1802     unsigned int data_len;
1803     BOOL         finished; /* finished authenticating */
1804 };
1805 
1806 typedef struct _RpcConnection_http
1807 {
1808     RpcConnection common;
1809     HINTERNET app_info;
1810     HINTERNET session;
1811     HINTERNET in_request;
1812     HINTERNET out_request;
1813     WCHAR *servername;
1814     HANDLE timer_cancelled;
1815     HANDLE cancel_event;
1816     DWORD last_sent_time;
1817     ULONG bytes_received;
1818     ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1819     ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1820     UUID connection_uuid;
1821     UUID in_pipe_uuid;
1822     UUID out_pipe_uuid;
1823     RpcHttpAsyncData *async_data;
1824 } RpcConnection_http;
1825 
1826 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1827 {
1828     RpcConnection_http *httpc;
1829     httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1830     if (!httpc) return NULL;
1831     httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1832     if (!httpc->async_data)
1833     {
1834         HeapFree(GetProcessHeap(), 0, httpc);
1835         return NULL;
1836     }
1837     TRACE("async data = %p\n", httpc->async_data);
1838     httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1839     httpc->async_data->refs = 1;
1840     httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW);
1841     InitializeCriticalSection(&httpc->async_data->cs);
1842     httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs");
1843     return &httpc->common;
1844 }
1845 
1846 typedef struct _HttpTimerThreadData
1847 {
1848     PVOID timer_param;
1849     DWORD *last_sent_time;
1850     HANDLE timer_cancelled;
1851 } HttpTimerThreadData;
1852 
1853 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1854 {
1855     HINTERNET in_request = param;
1856     RpcPktHdr *idle_pkt;
1857 
1858     idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1859                                       0, 0);
1860     if (idle_pkt)
1861     {
1862         DWORD bytes_written;
1863         InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1864         RPCRT4_FreeHeader(idle_pkt);
1865     }
1866 }
1867 
1868 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1869 {
1870     DWORD cur_time = GetTickCount();
1871     DWORD cached_last_sent_time = *last_sent_time;
1872     return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1873 }
1874 
1875 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1876 {
1877     HttpTimerThreadData *data_in = param;
1878     HttpTimerThreadData data;
1879     DWORD timeout;
1880 
1881     data = *data_in;
1882     HeapFree(GetProcessHeap(), 0, data_in);
1883 
1884     for (timeout = HTTP_IDLE_TIME;
1885          WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1886          timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1887     {
1888         /* are we too soon after last send? */
1889         if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME)
1890             continue;
1891         rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1892     }
1893 
1894     CloseHandle(data.timer_cancelled);
1895     return 0;
1896 }
1897 
1898 static VOID WINAPI rpcrt4_http_internet_callback(
1899      HINTERNET hInternet,
1900      DWORD_PTR dwContext,
1901      DWORD dwInternetStatus,
1902      LPVOID lpvStatusInformation,
1903      DWORD dwStatusInformationLength)
1904 {
1905     RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1906 
1907     switch (dwInternetStatus)
1908     {
1909     case INTERNET_STATUS_REQUEST_COMPLETE:
1910         TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1911         if (async_data)
1912         {
1913             INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation;
1914 
1915             async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError;
1916             SetEvent(async_data->completion_event);
1917             RpcHttpAsyncData_Release(async_data);
1918         }
1919         break;
1920     }
1921 }
1922 
1923 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1924 {
1925     BOOL ret;
1926     DWORD status_code;
1927     DWORD size;
1928     DWORD index;
1929     WCHAR buf[32];
1930     WCHAR *status_text = buf;
1931     TRACE("\n");
1932 
1933     index = 0;
1934     size = sizeof(status_code);
1935     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1936     if (!ret)
1937         return GetLastError();
1938     if (status_code == HTTP_STATUS_OK)
1939         return RPC_S_OK;
1940     index = 0;
1941     size = sizeof(buf);
1942     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1943     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1944     {
1945         status_text = HeapAlloc(GetProcessHeap(), 0, size);
1946         ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1947     }
1948 
1949     ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
1950     if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
1951 
1952     if (status_code == HTTP_STATUS_DENIED)
1953         return ERROR_ACCESS_DENIED;
1954     return RPC_S_SERVER_UNAVAILABLE;
1955 }
1956 
1957 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
1958 {
1959     static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
1960     LPWSTR proxy = NULL;
1961     LPWSTR user = NULL;
1962     LPWSTR password = NULL;
1963     LPWSTR servername = NULL;
1964     const WCHAR *option;
1965     INTERNET_PORT port;
1966 
1967     if (httpc->common.QOS &&
1968         (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1969     {
1970         const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1971         if (http_cred->TransportCredentials)
1972         {
1973             WCHAR *p;
1974             const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1975             ULONG len = cred->DomainLength + 1 + cred->UserLength;
1976             user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1977             if (!user)
1978                 return RPC_S_OUT_OF_RESOURCES;
1979             p = user;
1980             if (cred->DomainLength)
1981             {
1982                 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1983                 p += cred->DomainLength;
1984                 *p = '\\';
1985                 p++;
1986             }
1987             memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1988             p[cred->UserLength] = 0;
1989 
1990             password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1991         }
1992     }
1993 
1994     for (option = httpc->common.NetworkOptions; option;
1995          option = (wcschr(option, ',') ? wcschr(option, ',')+1 : NULL))
1996     {
1997         static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
1998         static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
1999 
2000         if (!_wcsnicmp(option, wszRpcProxy, ARRAY_SIZE(wszRpcProxy)-1))
2001         {
2002             const WCHAR *value_start = option + ARRAY_SIZE(wszRpcProxy)-1;
2003             const WCHAR *value_end;
2004             const WCHAR *p;
2005 
2006             value_end = wcschr(option, ',');
2007             if (!value_end)
2008                 value_end = value_start + lstrlenW(value_start);
2009             for (p = value_start; p < value_end; p++)
2010                 if (*p == ':')
2011                 {
2012                     port = wcstol(p+1, NULL, 10);
2013                     value_end = p;
2014                     break;
2015                 }
2016             TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2017             servername = RPCRT4_strndupW(value_start, value_end-value_start);
2018         }
2019         else if (!_wcsnicmp(option, wszHttpProxy, ARRAY_SIZE(wszHttpProxy)-1))
2020         {
2021             const WCHAR *value_start = option + ARRAY_SIZE(wszHttpProxy)-1;
2022             const WCHAR *value_end;
2023 
2024             value_end = wcschr(option, ',');
2025             if (!value_end)
2026                 value_end = value_start + lstrlenW(value_start);
2027             TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2028             proxy = RPCRT4_strndupW(value_start, value_end-value_start);
2029         }
2030         else
2031             FIXME("unhandled option %s\n", debugstr_w(option));
2032     }
2033 
2034     httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
2035                                     NULL, NULL, INTERNET_FLAG_ASYNC);
2036     if (!httpc->app_info)
2037     {
2038         HeapFree(GetProcessHeap(), 0, password);
2039         HeapFree(GetProcessHeap(), 0, user);
2040         HeapFree(GetProcessHeap(), 0, proxy);
2041         HeapFree(GetProcessHeap(), 0, servername);
2042         ERR("InternetOpenW failed with error %d\n", GetLastError());
2043         return RPC_S_SERVER_UNAVAILABLE;
2044     }
2045     InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
2046 
2047     /* if no RpcProxy option specified, set the HTTP server address to the
2048      * RPC server address */
2049     if (!servername)
2050     {
2051         servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
2052         if (!servername)
2053         {
2054             HeapFree(GetProcessHeap(), 0, password);
2055             HeapFree(GetProcessHeap(), 0, user);
2056             HeapFree(GetProcessHeap(), 0, proxy);
2057             return RPC_S_OUT_OF_RESOURCES;
2058         }
2059         MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
2060     }
2061 
2062     port = (httpc->common.QOS &&
2063             (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2064             (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ?
2065             INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
2066 
2067     httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
2068                                       INTERNET_SERVICE_HTTP, 0, 0);
2069 
2070     HeapFree(GetProcessHeap(), 0, password);
2071     HeapFree(GetProcessHeap(), 0, user);
2072     HeapFree(GetProcessHeap(), 0, proxy);
2073 
2074     if (!httpc->session)
2075     {
2076         ERR("InternetConnectW failed with error %d\n", GetLastError());
2077         HeapFree(GetProcessHeap(), 0, servername);
2078         return RPC_S_SERVER_UNAVAILABLE;
2079     }
2080     httpc->servername = servername;
2081     return RPC_S_OK;
2082 }
2083 
2084 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2085                                   void *buffer, unsigned int count)
2086 {
2087     char *buf = buffer;
2088     BOOL ret;
2089     unsigned int bytes_left = count;
2090     RPC_STATUS status = RPC_S_OK;
2091 
2092     async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count);
2093 
2094     while (bytes_left)
2095     {
2096         async_data->inet_buffers.dwBufferLength = bytes_left;
2097         prepare_async_request(async_data);
2098         ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0);
2099         status = wait_async_request(async_data, ret, cancel_event);
2100         if (status != RPC_S_OK)
2101         {
2102             if (status == RPC_S_CALL_CANCELLED)
2103                 TRACE("call cancelled\n");
2104             break;
2105         }
2106 
2107         if (!async_data->inet_buffers.dwBufferLength)
2108             break;
2109         memcpy(buf, async_data->inet_buffers.lpvBuffer,
2110                async_data->inet_buffers.dwBufferLength);
2111 
2112         bytes_left -= async_data->inet_buffers.dwBufferLength;
2113         buf += async_data->inet_buffers.dwBufferLength;
2114     }
2115 
2116     HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
2117     async_data->inet_buffers.lpvBuffer = NULL;
2118 
2119     TRACE("%p %p %u -> %u\n", req, buffer, count, status);
2120     return status == RPC_S_OK ? count : -1;
2121 }
2122 
2123 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2124 {
2125     BYTE buf[20];
2126     BOOL ret;
2127     RPC_STATUS status;
2128 
2129     TRACE("sending echo request to server\n");
2130 
2131     prepare_async_request(async_data);
2132     ret = HttpSendRequestW(req, NULL, 0, NULL, 0);
2133     status = wait_async_request(async_data, ret, cancel_event);
2134     if (status != RPC_S_OK) return status;
2135 
2136     status = rpcrt4_http_check_response(req);
2137     if (status != RPC_S_OK) return status;
2138 
2139     rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf));
2140     /* FIXME: do something with retrieved data */
2141 
2142     return RPC_S_OK;
2143 }
2144 
2145 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len)
2146 {
2147     static const WCHAR fmtW[] =
2148         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0};
2149     WCHAR header[ARRAY_SIZE(fmtW) + 10];
2150 
2151     swprintf(header, fmtW, len);
2152     if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK;
2153     return RPC_S_SERVER_UNAVAILABLE;
2154 }
2155 
2156 /* prepare the in pipe for use by RPC packets */
2157 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2158                                               const UUID *connection_uuid, const UUID *in_pipe_uuid,
2159                                               const UUID *association_uuid, BOOL authorized)
2160 {
2161     BOOL ret;
2162     RPC_STATUS status;
2163     RpcPktHdr *hdr;
2164     INTERNET_BUFFERSW buffers_in;
2165     DWORD bytes_written;
2166 
2167     if (!authorized)
2168     {
2169         /* ask wininet to authorize, if necessary */
2170         status = send_echo_request(in_request, async_data, cancel_event);
2171         if (status != RPC_S_OK) return status;
2172     }
2173     memset(&buffers_in, 0, sizeof(buffers_in));
2174     buffers_in.dwStructSize = sizeof(buffers_in);
2175     /* FIXME: get this from the registry */
2176     buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2177     status = insert_content_length_header(in_request, buffers_in.dwBufferTotal);
2178     if (status != RPC_S_OK) return status;
2179 
2180     prepare_async_request(async_data);
2181     ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2182     status = wait_async_request(async_data, ret, cancel_event);
2183     if (status != RPC_S_OK) return status;
2184 
2185     TRACE("sending HTTP connect header to server\n");
2186     hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2187     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2188     ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2189     RPCRT4_FreeHeader(hdr);
2190     if (!ret)
2191     {
2192         ERR("InternetWriteFile failed with error %d\n", GetLastError());
2193         return RPC_S_SERVER_UNAVAILABLE;
2194     }
2195 
2196     return RPC_S_OK;
2197 }
2198 
2199 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data,
2200                                                HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data)
2201 {
2202     unsigned short data_len;
2203     unsigned int size;
2204 
2205     if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0)
2206         return RPC_S_SERVER_UNAVAILABLE;
2207     if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2208     {
2209         ERR("wrong packet type received %d or wrong frag_len %d\n",
2210             hdr->common.ptype, hdr->common.frag_len);
2211         return RPC_S_PROTOCOL_ERROR;
2212     }
2213 
2214     size = sizeof(hdr->http) - sizeof(hdr->common);
2215     if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0)
2216         return RPC_S_SERVER_UNAVAILABLE;
2217 
2218     data_len = hdr->common.frag_len - sizeof(hdr->http);
2219     if (data_len)
2220     {
2221         *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2222         if (!*data)
2223             return RPC_S_OUT_OF_RESOURCES;
2224         if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0)
2225         {
2226             HeapFree(GetProcessHeap(), 0, *data);
2227             return RPC_S_SERVER_UNAVAILABLE;
2228         }
2229     }
2230     else
2231         *data = NULL;
2232 
2233     if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2234     {
2235         ERR("invalid http packet\n");
2236         HeapFree(GetProcessHeap(), 0, *data);
2237         return RPC_S_PROTOCOL_ERROR;
2238     }
2239 
2240     return RPC_S_OK;
2241 }
2242 
2243 /* prepare the out pipe for use by RPC packets */
2244 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data,
2245                                                HANDLE cancel_event, const UUID *connection_uuid,
2246                                                const UUID *out_pipe_uuid, ULONG *flow_control_increment,
2247                                                BOOL authorized)
2248 {
2249     BOOL ret;
2250     RPC_STATUS status;
2251     RpcPktHdr *hdr;
2252     BYTE *data_from_server;
2253     RpcPktHdr pkt_from_server;
2254     ULONG field1, field3;
2255     BYTE buf[20];
2256 
2257     if (!authorized)
2258     {
2259         /* ask wininet to authorize, if necessary */
2260         status = send_echo_request(out_request, async_data, cancel_event);
2261         if (status != RPC_S_OK) return status;
2262     }
2263     else
2264         rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf));
2265 
2266     hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL);
2267     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2268 
2269     status = insert_content_length_header(out_request, hdr->common.frag_len);
2270     if (status != RPC_S_OK)
2271     {
2272         RPCRT4_FreeHeader(hdr);
2273         return status;
2274     }
2275 
2276     TRACE("sending HTTP connect header to server\n");
2277     prepare_async_request(async_data);
2278     ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2279     status = wait_async_request(async_data, ret, cancel_event);
2280     RPCRT4_FreeHeader(hdr);
2281     if (status != RPC_S_OK) return status;
2282 
2283     status = rpcrt4_http_check_response(out_request);
2284     if (status != RPC_S_OK) return status;
2285 
2286     status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2287                                           &pkt_from_server, &data_from_server);
2288     if (status != RPC_S_OK) return status;
2289     status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2290                                             &field1);
2291     HeapFree(GetProcessHeap(), 0, data_from_server);
2292     if (status != RPC_S_OK) return status;
2293     TRACE("received (%d) from first prepare header\n", field1);
2294 
2295     for (;;)
2296     {
2297         status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2298                                               &pkt_from_server, &data_from_server);
2299         if (status != RPC_S_OK) return status;
2300         if (pkt_from_server.http.flags != 0x0001) break;
2301 
2302         TRACE("http idle packet, waiting for real packet\n");
2303         HeapFree(GetProcessHeap(), 0, data_from_server);
2304         if (pkt_from_server.http.num_data_items != 0)
2305         {
2306             ERR("HTTP idle packet should have no data items instead of %d\n",
2307                 pkt_from_server.http.num_data_items);
2308             return RPC_S_PROTOCOL_ERROR;
2309         }
2310     }
2311     status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2312                                             &field1, flow_control_increment,
2313                                             &field3);
2314     HeapFree(GetProcessHeap(), 0, data_from_server);
2315     if (status != RPC_S_OK) return status;
2316     TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2317 
2318     return RPC_S_OK;
2319 }
2320 
2321 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
2322 {
2323     static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2324     UINT i = 0, x;
2325 
2326     while (len > 0)
2327     {
2328         /* first 6 bits, all from bin[0] */
2329         base64[i++] = enc[(bin[0] & 0xfc) >> 2];
2330         x = (bin[0] & 3) << 4;
2331 
2332         /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
2333         if (len == 1)
2334         {
2335             base64[i++] = enc[x];
2336             base64[i++] = '=';
2337             base64[i++] = '=';
2338             break;
2339         }
2340         base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
2341         x = (bin[1] & 0x0f) << 2;
2342 
2343         /* next 6 bits 4 from bin[1] and 2 from bin[2] */
2344         if (len == 2)
2345         {
2346             base64[i++] = enc[x];
2347             base64[i++] = '=';
2348             break;
2349         }
2350         base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
2351 
2352         /* last 6 bits, all from bin [2] */
2353         base64[i++] = enc[bin[2] & 0x3f];
2354         bin += 3;
2355         len -= 3;
2356     }
2357     base64[i] = 0;
2358     return i;
2359 }
2360 
2361 static inline char decode_char( WCHAR c )
2362 {
2363     if (c >= 'A' && c <= 'Z') return c - 'A';
2364     if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2365     if (c >= '0' && c <= '9') return c - '0' + 52;
2366     if (c == '+') return 62;
2367     if (c == '/') return 63;
2368     return 64;
2369 }
2370 
2371 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
2372 {
2373     unsigned int i = 0;
2374     char c0, c1, c2, c3;
2375     const WCHAR *p = base64;
2376 
2377     while (len > 4)
2378     {
2379         if ((c0 = decode_char( p[0] )) > 63) return 0;
2380         if ((c1 = decode_char( p[1] )) > 63) return 0;
2381         if ((c2 = decode_char( p[2] )) > 63) return 0;
2382         if ((c3 = decode_char( p[3] )) > 63) return 0;
2383 
2384         if (buf)
2385         {
2386             buf[i + 0] = (c0 << 2) | (c1 >> 4);
2387             buf[i + 1] = (c1 << 4) | (c2 >> 2);
2388             buf[i + 2] = (c2 << 6) |  c3;
2389         }
2390         len -= 4;
2391         i += 3;
2392         p += 4;
2393     }
2394     if (p[2] == '=')
2395     {
2396         if ((c0 = decode_char( p[0] )) > 63) return 0;
2397         if ((c1 = decode_char( p[1] )) > 63) return 0;
2398 
2399         if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
2400         i++;
2401     }
2402     else if (p[3] == '=')
2403     {
2404         if ((c0 = decode_char( p[0] )) > 63) return 0;
2405         if ((c1 = decode_char( p[1] )) > 63) return 0;
2406         if ((c2 = decode_char( p[2] )) > 63) return 0;
2407 
2408         if (buf)
2409         {
2410             buf[i + 0] = (c0 << 2) | (c1 >> 4);
2411             buf[i + 1] = (c1 << 4) | (c2 >> 2);
2412         }
2413         i += 2;
2414     }
2415     else
2416     {
2417         if ((c0 = decode_char( p[0] )) > 63) return 0;
2418         if ((c1 = decode_char( p[1] )) > 63) return 0;
2419         if ((c2 = decode_char( p[2] )) > 63) return 0;
2420         if ((c3 = decode_char( p[3] )) > 63) return 0;
2421 
2422         if (buf)
2423         {
2424             buf[i + 0] = (c0 << 2) | (c1 >> 4);
2425             buf[i + 1] = (c1 << 4) | (c2 >> 2);
2426             buf[i + 2] = (c2 << 6) |  c3;
2427         }
2428         i += 3;
2429     }
2430     return i;
2431 }
2432 
2433 static struct authinfo *alloc_authinfo(void)
2434 {
2435     struct authinfo *ret;
2436 
2437     if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL;
2438 
2439     SecInvalidateHandle(&ret->cred);
2440     SecInvalidateHandle(&ret->ctx);
2441     memset(&ret->exp, 0, sizeof(ret->exp));
2442     ret->scheme    = 0;
2443     ret->attr      = 0;
2444     ret->max_token = 0;
2445     ret->data      = NULL;
2446     ret->data_len  = 0;
2447     ret->finished  = FALSE;
2448     return ret;
2449 }
2450 
2451 static void destroy_authinfo(struct authinfo *info)
2452 {
2453     if (!info) return;
2454 
2455     if (SecIsValidHandle(&info->ctx))
2456         DeleteSecurityContext(&info->ctx);
2457     if (SecIsValidHandle(&info->cred))
2458         FreeCredentialsHandle(&info->cred);
2459 
2460     HeapFree(GetProcessHeap(), 0, info->data);
2461     HeapFree(GetProcessHeap(), 0, info);
2462 }
2463 
2464 static const WCHAR basicW[]     = {'B','a','s','i','c',0};
2465 static const WCHAR ntlmW[]      = {'N','T','L','M',0};
2466 static const WCHAR passportW[]  = {'P','a','s','s','p','o','r','t',0};
2467 static const WCHAR digestW[]    = {'D','i','g','e','s','t',0};
2468 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2469 
2470 static const struct
2471 {
2472     const WCHAR *str;
2473     unsigned int len;
2474     DWORD        scheme;
2475 }
2476 auth_schemes[] =
2477 {
2478     { basicW,     ARRAY_SIZE(basicW) - 1,     RPC_C_HTTP_AUTHN_SCHEME_BASIC },
2479     { ntlmW,      ARRAY_SIZE(ntlmW) - 1,      RPC_C_HTTP_AUTHN_SCHEME_NTLM },
2480     { passportW,  ARRAY_SIZE(passportW) - 1,  RPC_C_HTTP_AUTHN_SCHEME_PASSPORT },
2481     { digestW,    ARRAY_SIZE(digestW) - 1,    RPC_C_HTTP_AUTHN_SCHEME_DIGEST },
2482     { negotiateW, ARRAY_SIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE }
2483 };
2484 
2485 static DWORD auth_scheme_from_header( const WCHAR *header )
2486 {
2487     unsigned int i;
2488     for (i = 0; i < ARRAY_SIZE(auth_schemes); i++)
2489     {
2490         if (!_wcsnicmp( header, auth_schemes[i].str, auth_schemes[i].len ) &&
2491             (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
2492     }
2493     return 0;
2494 }
2495 
2496 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen)
2497 {
2498     DWORD len, index = 0;
2499     for (;;)
2500     {
2501         len = buflen;
2502         if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE;
2503         if (auth_scheme_from_header(buffer) == scheme) break;
2504     }
2505     return TRUE;
2506 }
2507 
2508 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername,
2509                                    const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr)
2510 {
2511     struct authinfo *info = *auth_ptr;
2512     SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials;
2513     RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2514 
2515     if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE;
2516 
2517     switch (creds->AuthnSchemes[0])
2518     {
2519     case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2520     {
2521         int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
2522         int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
2523 
2524         info->data_len = userlen + passlen + 1;
2525         if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len)))
2526         {
2527             status = RPC_S_OUT_OF_MEMORY;
2528             break;
2529         }
2530         WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL);
2531         info->data[userlen] = ':';
2532         WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL);
2533 
2534         info->scheme   = RPC_C_HTTP_AUTHN_SCHEME_BASIC;
2535         info->finished = TRUE;
2536         status = RPC_S_OK;
2537         break;
2538     }
2539     case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2540     case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2541     {
2542 
2543         static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2544         SECURITY_STATUS ret;
2545         SecBufferDesc out_desc, in_desc;
2546         SecBuffer out, in;
2547         ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE;
2548         SEC_WCHAR *scheme;
2549         int scheme_len;
2550         const WCHAR *p;
2551         WCHAR auth_value[2048];
2552         DWORD size = sizeof(auth_value);
2553         BOOL first = FALSE;
2554 
2555         if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW;
2556         else scheme = negotiateW;
2557         scheme_len = lstrlenW( scheme );
2558 
2559         if (!*auth_ptr)
2560         {
2561             TimeStamp exp;
2562             SecPkgInfoW *pkg_info;
2563 
2564             ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp);
2565             if (ret != SEC_E_OK) break;
2566 
2567             ret = QuerySecurityPackageInfoW(scheme, &pkg_info);
2568             if (ret != SEC_E_OK) break;
2569 
2570             info->max_token = pkg_info->cbMaxToken;
2571             FreeContextBuffer(pkg_info);
2572             first = TRUE;
2573         }
2574         else
2575         {
2576             if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break;
2577             if (auth_scheme_from_header(auth_value) != info->scheme)
2578             {
2579                 ERR("authentication scheme changed\n");
2580                 break;
2581             }
2582         }
2583         in.BufferType = SECBUFFER_TOKEN;
2584         in.cbBuffer   = 0;
2585         in.pvBuffer   = NULL;
2586 
2587         in_desc.ulVersion = 0;
2588         in_desc.cBuffers  = 1;
2589         in_desc.pBuffers  = &in;
2590 
2591         p = auth_value + scheme_len;
2592         if (!first && *p == ' ')
2593         {
2594             int len = lstrlenW(++p);
2595             in.cbBuffer = decode_base64(p, len, NULL);
2596             if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break;
2597             decode_base64(p, len, in.pvBuffer);
2598         }
2599         out.BufferType = SECBUFFER_TOKEN;
2600         out.cbBuffer   = info->max_token;
2601         if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer)))
2602         {
2603             HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2604             break;
2605         }
2606         out_desc.ulVersion = 0;
2607         out_desc.cBuffers  = 1;
2608         out_desc.pBuffers  = &out;
2609 
2610         ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx,
2611                                          first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP,
2612                                          in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc,
2613                                          &info->attr, &info->exp);
2614         HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2615         if (ret == SEC_E_OK)
2616         {
2617             HeapFree(GetProcessHeap(), 0, info->data);
2618             info->data     = out.pvBuffer;
2619             info->data_len = out.cbBuffer;
2620             info->finished = TRUE;
2621             TRACE("sending last auth packet\n");
2622             status = RPC_S_OK;
2623         }
2624         else if (ret == SEC_I_CONTINUE_NEEDED)
2625         {
2626             HeapFree(GetProcessHeap(), 0, info->data);
2627             info->data     = out.pvBuffer;
2628             info->data_len = out.cbBuffer;
2629             TRACE("sending next auth packet\n");
2630             status = RPC_S_OK;
2631         }
2632         else
2633         {
2634             ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret);
2635             HeapFree(GetProcessHeap(), 0, out.pvBuffer);
2636             break;
2637         }
2638         info->scheme = creds->AuthnSchemes[0];
2639         break;
2640     }
2641     default:
2642         FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]);
2643         break;
2644     }
2645 
2646     if (status != RPC_S_OK)
2647     {
2648         destroy_authinfo(info);
2649         *auth_ptr = NULL;
2650         return status;
2651     }
2652     *auth_ptr = info;
2653     return RPC_S_OK;
2654 }
2655 
2656 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len)
2657 {
2658     static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '};
2659     static const WCHAR basicW[] = {'B','a','s','i','c',' '};
2660     static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '};
2661     static const WCHAR ntlmW[] = {'N','T','L','M',' '};
2662     int scheme_len, auth_len = ARRAY_SIZE(authW), len = ((data_len + 2) * 4) / 3;
2663     const WCHAR *scheme_str;
2664     WCHAR *header, *ptr;
2665     RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2666 
2667     switch (scheme)
2668     {
2669     case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2670         scheme_str = basicW;
2671         scheme_len = ARRAY_SIZE(basicW);
2672         break;
2673     case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2674         scheme_str = negotiateW;
2675         scheme_len = ARRAY_SIZE(negotiateW);
2676         break;
2677     case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2678         scheme_str = ntlmW;
2679         scheme_len = ARRAY_SIZE(ntlmW);
2680         break;
2681     default:
2682         ERR("unknown scheme %u\n", scheme);
2683         return RPC_S_SERVER_UNAVAILABLE;
2684     }
2685     if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR))))
2686     {
2687         memcpy(header, authW, auth_len * sizeof(WCHAR));
2688         ptr = header + auth_len;
2689         memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR));
2690         ptr += scheme_len;
2691         len = encode_base64(data, data_len, ptr);
2692         ptr[len++] = '\r';
2693         ptr[len++] = '\n';
2694         ptr[len] = 0;
2695         if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE))
2696             status = RPC_S_OK;
2697         HeapFree(GetProcessHeap(), 0, header);
2698     }
2699     return status;
2700 }
2701 
2702 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2703 {
2704     DWORD count, len = 0, size = sizeof(len);
2705     char buf[2048];
2706 
2707     HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL);
2708     if (!len) return;
2709     for (;;)
2710     {
2711         count = min(sizeof(buf), len);
2712         if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return;
2713         len -= count;
2714     }
2715 }
2716 
2717 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request)
2718 {
2719     static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0};
2720     struct authinfo *info = NULL;
2721     RPC_STATUS status;
2722     BOOL ret;
2723 
2724     for (;;)
2725     {
2726         status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info);
2727         if (status != RPC_S_OK) break;
2728 
2729         status = insert_authorization_header(request, info->scheme, info->data, info->data_len);
2730         if (status != RPC_S_OK) break;
2731 
2732         prepare_async_request(httpc->async_data);
2733         ret = HttpSendRequestW(request, NULL, 0, NULL, 0);
2734         status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
2735         if (status != RPC_S_OK || info->finished) break;
2736 
2737         status = rpcrt4_http_check_response(request);
2738         if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break;
2739         drain_content(request, httpc->async_data, httpc->cancel_event);
2740     }
2741 
2742     if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
2743         HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
2744 
2745     destroy_authinfo(info);
2746     return status;
2747 }
2748 
2749 static BOOL has_credentials(RpcConnection_http *httpc)
2750 {
2751     RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
2752     SEC_WINNT_AUTH_IDENTITY_W *id;
2753 
2754     if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
2755         return FALSE;
2756 
2757     creds = httpc->common.QOS->qos->u.HttpCredentials;
2758     if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
2759         return FALSE;
2760 
2761     id = creds->TransportCredentials;
2762     if (!id || !id->User || !id->Password) return FALSE;
2763 
2764     return TRUE;
2765 }
2766 
2767 static BOOL is_secure(RpcConnection_http *httpc)
2768 {
2769     return httpc->common.QOS &&
2770            (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2771            (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2772 }
2773 
2774 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value)
2775 {
2776     static WCHAR httpW[] = {'h','t','t','p',0};
2777     static WCHAR httpsW[] = {'h','t','t','p','s',0};
2778     URL_COMPONENTSW uc;
2779     DWORD len;
2780     WCHAR *url;
2781     BOOL ret;
2782 
2783     if (!value) return RPC_S_OK;
2784 
2785     uc.dwStructSize     = sizeof(uc);
2786     uc.lpszScheme       = is_secure(httpc) ? httpsW : httpW;
2787     uc.dwSchemeLength   = 0;
2788     uc.lpszHostName     = httpc->servername;
2789     uc.dwHostNameLength = 0;
2790     uc.nPort            = 0;
2791     uc.lpszUserName     = NULL;
2792     uc.dwUserNameLength = 0;
2793     uc.lpszPassword     = NULL;
2794     uc.dwPasswordLength = 0;
2795     uc.lpszUrlPath      = NULL;
2796     uc.dwUrlPathLength  = 0;
2797     uc.lpszExtraInfo    = NULL;
2798     uc.dwExtraInfoLength = 0;
2799 
2800     if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
2801         return RPC_S_SERVER_UNAVAILABLE;
2802 
2803     if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY;
2804 
2805     len = len / sizeof(WCHAR) - 1;
2806     if (!InternetCreateUrlW(&uc, 0, url, &len))
2807     {
2808         HeapFree(GetProcessHeap(), 0, url);
2809         return RPC_S_SERVER_UNAVAILABLE;
2810     }
2811 
2812     ret = InternetSetCookieW(url, NULL, value);
2813     HeapFree(GetProcessHeap(), 0, url);
2814     if (!ret) return RPC_S_SERVER_UNAVAILABLE;
2815 
2816     return RPC_S_OK;
2817 }
2818 
2819 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2820 {
2821     RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2822     static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2823     static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2824     static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2825     static const WCHAR wszColon[] = {':',0};
2826     static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2827     LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2828     DWORD flags;
2829     WCHAR *url;
2830     RPC_STATUS status;
2831     BOOL secure, credentials;
2832     HttpTimerThreadData *timer_data;
2833     HANDLE thread;
2834 
2835     TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2836 
2837     if (Connection->server)
2838     {
2839         ERR("ncacn_http servers not supported yet\n");
2840         return RPC_S_SERVER_UNAVAILABLE;
2841     }
2842 
2843     if (httpc->in_request)
2844         return RPC_S_OK;
2845 
2846     httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2847 
2848     UuidCreate(&httpc->connection_uuid);
2849     UuidCreate(&httpc->in_pipe_uuid);
2850     UuidCreate(&httpc->out_pipe_uuid);
2851 
2852     status = rpcrt4_http_internet_connect(httpc);
2853     if (status != RPC_S_OK)
2854         return status;
2855 
2856     url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2857     if (!url)
2858         return RPC_S_OUT_OF_MEMORY;
2859     memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2860     MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+ARRAY_SIZE(wszRpcProxyPrefix)-1,
2861                         strlen(Connection->NetworkAddr)+1);
2862     lstrcatW(url, wszColon);
2863     MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+lstrlenW(url), strlen(Connection->Endpoint)+1);
2864 
2865     secure = is_secure(httpc);
2866     credentials = has_credentials(httpc);
2867 
2868     flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
2869             INTERNET_FLAG_NO_AUTO_REDIRECT;
2870     if (secure) flags |= INTERNET_FLAG_SECURE;
2871     if (credentials) flags |= INTERNET_FLAG_NO_AUTH;
2872 
2873     status = set_auth_cookie(httpc, Connection->CookieAuth);
2874     if (status != RPC_S_OK)
2875     {
2876         HeapFree(GetProcessHeap(), 0, url);
2877         return status;
2878     }
2879     httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes,
2880                                          flags, (DWORD_PTR)httpc->async_data);
2881     if (!httpc->in_request)
2882     {
2883         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2884         HeapFree(GetProcessHeap(), 0, url);
2885         return RPC_S_SERVER_UNAVAILABLE;
2886     }
2887 
2888     if (credentials)
2889     {
2890         status = authorize_request(httpc, httpc->in_request);
2891         if (status != RPC_S_OK)
2892         {
2893             HeapFree(GetProcessHeap(), 0, url);
2894             return status;
2895         }
2896         status = rpcrt4_http_check_response(httpc->in_request);
2897         if (status != RPC_S_OK)
2898         {
2899             HeapFree(GetProcessHeap(), 0, url);
2900             return status;
2901         }
2902         drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event);
2903     }
2904 
2905     httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes,
2906                                           flags, (DWORD_PTR)httpc->async_data);
2907     HeapFree(GetProcessHeap(), 0, url);
2908     if (!httpc->out_request)
2909     {
2910         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2911         return RPC_S_SERVER_UNAVAILABLE;
2912     }
2913 
2914     if (credentials)
2915     {
2916         status = authorize_request(httpc, httpc->out_request);
2917         if (status != RPC_S_OK)
2918             return status;
2919     }
2920 
2921     status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event,
2922                                          &httpc->connection_uuid, &httpc->in_pipe_uuid,
2923                                          &Connection->assoc->http_uuid, credentials);
2924     if (status != RPC_S_OK)
2925         return status;
2926 
2927     status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event,
2928                                           &httpc->connection_uuid, &httpc->out_pipe_uuid,
2929                                           &httpc->flow_control_increment, credentials);
2930     if (status != RPC_S_OK)
2931         return status;
2932 
2933     httpc->flow_control_mark = httpc->flow_control_increment / 2;
2934     httpc->last_sent_time = GetTickCount();
2935     httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2936 
2937     timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2938     if (!timer_data)
2939         return ERROR_OUTOFMEMORY;
2940     timer_data->timer_param = httpc->in_request;
2941     timer_data->last_sent_time = &httpc->last_sent_time;
2942     timer_data->timer_cancelled = httpc->timer_cancelled;
2943     /* FIXME: should use CreateTimerQueueTimer when implemented */
2944     thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2945     if (!thread)
2946     {
2947         HeapFree(GetProcessHeap(), 0, timer_data);
2948         return GetLastError();
2949     }
2950     CloseHandle(thread);
2951 
2952     return RPC_S_OK;
2953 }
2954 
2955 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2956 {
2957     assert(0);
2958     return RPC_S_SERVER_UNAVAILABLE;
2959 }
2960 
2961 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2962                                 void *buffer, unsigned int count)
2963 {
2964   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2965   return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count);
2966 }
2967 
2968 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2969 {
2970   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2971   RPC_STATUS status;
2972   DWORD hdr_length;
2973   LONG dwRead;
2974   RpcPktCommonHdr common_hdr;
2975 
2976   *Header = NULL;
2977 
2978   TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2979 
2980 again:
2981   /* read packet common header */
2982   dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2983   if (dwRead != sizeof(common_hdr)) {
2984     WARN("Short read of header, %d bytes\n", dwRead);
2985     status = RPC_S_PROTOCOL_ERROR;
2986     goto fail;
2987   }
2988   if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2989       !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2990   {
2991     FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2992     status = RPC_S_PROTOCOL_ERROR;
2993     goto fail;
2994   }
2995 
2996   status = RPCRT4_ValidateCommonHeader(&common_hdr);
2997   if (status != RPC_S_OK) goto fail;
2998 
2999   hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
3000   if (hdr_length == 0) {
3001     WARN("header length == 0\n");
3002     status = RPC_S_PROTOCOL_ERROR;
3003     goto fail;
3004   }
3005 
3006   *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
3007   if (!*Header)
3008   {
3009     status = RPC_S_OUT_OF_RESOURCES;
3010     goto fail;
3011   }
3012   memcpy(*Header, &common_hdr, sizeof(common_hdr));
3013 
3014   /* read the rest of packet header */
3015   dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
3016   if (dwRead != hdr_length - sizeof(common_hdr)) {
3017     WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
3018     status = RPC_S_PROTOCOL_ERROR;
3019     goto fail;
3020   }
3021 
3022   if (common_hdr.frag_len - hdr_length)
3023   {
3024     *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
3025     if (!*Payload)
3026     {
3027       status = RPC_S_OUT_OF_RESOURCES;
3028       goto fail;
3029     }
3030 
3031     dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
3032     if (dwRead != common_hdr.frag_len - hdr_length)
3033     {
3034       WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
3035       status = RPC_S_PROTOCOL_ERROR;
3036       goto fail;
3037     }
3038   }
3039   else
3040     *Payload = NULL;
3041 
3042   if ((*Header)->common.ptype == PKT_HTTP)
3043   {
3044     if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
3045     {
3046       ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
3047       status = RPC_S_PROTOCOL_ERROR;
3048       goto fail;
3049     }
3050     if ((*Header)->http.flags == 0x0001)
3051     {
3052       TRACE("http idle packet, waiting for real packet\n");
3053       if ((*Header)->http.num_data_items != 0)
3054       {
3055         ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
3056         status = RPC_S_PROTOCOL_ERROR;
3057         goto fail;
3058       }
3059     }
3060     else if ((*Header)->http.flags == 0x0002)
3061     {
3062       ULONG bytes_transmitted;
3063       ULONG flow_control_increment;
3064       UUID pipe_uuid;
3065       status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
3066                                                  Connection->server,
3067                                                  &bytes_transmitted,
3068                                                  &flow_control_increment,
3069                                                  &pipe_uuid);
3070       if (status != RPC_S_OK)
3071         goto fail;
3072       TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
3073             bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
3074       /* FIXME: do something with parsed data */
3075     }
3076     else
3077     {
3078       FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
3079       status = RPC_S_PROTOCOL_ERROR;
3080       goto fail;
3081     }
3082     RPCRT4_FreeHeader(*Header);
3083     *Header = NULL;
3084     HeapFree(GetProcessHeap(), 0, *Payload);
3085     *Payload = NULL;
3086     goto again;
3087   }
3088 
3089   /* success */
3090   status = RPC_S_OK;
3091 
3092   httpc->bytes_received += common_hdr.frag_len;
3093 
3094   TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
3095 
3096   if (httpc->bytes_received > httpc->flow_control_mark)
3097   {
3098     RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
3099                                                        httpc->bytes_received,
3100                                                        httpc->flow_control_increment,
3101                                                        &httpc->out_pipe_uuid);
3102     if (hdr)
3103     {
3104       DWORD bytes_written;
3105       BOOL ret2;
3106       TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
3107       ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
3108       RPCRT4_FreeHeader(hdr);
3109       if (ret2)
3110         httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
3111     }
3112   }
3113 
3114 fail:
3115   if (status != RPC_S_OK) {
3116     RPCRT4_FreeHeader(*Header);
3117     *Header = NULL;
3118     HeapFree(GetProcessHeap(), 0, *Payload);
3119     *Payload = NULL;
3120   }
3121   return status;
3122 }
3123 
3124 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
3125                                  const void *buffer, unsigned int count)
3126 {
3127   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3128   DWORD bytes_written;
3129   BOOL ret;
3130 
3131   httpc->last_sent_time = ~0U; /* disable idle packet sending */
3132   ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
3133   httpc->last_sent_time = GetTickCount();
3134   TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
3135   return ret ? bytes_written : -1;
3136 }
3137 
3138 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
3139 {
3140   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3141 
3142   TRACE("\n");
3143 
3144   SetEvent(httpc->timer_cancelled);
3145   if (httpc->in_request)
3146     InternetCloseHandle(httpc->in_request);
3147   httpc->in_request = NULL;
3148   if (httpc->out_request)
3149     InternetCloseHandle(httpc->out_request);
3150   httpc->out_request = NULL;
3151   if (httpc->app_info)
3152     InternetCloseHandle(httpc->app_info);
3153   httpc->app_info = NULL;
3154   if (httpc->session)
3155     InternetCloseHandle(httpc->session);
3156   httpc->session = NULL;
3157   RpcHttpAsyncData_Release(httpc->async_data);
3158   if (httpc->cancel_event)
3159     CloseHandle(httpc->cancel_event);
3160   HeapFree(GetProcessHeap(), 0, httpc->servername);
3161   httpc->servername = NULL;
3162 
3163   return 0;
3164 }
3165 
3166 static void rpcrt4_ncacn_http_close_read(RpcConnection *conn)
3167 {
3168     rpcrt4_ncacn_http_close(conn); /* FIXME */
3169 }
3170 
3171 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
3172 {
3173   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3174 
3175   SetEvent(httpc->cancel_event);
3176 }
3177 
3178 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint)
3179 {
3180     FIXME("\n");
3181     return RPC_S_ACCESS_DENIED;
3182 }
3183 
3184 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
3185 {
3186   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3187   BOOL ret;
3188   RPC_STATUS status;
3189 
3190   prepare_async_request(httpc->async_data);
3191   ret = InternetQueryDataAvailable(httpc->out_request,
3192     &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
3193   status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
3194   return status == RPC_S_OK ? 0 : -1;
3195 }
3196 
3197 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
3198                                                  const char *networkaddr,
3199                                                  const char *endpoint)
3200 {
3201     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
3202                                           EPM_PROTOCOL_HTTP, endpoint);
3203 }
3204 
3205 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
3206                                                        size_t tower_size,
3207                                                        char **networkaddr,
3208                                                        char **endpoint)
3209 {
3210     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
3211                                             networkaddr, EPM_PROTOCOL_HTTP,
3212                                             endpoint);
3213 }
3214 
3215 static const struct connection_ops conn_protseq_list[] = {
3216   { "ncacn_np",
3217     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
3218     rpcrt4_conn_np_alloc,
3219     rpcrt4_ncacn_np_open,
3220     rpcrt4_ncacn_np_handoff,
3221     rpcrt4_conn_np_read,
3222     rpcrt4_conn_np_write,
3223     rpcrt4_conn_np_close,
3224     rpcrt4_conn_np_close_read,
3225     rpcrt4_conn_np_cancel_call,
3226     rpcrt4_ncacn_np_is_server_listening,
3227     rpcrt4_conn_np_wait_for_incoming_data,
3228     rpcrt4_ncacn_np_get_top_of_tower,
3229     rpcrt4_ncacn_np_parse_top_of_tower,
3230     NULL,
3231     RPCRT4_default_is_authorized,
3232     RPCRT4_default_authorize,
3233     RPCRT4_default_secure_packet,
3234     rpcrt4_conn_np_impersonate_client,
3235     rpcrt4_conn_np_revert_to_self,
3236     RPCRT4_default_inquire_auth_client,
3237   },
3238   { "ncalrpc",
3239     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
3240     rpcrt4_conn_np_alloc,
3241     rpcrt4_ncalrpc_open,
3242     rpcrt4_ncalrpc_handoff,
3243     rpcrt4_conn_np_read,
3244     rpcrt4_conn_np_write,
3245     rpcrt4_conn_np_close,
3246     rpcrt4_conn_np_close_read,
3247     rpcrt4_conn_np_cancel_call,
3248     rpcrt4_ncalrpc_np_is_server_listening,
3249     rpcrt4_conn_np_wait_for_incoming_data,
3250     rpcrt4_ncalrpc_get_top_of_tower,
3251     rpcrt4_ncalrpc_parse_top_of_tower,
3252     NULL,
3253     rpcrt4_ncalrpc_is_authorized,
3254     rpcrt4_ncalrpc_authorize,
3255     rpcrt4_ncalrpc_secure_packet,
3256     rpcrt4_conn_np_impersonate_client,
3257     rpcrt4_conn_np_revert_to_self,
3258     rpcrt4_ncalrpc_inquire_auth_client,
3259   },
3260   { "ncacn_ip_tcp",
3261     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
3262     rpcrt4_conn_tcp_alloc,
3263     rpcrt4_ncacn_ip_tcp_open,
3264     rpcrt4_conn_tcp_handoff,
3265     rpcrt4_conn_tcp_read,
3266     rpcrt4_conn_tcp_write,
3267     rpcrt4_conn_tcp_close,
3268     rpcrt4_conn_tcp_close_read,
3269     rpcrt4_conn_tcp_cancel_call,
3270     rpcrt4_conn_tcp_is_server_listening,
3271     rpcrt4_conn_tcp_wait_for_incoming_data,
3272     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
3273     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
3274     NULL,
3275     RPCRT4_default_is_authorized,
3276     RPCRT4_default_authorize,
3277     RPCRT4_default_secure_packet,
3278     RPCRT4_default_impersonate_client,
3279     RPCRT4_default_revert_to_self,
3280     RPCRT4_default_inquire_auth_client,
3281   },
3282   { "ncacn_http",
3283     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
3284     rpcrt4_ncacn_http_alloc,
3285     rpcrt4_ncacn_http_open,
3286     rpcrt4_ncacn_http_handoff,
3287     rpcrt4_ncacn_http_read,
3288     rpcrt4_ncacn_http_write,
3289     rpcrt4_ncacn_http_close,
3290     rpcrt4_ncacn_http_close_read,
3291     rpcrt4_ncacn_http_cancel_call,
3292     rpcrt4_ncacn_http_is_server_listening,
3293     rpcrt4_ncacn_http_wait_for_incoming_data,
3294     rpcrt4_ncacn_http_get_top_of_tower,
3295     rpcrt4_ncacn_http_parse_top_of_tower,
3296     rpcrt4_ncacn_http_receive_fragment,
3297     RPCRT4_default_is_authorized,
3298     RPCRT4_default_authorize,
3299     RPCRT4_default_secure_packet,
3300     RPCRT4_default_impersonate_client,
3301     RPCRT4_default_revert_to_self,
3302     RPCRT4_default_inquire_auth_client,
3303   },
3304 };
3305 
3306 
3307 static const struct protseq_ops protseq_list[] =
3308 {
3309     {
3310         "ncacn_np",
3311         rpcrt4_protseq_np_alloc,
3312         rpcrt4_protseq_np_signal_state_changed,
3313         rpcrt4_protseq_np_get_wait_array,
3314         rpcrt4_protseq_np_free_wait_array,
3315         rpcrt4_protseq_np_wait_for_new_connection,
3316         rpcrt4_protseq_ncacn_np_open_endpoint,
3317     },
3318     {
3319         "ncalrpc",
3320         rpcrt4_protseq_np_alloc,
3321         rpcrt4_protseq_np_signal_state_changed,
3322         rpcrt4_protseq_np_get_wait_array,
3323         rpcrt4_protseq_np_free_wait_array,
3324         rpcrt4_protseq_np_wait_for_new_connection,
3325         rpcrt4_protseq_ncalrpc_open_endpoint,
3326     },
3327     {
3328         "ncacn_ip_tcp",
3329         rpcrt4_protseq_sock_alloc,
3330         rpcrt4_protseq_sock_signal_state_changed,
3331         rpcrt4_protseq_sock_get_wait_array,
3332         rpcrt4_protseq_sock_free_wait_array,
3333         rpcrt4_protseq_sock_wait_for_new_connection,
3334         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
3335     },
3336 };
3337 
3338 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
3339 {
3340   unsigned int i;
3341   for(i = 0; i < ARRAY_SIZE(protseq_list); i++)
3342     if (!strcmp(protseq_list[i].name, protseq))
3343       return &protseq_list[i];
3344   return NULL;
3345 }
3346 
3347 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
3348 {
3349     unsigned int i;
3350     for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3351         if (!strcmp(conn_protseq_list[i].name, protseq))
3352             return &conn_protseq_list[i];
3353     return NULL;
3354 }
3355 
3356 /**** interface to rest of code ****/
3357 
3358 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
3359 {
3360   TRACE("(Connection == ^%p)\n", Connection);
3361 
3362   assert(!Connection->server);
3363   return Connection->ops->open_connection_client(Connection);
3364 }
3365 
3366 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
3367 {
3368   TRACE("(Connection == ^%p)\n", Connection);
3369   if (SecIsValidHandle(&Connection->ctx))
3370   {
3371     DeleteSecurityContext(&Connection->ctx);
3372     SecInvalidateHandle(&Connection->ctx);
3373   }
3374   rpcrt4_conn_close(Connection);
3375   return RPC_S_OK;
3376 }
3377 
3378 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
3379     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
3380     LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth)
3381 {
3382   static LONG next_id;
3383   const struct connection_ops *ops;
3384   RpcConnection* NewConnection;
3385 
3386   ops = rpcrt4_get_conn_protseq_ops(Protseq);
3387   if (!ops)
3388   {
3389     FIXME("not supported for protseq %s\n", Protseq);
3390     return RPC_S_PROTSEQ_NOT_SUPPORTED;
3391   }
3392 
3393   NewConnection = ops->alloc();
3394   NewConnection->ref = 1;
3395   NewConnection->server = server;
3396   NewConnection->ops = ops;
3397   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
3398   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
3399   NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
3400   NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth);
3401   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
3402   NewConnection->NextCallId = 1;
3403 
3404   SecInvalidateHandle(&NewConnection->ctx);
3405   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
3406   NewConnection->AuthInfo = AuthInfo;
3407   NewConnection->auth_context_id = InterlockedIncrement( &next_id );
3408   if (QOS) RpcQualityOfService_AddRef(QOS);
3409   NewConnection->QOS = QOS;
3410 
3411   list_init(&NewConnection->conn_pool_entry);
3412   list_init(&NewConnection->protseq_entry);
3413 
3414   TRACE("connection: %p\n", NewConnection);
3415   *Connection = NewConnection;
3416 
3417   return RPC_S_OK;
3418 }
3419 
3420 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection)
3421 {
3422     RpcConnection *connection;
3423     RPC_STATUS err;
3424 
3425     err = RPCRT4_CreateConnection(&connection, old_connection->server, rpcrt4_conn_get_name(old_connection),
3426                                   old_connection->NetworkAddr, old_connection->Endpoint, NULL,
3427                                   old_connection->AuthInfo, old_connection->QOS, old_connection->CookieAuth);
3428     if (err != RPC_S_OK)
3429         return NULL;
3430 
3431     rpcrt4_conn_handoff(old_connection, connection);
3432     if (old_connection->protseq)
3433     {
3434         EnterCriticalSection(&old_connection->protseq->cs);
3435         connection->protseq = old_connection->protseq;
3436         list_add_tail(&old_connection->protseq->connections, &connection->protseq_entry);
3437         LeaveCriticalSection(&old_connection->protseq->cs);
3438     }
3439     return connection;
3440 }
3441 
3442 void rpcrt4_conn_release_and_wait(RpcConnection *connection)
3443 {
3444     HANDLE event = NULL;
3445 
3446     if (connection->ref > 1)
3447         event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL);
3448 
3449     RPCRT4_ReleaseConnection(connection);
3450 
3451     if(event)
3452     {
3453         WaitForSingleObject(event, INFINITE);
3454         CloseHandle(event);
3455     }
3456 }
3457 
3458 RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection)
3459 {
3460     LONG ref = InterlockedIncrement(&connection->ref);
3461     TRACE("%p ref=%u\n", connection, ref);
3462     return connection;
3463 }
3464 
3465 void RPCRT4_ReleaseConnection(RpcConnection *connection)
3466 {
3467     LONG ref;
3468 
3469     /* protseq stores a list of active connections, but does not own references to them.
3470      * It may need to grab a connection from the list, which could lead to a race if
3471      * connection is being released, but not yet removed from the list. We handle that
3472      * by synchronizing on CS here. */
3473     if (connection->protseq)
3474     {
3475         EnterCriticalSection(&connection->protseq->cs);
3476         ref = InterlockedDecrement(&connection->ref);
3477         if (!ref)
3478             list_remove(&connection->protseq_entry);
3479         LeaveCriticalSection(&connection->protseq->cs);
3480     }
3481     else
3482     {
3483         ref = InterlockedDecrement(&connection->ref);
3484     }
3485 
3486     TRACE("%p ref=%u\n", connection, ref);
3487 
3488     if (!ref)
3489     {
3490         RPCRT4_CloseConnection(connection);
3491         RPCRT4_strfree(connection->Endpoint);
3492         RPCRT4_strfree(connection->NetworkAddr);
3493         HeapFree(GetProcessHeap(), 0, connection->NetworkOptions);
3494         HeapFree(GetProcessHeap(), 0, connection->CookieAuth);
3495         if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo);
3496         if (connection->QOS) RpcQualityOfService_Release(connection->QOS);
3497 
3498         /* server-only */
3499         if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding);
3500         else if (connection->assoc) RpcAssoc_ConnectionReleased(connection->assoc);
3501 
3502         if (connection->wait_release) SetEvent(connection->wait_release);
3503 
3504         HeapFree(GetProcessHeap(), 0, connection);
3505     }
3506 }
3507 
3508 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)
3509 {
3510   const struct connection_ops *ops;
3511 
3512   ops = rpcrt4_get_conn_protseq_ops(protseq);
3513   if (!ops)
3514   {
3515     FIXME("not supported for protseq %s\n", protseq);
3516     return RPC_S_INVALID_BINDING;
3517   }
3518 
3519   return ops->is_server_listening(endpoint);
3520 }
3521 
3522 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3523                                       size_t *tower_size,
3524                                       const char *protseq,
3525                                       const char *networkaddr,
3526                                       const char *endpoint)
3527 {
3528     twr_empty_floor_t *protocol_floor;
3529     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3530 
3531     *tower_size = 0;
3532 
3533     if (!protseq_ops)
3534         return RPC_S_INVALID_RPC_PROTSEQ;
3535 
3536     if (!tower_data)
3537     {
3538         *tower_size = sizeof(*protocol_floor);
3539         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3540         return RPC_S_OK;
3541     }
3542 
3543     protocol_floor = (twr_empty_floor_t *)tower_data;
3544     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3545     protocol_floor->protid = protseq_ops->epm_protocols[0];
3546     protocol_floor->count_rhs = 0;
3547 
3548     tower_data += sizeof(*protocol_floor);
3549 
3550     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3551     if (!*tower_size)
3552         return EPT_S_NOT_REGISTERED;
3553 
3554     *tower_size += sizeof(*protocol_floor);
3555 
3556     return RPC_S_OK;
3557 }
3558 
3559 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3560                                         size_t tower_size,
3561                                         char **protseq,
3562                                         char **networkaddr,
3563                                         char **endpoint)
3564 {
3565     const twr_empty_floor_t *protocol_floor;
3566     const twr_empty_floor_t *floor4;
3567     const struct connection_ops *protseq_ops = NULL;
3568     RPC_STATUS status;
3569     unsigned int i;
3570 
3571     if (tower_size < sizeof(*protocol_floor))
3572         return EPT_S_NOT_REGISTERED;
3573 
3574     protocol_floor = (const twr_empty_floor_t *)tower_data;
3575     tower_data += sizeof(*protocol_floor);
3576     tower_size -= sizeof(*protocol_floor);
3577     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3578         (protocol_floor->count_rhs > tower_size))
3579         return EPT_S_NOT_REGISTERED;
3580     tower_data += protocol_floor->count_rhs;
3581     tower_size -= protocol_floor->count_rhs;
3582 
3583     floor4 = (const twr_empty_floor_t *)tower_data;
3584     if ((tower_size < sizeof(*floor4)) ||
3585         (floor4->count_lhs != sizeof(floor4->protid)))
3586         return EPT_S_NOT_REGISTERED;
3587 
3588     for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3589         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3590             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3591         {
3592             protseq_ops = &conn_protseq_list[i];
3593             break;
3594         }
3595 
3596     if (!protseq_ops)
3597         return EPT_S_NOT_REGISTERED;
3598 
3599     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3600 
3601     if ((status == RPC_S_OK) && protseq)
3602     {
3603         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3604         strcpy(*protseq, protseq_ops->name);
3605     }
3606 
3607     return status;
3608 }
3609 
3610 /***********************************************************************
3611  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
3612  *
3613  * Checks if the given protocol sequence is known by the RPC system.
3614  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3615  *
3616  */
3617 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3618 {
3619   char ps[0x10];
3620 
3621   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3622                       ps, sizeof ps, NULL, NULL);
3623   if (rpcrt4_get_conn_protseq_ops(ps))
3624     return RPC_S_OK;
3625 
3626   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3627 
3628   return RPC_S_INVALID_RPC_PROTSEQ;
3629 }
3630 
3631 /***********************************************************************
3632  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
3633  */
3634 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3635 {
3636   UNICODE_STRING protseqW;
3637 
3638   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3639   {
3640     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3641     RtlFreeUnicodeString(&protseqW);
3642     return ret;
3643   }
3644   return RPC_S_OUT_OF_MEMORY;
3645 }
3646 
3647 /***********************************************************************
3648  *             RpcProtseqVectorFreeA (RPCRT4.@)
3649  */
3650 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
3651 {
3652   TRACE("(%p)\n", protseqs);
3653 
3654   if (*protseqs)
3655   {
3656     unsigned int i;
3657     for (i = 0; i < (*protseqs)->Count; i++)
3658       HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3659     HeapFree(GetProcessHeap(), 0, *protseqs);
3660     *protseqs = NULL;
3661   }
3662   return RPC_S_OK;
3663 }
3664 
3665 /***********************************************************************
3666  *             RpcProtseqVectorFreeW (RPCRT4.@)
3667  */
3668 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
3669 {
3670   TRACE("(%p)\n", protseqs);
3671 
3672   if (*protseqs)
3673   {
3674     unsigned int i;
3675     for (i = 0; i < (*protseqs)->Count; i++)
3676       HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3677     HeapFree(GetProcessHeap(), 0, *protseqs);
3678     *protseqs = NULL;
3679   }
3680   return RPC_S_OK;
3681 }
3682 
3683 /***********************************************************************
3684  *             RpcNetworkInqProtseqsW (RPCRT4.@)
3685  */
3686 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
3687 {
3688   RPC_PROTSEQ_VECTORW *pvector;
3689   unsigned int i;
3690   RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3691 
3692   TRACE("(%p)\n", protseqs);
3693 
3694   *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAY_SIZE(protseq_list)));
3695   if (!*protseqs)
3696     goto end;
3697   pvector = *protseqs;
3698   pvector->Count = 0;
3699   for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3700   {
3701     pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
3702     if (pvector->Protseq[i] == NULL)
3703       goto end;
3704     MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
3705       (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
3706     pvector->Count++;
3707   }
3708   status = RPC_S_OK;
3709 
3710 end:
3711   if (status != RPC_S_OK)
3712     RpcProtseqVectorFreeW(protseqs);
3713   return status;
3714 }
3715 
3716 /***********************************************************************
3717  *             RpcNetworkInqProtseqsA (RPCRT4.@)
3718  */
3719 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
3720 {
3721   RPC_PROTSEQ_VECTORA *pvector;
3722   unsigned int i;
3723   RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3724 
3725   TRACE("(%p)\n", protseqs);
3726 
3727   *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAY_SIZE(protseq_list)));
3728   if (!*protseqs)
3729     goto end;
3730   pvector = *protseqs;
3731   pvector->Count = 0;
3732   for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3733   {
3734     pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
3735     if (pvector->Protseq[i] == NULL)
3736       goto end;
3737     strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
3738     pvector->Count++;
3739   }
3740   status = RPC_S_OK;
3741 
3742 end:
3743   if (status != RPC_S_OK)
3744     RpcProtseqVectorFreeA(protseqs);
3745   return status;
3746 }
3747