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