kernel32/tests: A spelling fix in a comment.
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blobfb3edb49b0092c8d7a39204ef63a54379942d8da
1 /*
2 * RPC transport layer
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
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.
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.
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
26 #include "config.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
39 #if defined(__MINGW32__) || defined (_MSC_VER)
40 # include <ws2tcpip.h>
41 # ifndef EADDRINUSE
42 # define EADDRINUSE WSAEADDRINUSE
43 # endif
44 # ifndef EAGAIN
45 # define EAGAIN WSAEWOULDBLOCK
46 # endif
47 # undef errno
48 # define errno WSAGetLastError()
49 #else
50 # include <errno.h>
51 # ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 # endif
54 # include <fcntl.h>
55 # ifdef HAVE_SYS_SOCKET_H
56 # include <sys/socket.h>
57 # endif
58 # ifdef HAVE_NETINET_IN_H
59 # include <netinet/in.h>
60 # endif
61 # ifdef HAVE_NETINET_TCP_H
62 # include <netinet/tcp.h>
63 # endif
64 # ifdef HAVE_ARPA_INET_H
65 # include <arpa/inet.h>
66 # endif
67 # ifdef HAVE_NETDB_H
68 # include <netdb.h>
69 # endif
70 # ifdef HAVE_SYS_POLL_H
71 # include <sys/poll.h>
72 # endif
73 # ifdef HAVE_SYS_FILIO_H
74 # include <sys/filio.h>
75 # endif
76 # ifdef HAVE_SYS_IOCTL_H
77 # include <sys/ioctl.h>
78 # endif
79 # define closesocket close
80 # define ioctlsocket ioctl
81 #endif /* defined(__MINGW32__) || defined (_MSC_VER) */
83 #include "windef.h"
84 #include "winbase.h"
85 #include "winnls.h"
86 #include "winerror.h"
87 #include "wininet.h"
88 #include "winternl.h"
89 #include "wine/unicode.h"
91 #include "rpc.h"
92 #include "rpcndr.h"
94 #include "wine/debug.h"
96 #include "rpc_binding.h"
97 #include "rpc_assoc.h"
98 #include "rpc_message.h"
99 #include "rpc_server.h"
100 #include "epm_towers.h"
102 #ifndef SOL_TCP
103 # define SOL_TCP IPPROTO_TCP
104 #endif
106 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
108 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
110 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
112 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
114 /**** ncacn_np support ****/
116 typedef struct _RpcConnection_np
118 RpcConnection common;
119 HANDLE pipe;
120 HANDLE listen_thread;
121 BOOL listening;
122 } RpcConnection_np;
124 static RpcConnection *rpcrt4_conn_np_alloc(void)
126 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
127 return &npc->common;
130 static DWORD CALLBACK listen_thread(void *arg)
132 RpcConnection_np *npc = arg;
133 for (;;)
135 if (ConnectNamedPipe(npc->pipe, NULL))
136 return RPC_S_OK;
138 switch(GetLastError())
140 case ERROR_PIPE_CONNECTED:
141 return RPC_S_OK;
142 case ERROR_HANDLES_CLOSED:
143 /* connection closed during listen */
144 return RPC_S_NO_CONTEXT_AVAILABLE;
145 case ERROR_NO_DATA_DETECTED:
146 /* client has disconnected, retry */
147 DisconnectNamedPipe( npc->pipe );
148 break;
149 default:
150 npc->listening = FALSE;
151 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
152 return RPC_S_OUT_OF_RESOURCES;
157 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
159 if (npc->listening)
160 return RPC_S_OK;
162 npc->listening = TRUE;
163 npc->listen_thread = CreateThread(NULL, 0, listen_thread, npc, 0, NULL);
164 if (!npc->listen_thread)
166 npc->listening = FALSE;
167 ERR("Couldn't create listen thread (error was %d)\n", GetLastError());
168 return RPC_S_OUT_OF_RESOURCES;
170 return RPC_S_OK;
173 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
175 RpcConnection_np *npc = (RpcConnection_np *) Connection;
176 TRACE("listening on %s\n", pname);
178 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
179 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
180 PIPE_UNLIMITED_INSTANCES,
181 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
182 if (npc->pipe == INVALID_HANDLE_VALUE) {
183 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
184 if (GetLastError() == ERROR_FILE_EXISTS)
185 return RPC_S_DUPLICATE_ENDPOINT;
186 else
187 return RPC_S_CANT_CREATE_ENDPOINT;
190 /* Note: we don't call ConnectNamedPipe here because it must be done in the
191 * server thread as the thread must be alertable */
192 return RPC_S_OK;
195 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
197 RpcConnection_np *npc = (RpcConnection_np *) Connection;
198 HANDLE pipe;
199 DWORD err, dwMode;
201 TRACE("connecting to %s\n", pname);
203 while (TRUE) {
204 DWORD dwFlags = 0;
205 if (Connection->QOS)
207 dwFlags = SECURITY_SQOS_PRESENT;
208 switch (Connection->QOS->qos->ImpersonationType)
210 case RPC_C_IMP_LEVEL_DEFAULT:
211 /* FIXME: what to do here? */
212 break;
213 case RPC_C_IMP_LEVEL_ANONYMOUS:
214 dwFlags |= SECURITY_ANONYMOUS;
215 break;
216 case RPC_C_IMP_LEVEL_IDENTIFY:
217 dwFlags |= SECURITY_IDENTIFICATION;
218 break;
219 case RPC_C_IMP_LEVEL_IMPERSONATE:
220 dwFlags |= SECURITY_IMPERSONATION;
221 break;
222 case RPC_C_IMP_LEVEL_DELEGATE:
223 dwFlags |= SECURITY_DELEGATION;
224 break;
226 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
227 dwFlags |= SECURITY_CONTEXT_TRACKING;
229 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
230 OPEN_EXISTING, dwFlags, 0);
231 if (pipe != INVALID_HANDLE_VALUE) break;
232 err = GetLastError();
233 if (err == ERROR_PIPE_BUSY) {
234 TRACE("connection failed, error=%x\n", err);
235 return RPC_S_SERVER_TOO_BUSY;
237 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
238 err = GetLastError();
239 WARN("connection failed, error=%x\n", err);
240 return RPC_S_SERVER_UNAVAILABLE;
244 /* success */
245 /* pipe is connected; change to message-read mode. */
246 dwMode = PIPE_READMODE_MESSAGE;
247 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
248 npc->pipe = pipe;
250 return RPC_S_OK;
253 static char *ncalrpc_pipe_name(const char *endpoint)
255 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
256 char *pipe_name;
258 /* protseq=ncalrpc: supposed to use NT LPC ports,
259 * but we'll implement it with named pipes for now */
260 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
261 strcat(strcpy(pipe_name, prefix), endpoint);
262 return pipe_name;
265 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
267 RpcConnection_np *npc = (RpcConnection_np *) Connection;
268 RPC_STATUS r;
269 LPSTR pname;
271 /* already connected? */
272 if (npc->pipe)
273 return RPC_S_OK;
275 pname = ncalrpc_pipe_name(Connection->Endpoint);
276 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
277 I_RpcFree(pname);
279 return r;
282 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
284 RPC_STATUS r;
285 LPSTR pname;
286 RpcConnection *Connection;
287 char generated_endpoint[22];
289 if (!endpoint)
291 static LONG lrpc_nameless_id;
292 DWORD process_id = GetCurrentProcessId();
293 ULONG id = InterlockedIncrement(&lrpc_nameless_id);
294 snprintf(generated_endpoint, sizeof(generated_endpoint),
295 "LRPC%08x.%08x", process_id, id);
296 endpoint = generated_endpoint;
299 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
300 endpoint, NULL, NULL, NULL, NULL);
301 if (r != RPC_S_OK)
302 return r;
304 pname = ncalrpc_pipe_name(Connection->Endpoint);
305 r = rpcrt4_conn_create_pipe(Connection, pname);
306 I_RpcFree(pname);
308 EnterCriticalSection(&protseq->cs);
309 Connection->Next = protseq->conn;
310 protseq->conn = Connection;
311 LeaveCriticalSection(&protseq->cs);
313 return r;
316 static char *ncacn_pipe_name(const char *endpoint)
318 static const char prefix[] = "\\\\.";
319 char *pipe_name;
321 /* protseq=ncacn_np: named pipes */
322 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
323 strcat(strcpy(pipe_name, prefix), endpoint);
324 return pipe_name;
327 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
329 RpcConnection_np *npc = (RpcConnection_np *) Connection;
330 RPC_STATUS r;
331 LPSTR pname;
333 /* already connected? */
334 if (npc->pipe)
335 return RPC_S_OK;
337 pname = ncacn_pipe_name(Connection->Endpoint);
338 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
339 I_RpcFree(pname);
341 return r;
344 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
346 RPC_STATUS r;
347 LPSTR pname;
348 RpcConnection *Connection;
349 char generated_endpoint[26];
351 if (!endpoint)
353 static LONG np_nameless_id;
354 DWORD process_id = GetCurrentProcessId();
355 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
356 snprintf(generated_endpoint, sizeof(generated_endpoint),
357 "\\\\pipe\\\\%08x.%03x", process_id, id);
358 endpoint = generated_endpoint;
361 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
362 endpoint, NULL, NULL, NULL, NULL);
363 if (r != RPC_S_OK)
364 return r;
366 pname = ncacn_pipe_name(Connection->Endpoint);
367 r = rpcrt4_conn_create_pipe(Connection, pname);
368 I_RpcFree(pname);
370 EnterCriticalSection(&protseq->cs);
371 Connection->Next = protseq->conn;
372 protseq->conn = Connection;
373 LeaveCriticalSection(&protseq->cs);
375 return r;
378 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
380 /* because of the way named pipes work, we'll transfer the connected pipe
381 * to the child, then reopen the server binding to continue listening */
383 new_npc->pipe = old_npc->pipe;
384 new_npc->listen_thread = old_npc->listen_thread;
385 old_npc->pipe = 0;
386 old_npc->listen_thread = 0;
387 old_npc->listening = FALSE;
390 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
392 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
393 RPC_STATUS status;
394 LPSTR pname;
396 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
398 pname = ncacn_pipe_name(old_conn->Endpoint);
399 status = rpcrt4_conn_create_pipe(old_conn, pname);
400 I_RpcFree(pname);
402 /* Store the local computer name as the NetworkAddr for ncacn_np as long as
403 * we don't support named pipes over the network. */
404 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
405 if (!GetComputerNameA(new_conn->NetworkAddr, &len))
407 ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
408 return RPC_S_OUT_OF_RESOURCES;
411 return status;
414 static RPC_STATUS is_pipe_listening(const char *pipe_name)
416 return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING;
419 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint)
421 char *pipe_name;
422 RPC_STATUS status;
424 pipe_name = ncacn_pipe_name(endpoint);
425 status = is_pipe_listening(pipe_name);
426 I_RpcFree(pipe_name);
427 return status;
430 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint)
432 char *pipe_name;
433 RPC_STATUS status;
435 pipe_name = ncalrpc_pipe_name(endpoint);
436 status = is_pipe_listening(pipe_name);
437 I_RpcFree(pipe_name);
438 return status;
441 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
443 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
444 RPC_STATUS status;
445 LPSTR pname;
447 TRACE("%s\n", old_conn->Endpoint);
449 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
451 pname = ncalrpc_pipe_name(old_conn->Endpoint);
452 status = rpcrt4_conn_create_pipe(old_conn, pname);
453 I_RpcFree(pname);
455 /* Store the local computer name as the NetworkAddr for ncalrpc. */
456 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
457 if (!GetComputerNameA(new_conn->NetworkAddr, &len))
459 ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
460 return RPC_S_OUT_OF_RESOURCES;
463 return status;
466 static int rpcrt4_conn_np_read(RpcConnection *Connection,
467 void *buffer, unsigned int count)
469 RpcConnection_np *npc = (RpcConnection_np *) Connection;
470 IO_STATUS_BLOCK io_status;
471 char *buf = buffer;
472 unsigned int bytes_left = count;
473 NTSTATUS status;
475 while (bytes_left)
477 status = NtReadFile(npc->pipe, NULL, NULL, NULL, &io_status, buf, bytes_left, NULL, NULL);
478 if (status && status != STATUS_BUFFER_OVERFLOW)
479 return -1;
480 bytes_left -= io_status.Information;
481 buf += io_status.Information;
483 return count;
486 static int rpcrt4_conn_np_write(RpcConnection *Connection,
487 const void *buffer, unsigned int count)
489 RpcConnection_np *npc = (RpcConnection_np *) Connection;
490 const char *buf = buffer;
491 BOOL ret = TRUE;
492 unsigned int bytes_left = count;
494 while (bytes_left)
496 DWORD bytes_written;
497 ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, NULL);
498 if (!ret || !bytes_written)
499 break;
500 bytes_left -= bytes_written;
501 buf += bytes_written;
503 return ret ? count : -1;
506 static int rpcrt4_conn_np_close(RpcConnection *Connection)
508 RpcConnection_np *npc = (RpcConnection_np *) Connection;
509 if (npc->pipe) {
510 FlushFileBuffers(npc->pipe);
511 CloseHandle(npc->pipe);
512 npc->pipe = 0;
514 if (npc->listen_thread) {
515 CloseHandle(npc->listen_thread);
516 npc->listen_thread = 0;
518 return 0;
521 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
523 /* FIXME: implement when named pipe writes use overlapped I/O */
526 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
528 /* FIXME: implement when named pipe writes use overlapped I/O */
529 return -1;
532 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
533 const char *networkaddr,
534 const char *endpoint)
536 twr_empty_floor_t *smb_floor;
537 twr_empty_floor_t *nb_floor;
538 size_t size;
539 size_t networkaddr_size;
540 size_t endpoint_size;
542 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
544 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
545 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
546 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
548 if (!tower_data)
549 return size;
551 smb_floor = (twr_empty_floor_t *)tower_data;
553 tower_data += sizeof(*smb_floor);
555 smb_floor->count_lhs = sizeof(smb_floor->protid);
556 smb_floor->protid = EPM_PROTOCOL_SMB;
557 smb_floor->count_rhs = endpoint_size;
559 if (endpoint)
560 memcpy(tower_data, endpoint, endpoint_size);
561 else
562 tower_data[0] = 0;
563 tower_data += endpoint_size;
565 nb_floor = (twr_empty_floor_t *)tower_data;
567 tower_data += sizeof(*nb_floor);
569 nb_floor->count_lhs = sizeof(nb_floor->protid);
570 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
571 nb_floor->count_rhs = networkaddr_size;
573 if (networkaddr)
574 memcpy(tower_data, networkaddr, networkaddr_size);
575 else
576 tower_data[0] = 0;
578 return size;
581 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
582 size_t tower_size,
583 char **networkaddr,
584 char **endpoint)
586 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
587 const twr_empty_floor_t *nb_floor;
589 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
591 if (tower_size < sizeof(*smb_floor))
592 return EPT_S_NOT_REGISTERED;
594 tower_data += sizeof(*smb_floor);
595 tower_size -= sizeof(*smb_floor);
597 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
598 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
599 (smb_floor->count_rhs > tower_size) ||
600 (tower_data[smb_floor->count_rhs - 1] != '\0'))
601 return EPT_S_NOT_REGISTERED;
603 if (endpoint)
605 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
606 if (!*endpoint)
607 return RPC_S_OUT_OF_RESOURCES;
608 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
610 tower_data += smb_floor->count_rhs;
611 tower_size -= smb_floor->count_rhs;
613 if (tower_size < sizeof(*nb_floor))
614 return EPT_S_NOT_REGISTERED;
616 nb_floor = (const twr_empty_floor_t *)tower_data;
618 tower_data += sizeof(*nb_floor);
619 tower_size -= sizeof(*nb_floor);
621 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
622 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
623 (nb_floor->count_rhs > tower_size) ||
624 (tower_data[nb_floor->count_rhs - 1] != '\0'))
625 return EPT_S_NOT_REGISTERED;
627 if (networkaddr)
629 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
630 if (!*networkaddr)
632 if (endpoint)
634 I_RpcFree(*endpoint);
635 *endpoint = NULL;
637 return RPC_S_OUT_OF_RESOURCES;
639 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
642 return RPC_S_OK;
645 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
647 RpcConnection_np *npc = (RpcConnection_np *)conn;
648 BOOL ret;
650 TRACE("(%p)\n", conn);
652 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
653 return RPCRT4_default_impersonate_client(conn);
655 ret = ImpersonateNamedPipeClient(npc->pipe);
656 if (!ret)
658 DWORD error = GetLastError();
659 WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
660 switch (error)
662 case ERROR_CANNOT_IMPERSONATE:
663 return RPC_S_NO_CONTEXT_AVAILABLE;
666 return RPC_S_OK;
669 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
671 BOOL ret;
673 TRACE("(%p)\n", conn);
675 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
676 return RPCRT4_default_revert_to_self(conn);
678 ret = RevertToSelf();
679 if (!ret)
681 WARN("RevertToSelf failed with error %u\n", GetLastError());
682 return RPC_S_NO_CONTEXT_AVAILABLE;
684 return RPC_S_OK;
687 typedef struct _RpcServerProtseq_np
689 RpcServerProtseq common;
690 HANDLE mgr_event;
691 } RpcServerProtseq_np;
693 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
695 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
696 if (ps)
697 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
698 return &ps->common;
701 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
703 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
704 SetEvent(npps->mgr_event);
707 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
709 HANDLE *objs = prev_array;
710 RpcConnection_np *conn;
711 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
713 EnterCriticalSection(&protseq->cs);
715 /* open and count connections */
716 *count = 1;
717 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
718 while (conn) {
719 rpcrt4_conn_listen_pipe(conn);
720 if (conn->listen_thread)
721 (*count)++;
722 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
725 /* make array of connections */
726 if (objs)
727 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
728 else
729 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
730 if (!objs)
732 ERR("couldn't allocate objs\n");
733 LeaveCriticalSection(&protseq->cs);
734 return NULL;
737 objs[0] = npps->mgr_event;
738 *count = 1;
739 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
740 while (conn) {
741 if ((objs[*count] = conn->listen_thread))
742 (*count)++;
743 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
745 LeaveCriticalSection(&protseq->cs);
746 return objs;
749 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
751 HeapFree(GetProcessHeap(), 0, array);
754 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
756 HANDLE b_handle;
757 HANDLE *objs = wait_array;
758 DWORD res;
759 RpcConnection *cconn;
760 RpcConnection_np *conn;
762 if (!objs)
763 return -1;
767 /* an alertable wait isn't strictly necessary, but due to our
768 * overlapped I/O implementation in Wine we need to free some memory
769 * by the file user APC being called, even if no completion routine was
770 * specified at the time of starting the async operation */
771 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
772 } while (res == WAIT_IO_COMPLETION);
774 if (res == WAIT_OBJECT_0)
775 return 0;
776 else if (res == WAIT_FAILED)
778 ERR("wait failed with error %d\n", GetLastError());
779 return -1;
781 else
783 b_handle = objs[res - WAIT_OBJECT_0];
784 /* find which connection got a RPC */
785 EnterCriticalSection(&protseq->cs);
786 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
787 while (conn) {
788 if (b_handle == conn->listen_thread) break;
789 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
791 cconn = NULL;
792 if (conn)
794 DWORD exit_code;
795 if (GetExitCodeThread(conn->listen_thread, &exit_code) && exit_code == RPC_S_OK)
796 RPCRT4_SpawnConnection(&cconn, &conn->common);
797 CloseHandle(conn->listen_thread);
798 conn->listen_thread = 0;
800 else
801 ERR("failed to locate connection for handle %p\n", b_handle);
802 LeaveCriticalSection(&protseq->cs);
803 if (cconn)
805 RPCRT4_new_client(cconn);
806 return 1;
808 else return -1;
812 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
813 const char *networkaddr,
814 const char *endpoint)
816 twr_empty_floor_t *pipe_floor;
817 size_t size;
818 size_t endpoint_size;
820 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
822 endpoint_size = strlen(endpoint) + 1;
823 size = sizeof(*pipe_floor) + endpoint_size;
825 if (!tower_data)
826 return size;
828 pipe_floor = (twr_empty_floor_t *)tower_data;
830 tower_data += sizeof(*pipe_floor);
832 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
833 pipe_floor->protid = EPM_PROTOCOL_PIPE;
834 pipe_floor->count_rhs = endpoint_size;
836 memcpy(tower_data, endpoint, endpoint_size);
838 return size;
841 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
842 size_t tower_size,
843 char **networkaddr,
844 char **endpoint)
846 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
848 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
850 if (tower_size < sizeof(*pipe_floor))
851 return EPT_S_NOT_REGISTERED;
853 tower_data += sizeof(*pipe_floor);
854 tower_size -= sizeof(*pipe_floor);
856 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
857 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
858 (pipe_floor->count_rhs > tower_size) ||
859 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
860 return EPT_S_NOT_REGISTERED;
862 if (networkaddr)
863 *networkaddr = NULL;
865 if (endpoint)
867 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
868 if (!*endpoint)
869 return RPC_S_OUT_OF_RESOURCES;
870 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
873 return RPC_S_OK;
876 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
878 return FALSE;
881 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
882 unsigned char *in_buffer,
883 unsigned int in_size,
884 unsigned char *out_buffer,
885 unsigned int *out_size)
887 /* since this protocol is local to the machine there is no need to
888 * authenticate the caller */
889 *out_size = 0;
890 return RPC_S_OK;
893 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
894 enum secure_packet_direction dir,
895 RpcPktHdr *hdr, unsigned int hdr_size,
896 unsigned char *stub_data, unsigned int stub_data_size,
897 RpcAuthVerifier *auth_hdr,
898 unsigned char *auth_value, unsigned int auth_value_size)
900 /* since this protocol is local to the machine there is no need to secure
901 * the packet */
902 return RPC_S_OK;
905 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
906 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
907 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
909 TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
910 server_princ_name, authn_level, authn_svc, authz_svc, flags);
912 if (privs)
914 FIXME("privs not implemented\n");
915 *privs = NULL;
917 if (server_princ_name)
919 FIXME("server_princ_name not implemented\n");
920 *server_princ_name = NULL;
922 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
923 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
924 if (authz_svc)
926 FIXME("authorization service not implemented\n");
927 *authz_svc = RPC_C_AUTHZ_NONE;
929 if (flags)
930 FIXME("flags 0x%x not implemented\n", flags);
932 return RPC_S_OK;
935 /**** ncacn_ip_tcp support ****/
937 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
938 const char *networkaddr,
939 unsigned char tcp_protid,
940 const char *endpoint)
942 twr_tcp_floor_t *tcp_floor;
943 twr_ipv4_floor_t *ipv4_floor;
944 struct addrinfo *ai;
945 struct addrinfo hints;
946 int ret;
947 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
949 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
951 if (!tower_data)
952 return size;
954 tcp_floor = (twr_tcp_floor_t *)tower_data;
955 tower_data += sizeof(*tcp_floor);
957 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
959 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
960 tcp_floor->protid = tcp_protid;
961 tcp_floor->count_rhs = sizeof(tcp_floor->port);
963 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
964 ipv4_floor->protid = EPM_PROTOCOL_IP;
965 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
967 hints.ai_flags = AI_NUMERICHOST;
968 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
969 hints.ai_family = PF_INET;
970 hints.ai_socktype = SOCK_STREAM;
971 hints.ai_protocol = IPPROTO_TCP;
972 hints.ai_addrlen = 0;
973 hints.ai_addr = NULL;
974 hints.ai_canonname = NULL;
975 hints.ai_next = NULL;
977 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
978 if (ret)
980 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
981 if (ret)
983 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
984 return 0;
988 if (ai->ai_family == PF_INET)
990 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
991 tcp_floor->port = sin->sin_port;
992 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
994 else
996 ERR("unexpected protocol family %d\n", ai->ai_family);
997 freeaddrinfo(ai);
998 return 0;
1001 freeaddrinfo(ai);
1003 return size;
1006 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1007 size_t tower_size,
1008 char **networkaddr,
1009 unsigned char tcp_protid,
1010 char **endpoint)
1012 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1013 const twr_ipv4_floor_t *ipv4_floor;
1014 struct in_addr in_addr;
1016 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1018 if (tower_size < sizeof(*tcp_floor))
1019 return EPT_S_NOT_REGISTERED;
1021 tower_data += sizeof(*tcp_floor);
1022 tower_size -= sizeof(*tcp_floor);
1024 if (tower_size < sizeof(*ipv4_floor))
1025 return EPT_S_NOT_REGISTERED;
1027 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1029 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1030 (tcp_floor->protid != tcp_protid) ||
1031 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1032 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1033 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1034 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1035 return EPT_S_NOT_REGISTERED;
1037 if (endpoint)
1039 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1040 if (!*endpoint)
1041 return RPC_S_OUT_OF_RESOURCES;
1042 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1045 if (networkaddr)
1047 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1048 if (!*networkaddr)
1050 if (endpoint)
1052 I_RpcFree(*endpoint);
1053 *endpoint = NULL;
1055 return RPC_S_OUT_OF_RESOURCES;
1057 in_addr.s_addr = ipv4_floor->ipv4addr;
1058 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1060 ERR("inet_ntop: %s\n", strerror(errno));
1061 I_RpcFree(*networkaddr);
1062 *networkaddr = NULL;
1063 if (endpoint)
1065 I_RpcFree(*endpoint);
1066 *endpoint = NULL;
1068 return EPT_S_NOT_REGISTERED;
1072 return RPC_S_OK;
1075 typedef struct _RpcConnection_tcp
1077 RpcConnection common;
1078 int sock;
1079 #ifdef HAVE_SOCKETPAIR
1080 int cancel_fds[2];
1081 #else
1082 HANDLE sock_event;
1083 HANDLE cancel_event;
1084 #endif
1085 } RpcConnection_tcp;
1087 #ifdef HAVE_SOCKETPAIR
1089 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1091 if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
1093 ERR("socketpair() failed: %s\n", strerror(errno));
1094 return FALSE;
1096 return TRUE;
1099 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1101 struct pollfd pfds[2];
1102 pfds[0].fd = tcpc->sock;
1103 pfds[0].events = POLLIN;
1104 pfds[1].fd = tcpc->cancel_fds[0];
1105 pfds[1].events = POLLIN;
1106 if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
1108 ERR("poll() failed: %s\n", strerror(errno));
1109 return FALSE;
1111 if (pfds[1].revents & POLLIN) /* canceled */
1113 char dummy;
1114 read(pfds[1].fd, &dummy, sizeof(dummy));
1115 return FALSE;
1117 return TRUE;
1120 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1122 struct pollfd pfd;
1123 pfd.fd = tcpc->sock;
1124 pfd.events = POLLOUT;
1125 if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
1127 ERR("poll() failed: %s\n", strerror(errno));
1128 return FALSE;
1130 return TRUE;
1133 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1135 char dummy = 1;
1137 write(tcpc->cancel_fds[1], &dummy, 1);
1140 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1142 close(tcpc->cancel_fds[0]);
1143 close(tcpc->cancel_fds[1]);
1146 #else /* HAVE_SOCKETPAIR */
1148 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1150 static BOOL wsa_inited;
1151 if (!wsa_inited)
1153 WSADATA wsadata;
1154 WSAStartup(MAKEWORD(2, 2), &wsadata);
1155 /* Note: WSAStartup can be called more than once so we don't bother with
1156 * making accesses to wsa_inited thread-safe */
1157 wsa_inited = TRUE;
1159 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1160 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1161 if (!tcpc->sock_event || !tcpc->cancel_event)
1163 ERR("event creation failed\n");
1164 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1165 return FALSE;
1167 return TRUE;
1170 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1172 HANDLE wait_handles[2];
1173 DWORD res;
1174 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1176 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1177 return FALSE;
1179 wait_handles[0] = tcpc->sock_event;
1180 wait_handles[1] = tcpc->cancel_event;
1181 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1182 switch (res)
1184 case WAIT_OBJECT_0:
1185 return TRUE;
1186 case WAIT_OBJECT_0 + 1:
1187 return FALSE;
1188 default:
1189 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1190 return FALSE;
1194 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1196 DWORD res;
1197 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1199 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1200 return FALSE;
1202 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1203 switch (res)
1205 case WAIT_OBJECT_0:
1206 return TRUE;
1207 default:
1208 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1209 return FALSE;
1213 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1215 SetEvent(tcpc->cancel_event);
1218 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1220 CloseHandle(tcpc->sock_event);
1221 CloseHandle(tcpc->cancel_event);
1224 #endif
1226 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1228 RpcConnection_tcp *tcpc;
1229 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
1230 if (tcpc == NULL)
1231 return NULL;
1232 tcpc->sock = -1;
1233 if (!rpcrt4_sock_wait_init(tcpc))
1235 HeapFree(GetProcessHeap(), 0, tcpc);
1236 return NULL;
1238 return &tcpc->common;
1241 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1243 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1244 int sock;
1245 int ret;
1246 struct addrinfo *ai;
1247 struct addrinfo *ai_cur;
1248 struct addrinfo hints;
1250 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1252 if (tcpc->sock != -1)
1253 return RPC_S_OK;
1255 hints.ai_flags = 0;
1256 hints.ai_family = PF_UNSPEC;
1257 hints.ai_socktype = SOCK_STREAM;
1258 hints.ai_protocol = IPPROTO_TCP;
1259 hints.ai_addrlen = 0;
1260 hints.ai_addr = NULL;
1261 hints.ai_canonname = NULL;
1262 hints.ai_next = NULL;
1264 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1265 if (ret)
1267 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1268 Connection->Endpoint, gai_strerror(ret));
1269 return RPC_S_SERVER_UNAVAILABLE;
1272 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1274 int val;
1275 u_long nonblocking;
1277 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1279 TRACE("skipping non-IP/IPv6 address family\n");
1280 continue;
1283 if (TRACE_ON(rpc))
1285 char host[256];
1286 char service[256];
1287 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1288 host, sizeof(host), service, sizeof(service),
1289 NI_NUMERICHOST | NI_NUMERICSERV);
1290 TRACE("trying %s:%s\n", host, service);
1293 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1294 if (sock == -1)
1296 WARN("socket() failed: %s\n", strerror(errno));
1297 continue;
1300 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1302 WARN("connect() failed: %s\n", strerror(errno));
1303 closesocket(sock);
1304 continue;
1307 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1308 val = 1;
1309 setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1310 nonblocking = 1;
1311 ioctlsocket(sock, FIONBIO, &nonblocking);
1313 tcpc->sock = sock;
1315 freeaddrinfo(ai);
1316 TRACE("connected\n");
1317 return RPC_S_OK;
1320 freeaddrinfo(ai);
1321 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1322 return RPC_S_SERVER_UNAVAILABLE;
1325 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1327 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1328 int sock;
1329 int ret;
1330 struct addrinfo *ai;
1331 struct addrinfo *ai_cur;
1332 struct addrinfo hints;
1333 RpcConnection *first_connection = NULL;
1335 TRACE("(%p, %s)\n", protseq, endpoint);
1337 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1338 hints.ai_family = PF_UNSPEC;
1339 hints.ai_socktype = SOCK_STREAM;
1340 hints.ai_protocol = IPPROTO_TCP;
1341 hints.ai_addrlen = 0;
1342 hints.ai_addr = NULL;
1343 hints.ai_canonname = NULL;
1344 hints.ai_next = NULL;
1346 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1347 if (ret)
1349 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1350 gai_strerror(ret));
1351 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1352 return RPC_S_INVALID_ENDPOINT_FORMAT;
1353 return RPC_S_CANT_CREATE_ENDPOINT;
1356 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1358 RpcConnection_tcp *tcpc;
1359 RPC_STATUS create_status;
1360 struct sockaddr_storage sa;
1361 socklen_t sa_len;
1362 char service[NI_MAXSERV];
1363 u_long nonblocking;
1365 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1367 TRACE("skipping non-IP/IPv6 address family\n");
1368 continue;
1371 if (TRACE_ON(rpc))
1373 char host[256];
1374 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1375 host, sizeof(host), service, sizeof(service),
1376 NI_NUMERICHOST | NI_NUMERICSERV);
1377 TRACE("trying %s:%s\n", host, service);
1380 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1381 if (sock == -1)
1383 WARN("socket() failed: %s\n", strerror(errno));
1384 status = RPC_S_CANT_CREATE_ENDPOINT;
1385 continue;
1388 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1389 if (ret < 0)
1391 WARN("bind failed: %s\n", strerror(errno));
1392 closesocket(sock);
1393 if (errno == EADDRINUSE)
1394 status = RPC_S_DUPLICATE_ENDPOINT;
1395 else
1396 status = RPC_S_CANT_CREATE_ENDPOINT;
1397 continue;
1400 sa_len = sizeof(sa);
1401 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1403 WARN("getsockname() failed: %s\n", strerror(errno));
1404 closesocket(sock);
1405 status = RPC_S_CANT_CREATE_ENDPOINT;
1406 continue;
1409 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1410 NULL, 0, service, sizeof(service),
1411 NI_NUMERICSERV);
1412 if (ret)
1414 WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1415 closesocket(sock);
1416 status = RPC_S_CANT_CREATE_ENDPOINT;
1417 continue;
1420 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1421 protseq->Protseq, NULL,
1422 service, NULL, NULL, NULL, NULL);
1423 if (create_status != RPC_S_OK)
1425 closesocket(sock);
1426 status = create_status;
1427 continue;
1430 tcpc->sock = sock;
1431 ret = listen(sock, protseq->MaxCalls);
1432 if (ret < 0)
1434 WARN("listen failed: %s\n", strerror(errno));
1435 RPCRT4_ReleaseConnection(&tcpc->common);
1436 status = RPC_S_OUT_OF_RESOURCES;
1437 continue;
1439 /* need a non-blocking socket, otherwise accept() has a potential
1440 * race-condition (poll() says it is readable, connection drops,
1441 * and accept() blocks until the next connection comes...)
1443 nonblocking = 1;
1444 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1445 if (ret < 0)
1447 WARN("couldn't make socket non-blocking, error %d\n", ret);
1448 RPCRT4_ReleaseConnection(&tcpc->common);
1449 status = RPC_S_OUT_OF_RESOURCES;
1450 continue;
1453 tcpc->common.Next = first_connection;
1454 first_connection = &tcpc->common;
1456 /* since IPv4 and IPv6 share the same port space, we only need one
1457 * successful bind to listen for both */
1458 break;
1461 freeaddrinfo(ai);
1463 /* if at least one connection was created for an endpoint then
1464 * return success */
1465 if (first_connection)
1467 RpcConnection *conn;
1469 /* find last element in list */
1470 for (conn = first_connection; conn->Next; conn = conn->Next)
1473 EnterCriticalSection(&protseq->cs);
1474 conn->Next = protseq->conn;
1475 protseq->conn = first_connection;
1476 LeaveCriticalSection(&protseq->cs);
1478 TRACE("listening on %s\n", endpoint);
1479 return RPC_S_OK;
1482 ERR("couldn't listen on port %s\n", endpoint);
1483 return status;
1486 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1488 int ret;
1489 struct sockaddr_in address;
1490 socklen_t addrsize;
1491 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1492 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1493 u_long nonblocking;
1495 addrsize = sizeof(address);
1496 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1497 if (ret < 0)
1499 ERR("Failed to accept a TCP connection: error %d\n", ret);
1500 return RPC_S_OUT_OF_RESOURCES;
1503 nonblocking = 1;
1504 ioctlsocket(ret, FIONBIO, &nonblocking);
1505 client->sock = ret;
1507 client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN);
1508 ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
1509 if (ret != 0)
1511 ERR("Failed to retrieve the IP address, error %d\n", ret);
1512 return RPC_S_OUT_OF_RESOURCES;
1515 TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr);
1516 return RPC_S_OK;
1519 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1520 void *buffer, unsigned int count)
1522 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1523 int bytes_read = 0;
1524 while (bytes_read != count)
1526 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1527 if (!r)
1528 return -1;
1529 else if (r > 0)
1530 bytes_read += r;
1531 else if (errno == EINTR)
1532 continue;
1533 else if (errno != EAGAIN)
1535 WARN("recv() failed: %s\n", strerror(errno));
1536 return -1;
1538 else
1540 if (!rpcrt4_sock_wait_for_recv(tcpc))
1541 return -1;
1544 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1545 return bytes_read;
1548 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1549 const void *buffer, unsigned int count)
1551 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1552 int bytes_written = 0;
1553 while (bytes_written != count)
1555 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1556 if (r >= 0)
1557 bytes_written += r;
1558 else if (errno == EINTR)
1559 continue;
1560 else if (errno != EAGAIN)
1561 return -1;
1562 else
1564 if (!rpcrt4_sock_wait_for_send(tcpc))
1565 return -1;
1568 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1569 return bytes_written;
1572 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1574 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1576 TRACE("%d\n", tcpc->sock);
1578 if (tcpc->sock != -1)
1579 closesocket(tcpc->sock);
1580 tcpc->sock = -1;
1581 rpcrt4_sock_wait_destroy(tcpc);
1582 return 0;
1585 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1587 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1588 TRACE("%p\n", Connection);
1589 rpcrt4_sock_wait_cancel(tcpc);
1592 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint)
1594 FIXME("\n");
1595 return RPC_S_ACCESS_DENIED;
1598 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1600 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1602 TRACE("%p\n", Connection);
1604 if (!rpcrt4_sock_wait_for_recv(tcpc))
1605 return -1;
1606 return 0;
1609 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1610 const char *networkaddr,
1611 const char *endpoint)
1613 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1614 EPM_PROTOCOL_TCP, endpoint);
1617 #ifdef HAVE_SOCKETPAIR
1619 typedef struct _RpcServerProtseq_sock
1621 RpcServerProtseq common;
1622 int mgr_event_rcv;
1623 int mgr_event_snd;
1624 } RpcServerProtseq_sock;
1626 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1628 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1629 if (ps)
1631 int fds[2];
1632 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1634 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1635 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1636 ps->mgr_event_rcv = fds[0];
1637 ps->mgr_event_snd = fds[1];
1639 else
1641 ERR("socketpair failed with error %s\n", strerror(errno));
1642 HeapFree(GetProcessHeap(), 0, ps);
1643 return NULL;
1646 return &ps->common;
1649 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1651 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1652 char dummy = 1;
1653 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1656 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1658 struct pollfd *poll_info = prev_array;
1659 RpcConnection_tcp *conn;
1660 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1662 EnterCriticalSection(&protseq->cs);
1664 /* open and count connections */
1665 *count = 1;
1666 conn = (RpcConnection_tcp *)protseq->conn;
1667 while (conn) {
1668 if (conn->sock != -1)
1669 (*count)++;
1670 conn = (RpcConnection_tcp *)conn->common.Next;
1673 /* make array of connections */
1674 if (poll_info)
1675 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1676 else
1677 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1678 if (!poll_info)
1680 ERR("couldn't allocate poll_info\n");
1681 LeaveCriticalSection(&protseq->cs);
1682 return NULL;
1685 poll_info[0].fd = sockps->mgr_event_rcv;
1686 poll_info[0].events = POLLIN;
1687 *count = 1;
1688 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1689 while (conn) {
1690 if (conn->sock != -1)
1692 poll_info[*count].fd = conn->sock;
1693 poll_info[*count].events = POLLIN;
1694 (*count)++;
1696 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1698 LeaveCriticalSection(&protseq->cs);
1699 return poll_info;
1702 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1704 HeapFree(GetProcessHeap(), 0, array);
1707 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1709 struct pollfd *poll_info = wait_array;
1710 int ret;
1711 unsigned int i;
1712 RpcConnection *cconn;
1713 RpcConnection_tcp *conn;
1715 if (!poll_info)
1716 return -1;
1718 ret = poll(poll_info, count, -1);
1719 if (ret < 0)
1721 ERR("poll failed with error %d\n", ret);
1722 return -1;
1725 for (i = 0; i < count; i++)
1726 if (poll_info[i].revents & POLLIN)
1728 /* RPC server event */
1729 if (i == 0)
1731 char dummy;
1732 read(poll_info[0].fd, &dummy, sizeof(dummy));
1733 return 0;
1736 /* find which connection got a RPC */
1737 EnterCriticalSection(&protseq->cs);
1738 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1739 while (conn) {
1740 if (poll_info[i].fd == conn->sock) break;
1741 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1743 cconn = NULL;
1744 if (conn)
1745 RPCRT4_SpawnConnection(&cconn, &conn->common);
1746 else
1747 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1748 LeaveCriticalSection(&protseq->cs);
1749 if (cconn)
1750 RPCRT4_new_client(cconn);
1751 else
1752 return -1;
1755 return 1;
1758 #else /* HAVE_SOCKETPAIR */
1760 typedef struct _RpcServerProtseq_sock
1762 RpcServerProtseq common;
1763 HANDLE mgr_event;
1764 } RpcServerProtseq_sock;
1766 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1768 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1769 if (ps)
1771 static BOOL wsa_inited;
1772 if (!wsa_inited)
1774 WSADATA wsadata;
1775 WSAStartup(MAKEWORD(2, 2), &wsadata);
1776 /* Note: WSAStartup can be called more than once so we don't bother with
1777 * making accesses to wsa_inited thread-safe */
1778 wsa_inited = TRUE;
1780 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1782 return &ps->common;
1785 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1787 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1788 SetEvent(sockps->mgr_event);
1791 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1793 HANDLE *objs = prev_array;
1794 RpcConnection_tcp *conn;
1795 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1797 EnterCriticalSection(&protseq->cs);
1799 /* open and count connections */
1800 *count = 1;
1801 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1802 while (conn)
1804 if (conn->sock != -1)
1805 (*count)++;
1806 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1809 /* make array of connections */
1810 if (objs)
1811 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1812 else
1813 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1814 if (!objs)
1816 ERR("couldn't allocate objs\n");
1817 LeaveCriticalSection(&protseq->cs);
1818 return NULL;
1821 objs[0] = sockps->mgr_event;
1822 *count = 1;
1823 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1824 while (conn)
1826 if (conn->sock != -1)
1828 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1829 if (res == SOCKET_ERROR)
1830 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1831 else
1833 objs[*count] = conn->sock_event;
1834 (*count)++;
1837 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1839 LeaveCriticalSection(&protseq->cs);
1840 return objs;
1843 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1845 HeapFree(GetProcessHeap(), 0, array);
1848 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1850 HANDLE b_handle;
1851 HANDLE *objs = wait_array;
1852 DWORD res;
1853 RpcConnection *cconn;
1854 RpcConnection_tcp *conn;
1856 if (!objs)
1857 return -1;
1861 /* an alertable wait isn't strictly necessary, but due to our
1862 * overlapped I/O implementation in Wine we need to free some memory
1863 * by the file user APC being called, even if no completion routine was
1864 * specified at the time of starting the async operation */
1865 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1866 } while (res == WAIT_IO_COMPLETION);
1868 if (res == WAIT_OBJECT_0)
1869 return 0;
1870 else if (res == WAIT_FAILED)
1872 ERR("wait failed with error %d\n", GetLastError());
1873 return -1;
1875 else
1877 b_handle = objs[res - WAIT_OBJECT_0];
1878 /* find which connection got a RPC */
1879 EnterCriticalSection(&protseq->cs);
1880 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1881 while (conn)
1883 if (b_handle == conn->sock_event) break;
1884 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1886 cconn = NULL;
1887 if (conn)
1888 RPCRT4_SpawnConnection(&cconn, &conn->common);
1889 else
1890 ERR("failed to locate connection for handle %p\n", b_handle);
1891 LeaveCriticalSection(&protseq->cs);
1892 if (cconn)
1894 RPCRT4_new_client(cconn);
1895 return 1;
1897 else return -1;
1901 #endif /* HAVE_SOCKETPAIR */
1903 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1904 size_t tower_size,
1905 char **networkaddr,
1906 char **endpoint)
1908 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1909 networkaddr, EPM_PROTOCOL_TCP,
1910 endpoint);
1913 /**** ncacn_http support ****/
1915 /* 60 seconds is the period native uses */
1916 #define HTTP_IDLE_TIME 60000
1918 /* reference counted to avoid a race between a cancelled call's connection
1919 * being destroyed and the asynchronous InternetReadFileEx call being
1920 * completed */
1921 typedef struct _RpcHttpAsyncData
1923 LONG refs;
1924 HANDLE completion_event;
1925 WORD async_result;
1926 INTERNET_BUFFERSW inet_buffers;
1927 CRITICAL_SECTION cs;
1928 } RpcHttpAsyncData;
1930 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1932 return InterlockedIncrement(&data->refs);
1935 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1937 ULONG refs = InterlockedDecrement(&data->refs);
1938 if (!refs)
1940 TRACE("destroying async data %p\n", data);
1941 CloseHandle(data->completion_event);
1942 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1943 data->cs.DebugInfo->Spare[0] = 0;
1944 DeleteCriticalSection(&data->cs);
1945 HeapFree(GetProcessHeap(), 0, data);
1947 return refs;
1950 static void prepare_async_request(RpcHttpAsyncData *async_data)
1952 ResetEvent(async_data->completion_event);
1953 RpcHttpAsyncData_AddRef(async_data);
1956 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event)
1958 HANDLE handles[2] = { async_data->completion_event, cancel_event };
1959 DWORD res;
1961 if(call_ret) {
1962 RpcHttpAsyncData_Release(async_data);
1963 return RPC_S_OK;
1966 if(GetLastError() != ERROR_IO_PENDING) {
1967 RpcHttpAsyncData_Release(async_data);
1968 ERR("Request failed with error %d\n", GetLastError());
1969 return RPC_S_SERVER_UNAVAILABLE;
1972 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
1973 if(res != WAIT_OBJECT_0) {
1974 TRACE("Cancelled\n");
1975 return RPC_S_CALL_CANCELLED;
1978 if(async_data->async_result) {
1979 ERR("Async request failed with error %d\n", async_data->async_result);
1980 return RPC_S_SERVER_UNAVAILABLE;
1983 return RPC_S_OK;
1986 struct authinfo
1988 DWORD scheme;
1989 CredHandle cred;
1990 CtxtHandle ctx;
1991 TimeStamp exp;
1992 ULONG attr;
1993 ULONG max_token;
1994 char *data;
1995 unsigned int data_len;
1996 BOOL finished; /* finished authenticating */
1999 typedef struct _RpcConnection_http
2001 RpcConnection common;
2002 HINTERNET app_info;
2003 HINTERNET session;
2004 HINTERNET in_request;
2005 HINTERNET out_request;
2006 WCHAR *servername;
2007 HANDLE timer_cancelled;
2008 HANDLE cancel_event;
2009 DWORD last_sent_time;
2010 ULONG bytes_received;
2011 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
2012 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
2013 UUID connection_uuid;
2014 UUID in_pipe_uuid;
2015 UUID out_pipe_uuid;
2016 RpcHttpAsyncData *async_data;
2017 } RpcConnection_http;
2019 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
2021 RpcConnection_http *httpc;
2022 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
2023 if (!httpc) return NULL;
2024 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
2025 if (!httpc->async_data)
2027 HeapFree(GetProcessHeap(), 0, httpc);
2028 return NULL;
2030 TRACE("async data = %p\n", httpc->async_data);
2031 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2032 httpc->async_data->refs = 1;
2033 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW);
2034 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2035 InitializeCriticalSection(&httpc->async_data->cs);
2036 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs");
2037 return &httpc->common;
2040 typedef struct _HttpTimerThreadData
2042 PVOID timer_param;
2043 DWORD *last_sent_time;
2044 HANDLE timer_cancelled;
2045 } HttpTimerThreadData;
2047 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
2049 HINTERNET in_request = param;
2050 RpcPktHdr *idle_pkt;
2052 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
2053 0, 0);
2054 if (idle_pkt)
2056 DWORD bytes_written;
2057 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
2058 RPCRT4_FreeHeader(idle_pkt);
2062 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
2064 DWORD cur_time = GetTickCount();
2065 DWORD cached_last_sent_time = *last_sent_time;
2066 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
2069 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
2071 HttpTimerThreadData *data_in = param;
2072 HttpTimerThreadData data;
2073 DWORD timeout;
2075 data = *data_in;
2076 HeapFree(GetProcessHeap(), 0, data_in);
2078 for (timeout = HTTP_IDLE_TIME;
2079 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
2080 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
2082 /* are we too soon after last send? */
2083 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME)
2084 continue;
2085 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
2088 CloseHandle(data.timer_cancelled);
2089 return 0;
2092 static VOID WINAPI rpcrt4_http_internet_callback(
2093 HINTERNET hInternet,
2094 DWORD_PTR dwContext,
2095 DWORD dwInternetStatus,
2096 LPVOID lpvStatusInformation,
2097 DWORD dwStatusInformationLength)
2099 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
2101 switch (dwInternetStatus)
2103 case INTERNET_STATUS_REQUEST_COMPLETE:
2104 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
2105 if (async_data)
2107 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation;
2109 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError;
2110 SetEvent(async_data->completion_event);
2111 RpcHttpAsyncData_Release(async_data);
2113 break;
2117 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
2119 BOOL ret;
2120 DWORD status_code;
2121 DWORD size;
2122 DWORD index;
2123 WCHAR buf[32];
2124 WCHAR *status_text = buf;
2125 TRACE("\n");
2127 index = 0;
2128 size = sizeof(status_code);
2129 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
2130 if (!ret)
2131 return GetLastError();
2132 if (status_code == HTTP_STATUS_OK)
2133 return RPC_S_OK;
2134 index = 0;
2135 size = sizeof(buf);
2136 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2137 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2139 status_text = HeapAlloc(GetProcessHeap(), 0, size);
2140 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2143 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
2144 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
2146 if (status_code == HTTP_STATUS_DENIED)
2147 return ERROR_ACCESS_DENIED;
2148 return RPC_S_SERVER_UNAVAILABLE;
2151 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
2153 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
2154 LPWSTR proxy = NULL;
2155 LPWSTR user = NULL;
2156 LPWSTR password = NULL;
2157 LPWSTR servername = NULL;
2158 const WCHAR *option;
2159 INTERNET_PORT port;
2161 if (httpc->common.QOS &&
2162 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
2164 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
2165 if (http_cred->TransportCredentials)
2167 WCHAR *p;
2168 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
2169 ULONG len = cred->DomainLength + 1 + cred->UserLength;
2170 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2171 if (!user)
2172 return RPC_S_OUT_OF_RESOURCES;
2173 p = user;
2174 if (cred->DomainLength)
2176 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
2177 p += cred->DomainLength;
2178 *p = '\\';
2179 p++;
2181 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
2182 p[cred->UserLength] = 0;
2184 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
2188 for (option = httpc->common.NetworkOptions; option;
2189 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
2191 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
2192 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
2194 if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
2196 const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
2197 const WCHAR *value_end;
2198 const WCHAR *p;
2200 value_end = strchrW(option, ',');
2201 if (!value_end)
2202 value_end = value_start + strlenW(value_start);
2203 for (p = value_start; p < value_end; p++)
2204 if (*p == ':')
2206 port = atoiW(p+1);
2207 value_end = p;
2208 break;
2210 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2211 servername = RPCRT4_strndupW(value_start, value_end-value_start);
2213 else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
2215 const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
2216 const WCHAR *value_end;
2218 value_end = strchrW(option, ',');
2219 if (!value_end)
2220 value_end = value_start + strlenW(value_start);
2221 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2222 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
2224 else
2225 FIXME("unhandled option %s\n", debugstr_w(option));
2228 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
2229 NULL, NULL, INTERNET_FLAG_ASYNC);
2230 if (!httpc->app_info)
2232 HeapFree(GetProcessHeap(), 0, password);
2233 HeapFree(GetProcessHeap(), 0, user);
2234 HeapFree(GetProcessHeap(), 0, proxy);
2235 HeapFree(GetProcessHeap(), 0, servername);
2236 ERR("InternetOpenW failed with error %d\n", GetLastError());
2237 return RPC_S_SERVER_UNAVAILABLE;
2239 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
2241 /* if no RpcProxy option specified, set the HTTP server address to the
2242 * RPC server address */
2243 if (!servername)
2245 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
2246 if (!servername)
2248 HeapFree(GetProcessHeap(), 0, password);
2249 HeapFree(GetProcessHeap(), 0, user);
2250 HeapFree(GetProcessHeap(), 0, proxy);
2251 return RPC_S_OUT_OF_RESOURCES;
2253 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
2256 port = (httpc->common.QOS &&
2257 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2258 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ?
2259 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
2261 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
2262 INTERNET_SERVICE_HTTP, 0, 0);
2264 HeapFree(GetProcessHeap(), 0, password);
2265 HeapFree(GetProcessHeap(), 0, user);
2266 HeapFree(GetProcessHeap(), 0, proxy);
2268 if (!httpc->session)
2270 ERR("InternetConnectW failed with error %d\n", GetLastError());
2271 HeapFree(GetProcessHeap(), 0, servername);
2272 return RPC_S_SERVER_UNAVAILABLE;
2274 httpc->servername = servername;
2275 return RPC_S_OK;
2278 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2279 void *buffer, unsigned int count)
2281 char *buf = buffer;
2282 BOOL ret;
2283 unsigned int bytes_left = count;
2284 RPC_STATUS status = RPC_S_OK;
2286 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count);
2288 while (bytes_left)
2290 async_data->inet_buffers.dwBufferLength = bytes_left;
2291 prepare_async_request(async_data);
2292 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0);
2293 status = wait_async_request(async_data, ret, cancel_event);
2294 if (status != RPC_S_OK)
2296 if (status == RPC_S_CALL_CANCELLED)
2297 TRACE("call cancelled\n");
2298 break;
2301 if (!async_data->inet_buffers.dwBufferLength)
2302 break;
2303 memcpy(buf, async_data->inet_buffers.lpvBuffer,
2304 async_data->inet_buffers.dwBufferLength);
2306 bytes_left -= async_data->inet_buffers.dwBufferLength;
2307 buf += async_data->inet_buffers.dwBufferLength;
2310 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
2311 async_data->inet_buffers.lpvBuffer = NULL;
2313 TRACE("%p %p %u -> %u\n", req, buffer, count, status);
2314 return status == RPC_S_OK ? count : -1;
2317 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2319 BYTE buf[20];
2320 BOOL ret;
2321 RPC_STATUS status;
2323 TRACE("sending echo request to server\n");
2325 prepare_async_request(async_data);
2326 ret = HttpSendRequestW(req, NULL, 0, NULL, 0);
2327 status = wait_async_request(async_data, ret, cancel_event);
2328 if (status != RPC_S_OK) return status;
2330 status = rpcrt4_http_check_response(req);
2331 if (status != RPC_S_OK) return status;
2333 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf));
2334 /* FIXME: do something with retrieved data */
2336 return RPC_S_OK;
2339 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len)
2341 static const WCHAR fmtW[] =
2342 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0};
2343 WCHAR header[sizeof(fmtW) / sizeof(fmtW[0]) + 10];
2345 sprintfW(header, fmtW, len);
2346 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK;
2347 return RPC_S_SERVER_UNAVAILABLE;
2350 /* prepare the in pipe for use by RPC packets */
2351 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2352 const UUID *connection_uuid, const UUID *in_pipe_uuid,
2353 const UUID *association_uuid, BOOL authorized)
2355 BOOL ret;
2356 RPC_STATUS status;
2357 RpcPktHdr *hdr;
2358 INTERNET_BUFFERSW buffers_in;
2359 DWORD bytes_written;
2361 if (!authorized)
2363 /* ask wininet to authorize, if necessary */
2364 status = send_echo_request(in_request, async_data, cancel_event);
2365 if (status != RPC_S_OK) return status;
2367 memset(&buffers_in, 0, sizeof(buffers_in));
2368 buffers_in.dwStructSize = sizeof(buffers_in);
2369 /* FIXME: get this from the registry */
2370 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2371 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal);
2372 if (status != RPC_S_OK) return status;
2374 prepare_async_request(async_data);
2375 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2376 status = wait_async_request(async_data, ret, cancel_event);
2377 if (status != RPC_S_OK) return status;
2379 TRACE("sending HTTP connect header to server\n");
2380 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2381 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2382 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2383 RPCRT4_FreeHeader(hdr);
2384 if (!ret)
2386 ERR("InternetWriteFile failed with error %d\n", GetLastError());
2387 return RPC_S_SERVER_UNAVAILABLE;
2390 return RPC_S_OK;
2393 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data,
2394 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data)
2396 unsigned short data_len;
2397 unsigned int size;
2399 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0)
2400 return RPC_S_SERVER_UNAVAILABLE;
2401 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2403 ERR("wrong packet type received %d or wrong frag_len %d\n",
2404 hdr->common.ptype, hdr->common.frag_len);
2405 return RPC_S_PROTOCOL_ERROR;
2408 size = sizeof(hdr->http) - sizeof(hdr->common);
2409 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0)
2410 return RPC_S_SERVER_UNAVAILABLE;
2412 data_len = hdr->common.frag_len - sizeof(hdr->http);
2413 if (data_len)
2415 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2416 if (!*data)
2417 return RPC_S_OUT_OF_RESOURCES;
2418 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0)
2420 HeapFree(GetProcessHeap(), 0, *data);
2421 return RPC_S_SERVER_UNAVAILABLE;
2424 else
2425 *data = NULL;
2427 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2429 ERR("invalid http packet\n");
2430 HeapFree(GetProcessHeap(), 0, *data);
2431 return RPC_S_PROTOCOL_ERROR;
2434 return RPC_S_OK;
2437 /* prepare the out pipe for use by RPC packets */
2438 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data,
2439 HANDLE cancel_event, const UUID *connection_uuid,
2440 const UUID *out_pipe_uuid, ULONG *flow_control_increment,
2441 BOOL authorized)
2443 BOOL ret;
2444 RPC_STATUS status;
2445 RpcPktHdr *hdr;
2446 BYTE *data_from_server;
2447 RpcPktHdr pkt_from_server;
2448 ULONG field1, field3;
2449 BYTE buf[20];
2451 if (!authorized)
2453 /* ask wininet to authorize, if necessary */
2454 status = send_echo_request(out_request, async_data, cancel_event);
2455 if (status != RPC_S_OK) return status;
2457 else
2458 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf));
2460 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL);
2461 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2463 status = insert_content_length_header(out_request, hdr->common.frag_len);
2464 if (status != RPC_S_OK)
2466 RPCRT4_FreeHeader(hdr);
2467 return status;
2470 TRACE("sending HTTP connect header to server\n");
2471 prepare_async_request(async_data);
2472 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2473 status = wait_async_request(async_data, ret, cancel_event);
2474 RPCRT4_FreeHeader(hdr);
2475 if (status != RPC_S_OK) return status;
2477 status = rpcrt4_http_check_response(out_request);
2478 if (status != RPC_S_OK) return status;
2480 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2481 &pkt_from_server, &data_from_server);
2482 if (status != RPC_S_OK) return status;
2483 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2484 &field1);
2485 HeapFree(GetProcessHeap(), 0, data_from_server);
2486 if (status != RPC_S_OK) return status;
2487 TRACE("received (%d) from first prepare header\n", field1);
2489 for (;;)
2491 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2492 &pkt_from_server, &data_from_server);
2493 if (status != RPC_S_OK) return status;
2494 if (pkt_from_server.http.flags != 0x0001) break;
2496 TRACE("http idle packet, waiting for real packet\n");
2497 HeapFree(GetProcessHeap(), 0, data_from_server);
2498 if (pkt_from_server.http.num_data_items != 0)
2500 ERR("HTTP idle packet should have no data items instead of %d\n",
2501 pkt_from_server.http.num_data_items);
2502 return RPC_S_PROTOCOL_ERROR;
2505 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2506 &field1, flow_control_increment,
2507 &field3);
2508 HeapFree(GetProcessHeap(), 0, data_from_server);
2509 if (status != RPC_S_OK) return status;
2510 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2512 return RPC_S_OK;
2515 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
2517 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2518 UINT i = 0, x;
2520 while (len > 0)
2522 /* first 6 bits, all from bin[0] */
2523 base64[i++] = enc[(bin[0] & 0xfc) >> 2];
2524 x = (bin[0] & 3) << 4;
2526 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
2527 if (len == 1)
2529 base64[i++] = enc[x];
2530 base64[i++] = '=';
2531 base64[i++] = '=';
2532 break;
2534 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
2535 x = (bin[1] & 0x0f) << 2;
2537 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
2538 if (len == 2)
2540 base64[i++] = enc[x];
2541 base64[i++] = '=';
2542 break;
2544 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
2546 /* last 6 bits, all from bin [2] */
2547 base64[i++] = enc[bin[2] & 0x3f];
2548 bin += 3;
2549 len -= 3;
2551 base64[i] = 0;
2552 return i;
2555 static inline char decode_char( WCHAR c )
2557 if (c >= 'A' && c <= 'Z') return c - 'A';
2558 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2559 if (c >= '0' && c <= '9') return c - '0' + 52;
2560 if (c == '+') return 62;
2561 if (c == '/') return 63;
2562 return 64;
2565 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
2567 unsigned int i = 0;
2568 char c0, c1, c2, c3;
2569 const WCHAR *p = base64;
2571 while (len > 4)
2573 if ((c0 = decode_char( p[0] )) > 63) return 0;
2574 if ((c1 = decode_char( p[1] )) > 63) return 0;
2575 if ((c2 = decode_char( p[2] )) > 63) return 0;
2576 if ((c3 = decode_char( p[3] )) > 63) return 0;
2578 if (buf)
2580 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2581 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2582 buf[i + 2] = (c2 << 6) | c3;
2584 len -= 4;
2585 i += 3;
2586 p += 4;
2588 if (p[2] == '=')
2590 if ((c0 = decode_char( p[0] )) > 63) return 0;
2591 if ((c1 = decode_char( p[1] )) > 63) return 0;
2593 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
2594 i++;
2596 else if (p[3] == '=')
2598 if ((c0 = decode_char( p[0] )) > 63) return 0;
2599 if ((c1 = decode_char( p[1] )) > 63) return 0;
2600 if ((c2 = decode_char( p[2] )) > 63) return 0;
2602 if (buf)
2604 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2605 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2607 i += 2;
2609 else
2611 if ((c0 = decode_char( p[0] )) > 63) return 0;
2612 if ((c1 = decode_char( p[1] )) > 63) return 0;
2613 if ((c2 = decode_char( p[2] )) > 63) return 0;
2614 if ((c3 = decode_char( p[3] )) > 63) return 0;
2616 if (buf)
2618 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2619 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2620 buf[i + 2] = (c2 << 6) | c3;
2622 i += 3;
2624 return i;
2627 static struct authinfo *alloc_authinfo(void)
2629 struct authinfo *ret;
2631 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL;
2633 SecInvalidateHandle(&ret->cred);
2634 SecInvalidateHandle(&ret->ctx);
2635 memset(&ret->exp, 0, sizeof(ret->exp));
2636 ret->scheme = 0;
2637 ret->attr = 0;
2638 ret->max_token = 0;
2639 ret->data = NULL;
2640 ret->data_len = 0;
2641 ret->finished = FALSE;
2642 return ret;
2645 static void destroy_authinfo(struct authinfo *info)
2647 if (!info) return;
2649 if (SecIsValidHandle(&info->ctx))
2650 DeleteSecurityContext(&info->ctx);
2651 if (SecIsValidHandle(&info->cred))
2652 FreeCredentialsHandle(&info->cred);
2654 HeapFree(GetProcessHeap(), 0, info->data);
2655 HeapFree(GetProcessHeap(), 0, info);
2658 static const WCHAR basicW[] = {'B','a','s','i','c',0};
2659 static const WCHAR ntlmW[] = {'N','T','L','M',0};
2660 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0};
2661 static const WCHAR digestW[] = {'D','i','g','e','s','t',0};
2662 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2664 static const struct
2666 const WCHAR *str;
2667 unsigned int len;
2668 DWORD scheme;
2670 auth_schemes[] =
2672 { basicW, ARRAYSIZE(basicW) - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC },
2673 { ntlmW, ARRAYSIZE(ntlmW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM },
2674 { passportW, ARRAYSIZE(passportW) - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT },
2675 { digestW, ARRAYSIZE(digestW) - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST },
2676 { negotiateW, ARRAYSIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE }
2678 static const unsigned int num_auth_schemes = sizeof(auth_schemes)/sizeof(auth_schemes[0]);
2680 static DWORD auth_scheme_from_header( const WCHAR *header )
2682 unsigned int i;
2683 for (i = 0; i < num_auth_schemes; i++)
2685 if (!strncmpiW( header, auth_schemes[i].str, auth_schemes[i].len ) &&
2686 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
2688 return 0;
2691 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen)
2693 DWORD len, index = 0;
2694 for (;;)
2696 len = buflen;
2697 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE;
2698 if (auth_scheme_from_header(buffer) == scheme) break;
2700 return TRUE;
2703 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername,
2704 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr)
2706 struct authinfo *info = *auth_ptr;
2707 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials;
2708 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2710 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE;
2712 switch (creds->AuthnSchemes[0])
2714 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2716 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
2717 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
2719 info->data_len = userlen + passlen + 1;
2720 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len)))
2722 status = RPC_S_OUT_OF_MEMORY;
2723 break;
2725 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL);
2726 info->data[userlen] = ':';
2727 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL);
2729 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC;
2730 info->finished = TRUE;
2731 status = RPC_S_OK;
2732 break;
2734 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2735 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2738 static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2739 SECURITY_STATUS ret;
2740 SecBufferDesc out_desc, in_desc;
2741 SecBuffer out, in;
2742 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE;
2743 SEC_WCHAR *scheme;
2744 int scheme_len;
2745 const WCHAR *p;
2746 WCHAR auth_value[2048];
2747 DWORD size = sizeof(auth_value);
2748 BOOL first = FALSE;
2750 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW;
2751 else scheme = negotiateW;
2752 scheme_len = strlenW( scheme );
2754 if (!*auth_ptr)
2756 TimeStamp exp;
2757 SecPkgInfoW *pkg_info;
2759 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp);
2760 if (ret != SEC_E_OK) break;
2762 ret = QuerySecurityPackageInfoW(scheme, &pkg_info);
2763 if (ret != SEC_E_OK) break;
2765 info->max_token = pkg_info->cbMaxToken;
2766 FreeContextBuffer(pkg_info);
2767 first = TRUE;
2769 else
2771 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break;
2772 if (auth_scheme_from_header(auth_value) != info->scheme)
2774 ERR("authentication scheme changed\n");
2775 break;
2778 in.BufferType = SECBUFFER_TOKEN;
2779 in.cbBuffer = 0;
2780 in.pvBuffer = NULL;
2782 in_desc.ulVersion = 0;
2783 in_desc.cBuffers = 1;
2784 in_desc.pBuffers = &in;
2786 p = auth_value + scheme_len;
2787 if (!first && *p == ' ')
2789 int len = strlenW(++p);
2790 in.cbBuffer = decode_base64(p, len, NULL);
2791 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break;
2792 decode_base64(p, len, in.pvBuffer);
2794 out.BufferType = SECBUFFER_TOKEN;
2795 out.cbBuffer = info->max_token;
2796 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer)))
2798 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2799 break;
2801 out_desc.ulVersion = 0;
2802 out_desc.cBuffers = 1;
2803 out_desc.pBuffers = &out;
2805 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx,
2806 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP,
2807 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc,
2808 &info->attr, &info->exp);
2809 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2810 if (ret == SEC_E_OK)
2812 HeapFree(GetProcessHeap(), 0, info->data);
2813 info->data = out.pvBuffer;
2814 info->data_len = out.cbBuffer;
2815 info->finished = TRUE;
2816 TRACE("sending last auth packet\n");
2817 status = RPC_S_OK;
2819 else if (ret == SEC_I_CONTINUE_NEEDED)
2821 HeapFree(GetProcessHeap(), 0, info->data);
2822 info->data = out.pvBuffer;
2823 info->data_len = out.cbBuffer;
2824 TRACE("sending next auth packet\n");
2825 status = RPC_S_OK;
2827 else
2829 ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret);
2830 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
2831 break;
2833 info->scheme = creds->AuthnSchemes[0];
2834 break;
2836 default:
2837 FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]);
2838 break;
2841 if (status != RPC_S_OK)
2843 destroy_authinfo(info);
2844 *auth_ptr = NULL;
2845 return status;
2847 *auth_ptr = info;
2848 return RPC_S_OK;
2851 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len)
2853 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '};
2854 static const WCHAR basicW[] = {'B','a','s','i','c',' '};
2855 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '};
2856 static const WCHAR ntlmW[] = {'N','T','L','M',' '};
2857 int scheme_len, auth_len = sizeof(authW) / sizeof(authW[0]), len = ((data_len + 2) * 4) / 3;
2858 const WCHAR *scheme_str;
2859 WCHAR *header, *ptr;
2860 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2862 switch (scheme)
2864 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2865 scheme_str = basicW;
2866 scheme_len = sizeof(basicW) / sizeof(basicW[0]);
2867 break;
2868 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2869 scheme_str = negotiateW;
2870 scheme_len = sizeof(negotiateW) / sizeof(negotiateW[0]);
2871 break;
2872 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2873 scheme_str = ntlmW;
2874 scheme_len = sizeof(ntlmW) / sizeof(ntlmW[0]);
2875 break;
2876 default:
2877 ERR("unknown scheme %u\n", scheme);
2878 return RPC_S_SERVER_UNAVAILABLE;
2880 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR))))
2882 memcpy(header, authW, auth_len * sizeof(WCHAR));
2883 ptr = header + auth_len;
2884 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR));
2885 ptr += scheme_len;
2886 len = encode_base64(data, data_len, ptr);
2887 ptr[len++] = '\r';
2888 ptr[len++] = '\n';
2889 ptr[len] = 0;
2890 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE))
2891 status = RPC_S_OK;
2892 HeapFree(GetProcessHeap(), 0, header);
2894 return status;
2897 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2899 DWORD count, len = 0, size = sizeof(len);
2900 char buf[2048];
2902 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL);
2903 if (!len) return;
2904 for (;;)
2906 count = min(sizeof(buf), len);
2907 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return;
2908 len -= count;
2912 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request)
2914 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0};
2915 struct authinfo *info = NULL;
2916 RPC_STATUS status;
2917 BOOL ret;
2919 for (;;)
2921 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info);
2922 if (status != RPC_S_OK) break;
2924 status = insert_authorization_header(request, info->scheme, info->data, info->data_len);
2925 if (status != RPC_S_OK) break;
2927 prepare_async_request(httpc->async_data);
2928 ret = HttpSendRequestW(request, NULL, 0, NULL, 0);
2929 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
2930 if (status != RPC_S_OK || info->finished) break;
2932 status = rpcrt4_http_check_response(request);
2933 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break;
2934 drain_content(request, httpc->async_data, httpc->cancel_event);
2937 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
2938 HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
2940 destroy_authinfo(info);
2941 return status;
2944 static BOOL has_credentials(RpcConnection_http *httpc)
2946 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
2947 SEC_WINNT_AUTH_IDENTITY_W *id;
2949 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
2950 return FALSE;
2952 creds = httpc->common.QOS->qos->u.HttpCredentials;
2953 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
2954 return FALSE;
2956 id = creds->TransportCredentials;
2957 if (!id || !id->User || !id->Password) return FALSE;
2959 return TRUE;
2962 static BOOL is_secure(RpcConnection_http *httpc)
2964 return httpc->common.QOS &&
2965 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2966 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2969 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value)
2971 static WCHAR httpW[] = {'h','t','t','p',0};
2972 static WCHAR httpsW[] = {'h','t','t','p','s',0};
2973 URL_COMPONENTSW uc;
2974 DWORD len;
2975 WCHAR *url;
2976 BOOL ret;
2978 if (!value) return RPC_S_OK;
2980 uc.dwStructSize = sizeof(uc);
2981 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW;
2982 uc.dwSchemeLength = 0;
2983 uc.lpszHostName = httpc->servername;
2984 uc.dwHostNameLength = 0;
2985 uc.nPort = 0;
2986 uc.lpszUserName = NULL;
2987 uc.dwUserNameLength = 0;
2988 uc.lpszPassword = NULL;
2989 uc.dwPasswordLength = 0;
2990 uc.lpszUrlPath = NULL;
2991 uc.dwUrlPathLength = 0;
2992 uc.lpszExtraInfo = NULL;
2993 uc.dwExtraInfoLength = 0;
2995 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
2996 return RPC_S_SERVER_UNAVAILABLE;
2998 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY;
3000 len = len / sizeof(WCHAR) - 1;
3001 if (!InternetCreateUrlW(&uc, 0, url, &len))
3003 HeapFree(GetProcessHeap(), 0, url);
3004 return RPC_S_SERVER_UNAVAILABLE;
3007 ret = InternetSetCookieW(url, NULL, value);
3008 HeapFree(GetProcessHeap(), 0, url);
3009 if (!ret) return RPC_S_SERVER_UNAVAILABLE;
3011 return RPC_S_OK;
3014 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
3016 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
3017 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
3018 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
3019 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
3020 static const WCHAR wszColon[] = {':',0};
3021 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
3022 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
3023 DWORD flags;
3024 WCHAR *url;
3025 RPC_STATUS status;
3026 BOOL secure, credentials;
3027 HttpTimerThreadData *timer_data;
3028 HANDLE thread;
3030 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
3032 if (Connection->server)
3034 ERR("ncacn_http servers not supported yet\n");
3035 return RPC_S_SERVER_UNAVAILABLE;
3038 if (httpc->in_request)
3039 return RPC_S_OK;
3041 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3043 UuidCreate(&httpc->connection_uuid);
3044 UuidCreate(&httpc->in_pipe_uuid);
3045 UuidCreate(&httpc->out_pipe_uuid);
3047 status = rpcrt4_http_internet_connect(httpc);
3048 if (status != RPC_S_OK)
3049 return status;
3051 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
3052 if (!url)
3053 return RPC_S_OUT_OF_MEMORY;
3054 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
3055 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
3056 strcatW(url, wszColon);
3057 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
3059 secure = is_secure(httpc);
3060 credentials = has_credentials(httpc);
3062 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
3063 INTERNET_FLAG_NO_AUTO_REDIRECT;
3064 if (secure) flags |= INTERNET_FLAG_SECURE;
3065 if (credentials) flags |= INTERNET_FLAG_NO_AUTH;
3067 status = set_auth_cookie(httpc, Connection->CookieAuth);
3068 if (status != RPC_S_OK)
3070 HeapFree(GetProcessHeap(), 0, url);
3071 return status;
3073 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes,
3074 flags, (DWORD_PTR)httpc->async_data);
3075 if (!httpc->in_request)
3077 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
3078 HeapFree(GetProcessHeap(), 0, url);
3079 return RPC_S_SERVER_UNAVAILABLE;
3082 if (credentials)
3084 status = authorize_request(httpc, httpc->in_request);
3085 if (status != RPC_S_OK)
3087 HeapFree(GetProcessHeap(), 0, url);
3088 return status;
3090 status = rpcrt4_http_check_response(httpc->in_request);
3091 if (status != RPC_S_OK)
3093 HeapFree(GetProcessHeap(), 0, url);
3094 return status;
3096 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event);
3099 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes,
3100 flags, (DWORD_PTR)httpc->async_data);
3101 HeapFree(GetProcessHeap(), 0, url);
3102 if (!httpc->out_request)
3104 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
3105 return RPC_S_SERVER_UNAVAILABLE;
3108 if (credentials)
3110 status = authorize_request(httpc, httpc->out_request);
3111 if (status != RPC_S_OK)
3112 return status;
3115 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event,
3116 &httpc->connection_uuid, &httpc->in_pipe_uuid,
3117 &Connection->assoc->http_uuid, credentials);
3118 if (status != RPC_S_OK)
3119 return status;
3121 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event,
3122 &httpc->connection_uuid, &httpc->out_pipe_uuid,
3123 &httpc->flow_control_increment, credentials);
3124 if (status != RPC_S_OK)
3125 return status;
3127 httpc->flow_control_mark = httpc->flow_control_increment / 2;
3128 httpc->last_sent_time = GetTickCount();
3129 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
3131 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
3132 if (!timer_data)
3133 return ERROR_OUTOFMEMORY;
3134 timer_data->timer_param = httpc->in_request;
3135 timer_data->last_sent_time = &httpc->last_sent_time;
3136 timer_data->timer_cancelled = httpc->timer_cancelled;
3137 /* FIXME: should use CreateTimerQueueTimer when implemented */
3138 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
3139 if (!thread)
3141 HeapFree(GetProcessHeap(), 0, timer_data);
3142 return GetLastError();
3144 CloseHandle(thread);
3146 return RPC_S_OK;
3149 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
3151 assert(0);
3152 return RPC_S_SERVER_UNAVAILABLE;
3155 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
3156 void *buffer, unsigned int count)
3158 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3159 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count);
3162 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
3164 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3165 RPC_STATUS status;
3166 DWORD hdr_length;
3167 LONG dwRead;
3168 RpcPktCommonHdr common_hdr;
3170 *Header = NULL;
3172 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
3174 again:
3175 /* read packet common header */
3176 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
3177 if (dwRead != sizeof(common_hdr)) {
3178 WARN("Short read of header, %d bytes\n", dwRead);
3179 status = RPC_S_PROTOCOL_ERROR;
3180 goto fail;
3182 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
3183 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
3185 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
3186 status = RPC_S_PROTOCOL_ERROR;
3187 goto fail;
3190 status = RPCRT4_ValidateCommonHeader(&common_hdr);
3191 if (status != RPC_S_OK) goto fail;
3193 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
3194 if (hdr_length == 0) {
3195 WARN("header length == 0\n");
3196 status = RPC_S_PROTOCOL_ERROR;
3197 goto fail;
3200 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
3201 if (!*Header)
3203 status = RPC_S_OUT_OF_RESOURCES;
3204 goto fail;
3206 memcpy(*Header, &common_hdr, sizeof(common_hdr));
3208 /* read the rest of packet header */
3209 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
3210 if (dwRead != hdr_length - sizeof(common_hdr)) {
3211 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
3212 status = RPC_S_PROTOCOL_ERROR;
3213 goto fail;
3216 if (common_hdr.frag_len - hdr_length)
3218 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
3219 if (!*Payload)
3221 status = RPC_S_OUT_OF_RESOURCES;
3222 goto fail;
3225 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
3226 if (dwRead != common_hdr.frag_len - hdr_length)
3228 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
3229 status = RPC_S_PROTOCOL_ERROR;
3230 goto fail;
3233 else
3234 *Payload = NULL;
3236 if ((*Header)->common.ptype == PKT_HTTP)
3238 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
3240 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
3241 status = RPC_S_PROTOCOL_ERROR;
3242 goto fail;
3244 if ((*Header)->http.flags == 0x0001)
3246 TRACE("http idle packet, waiting for real packet\n");
3247 if ((*Header)->http.num_data_items != 0)
3249 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
3250 status = RPC_S_PROTOCOL_ERROR;
3251 goto fail;
3254 else if ((*Header)->http.flags == 0x0002)
3256 ULONG bytes_transmitted;
3257 ULONG flow_control_increment;
3258 UUID pipe_uuid;
3259 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
3260 Connection->server,
3261 &bytes_transmitted,
3262 &flow_control_increment,
3263 &pipe_uuid);
3264 if (status != RPC_S_OK)
3265 goto fail;
3266 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
3267 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
3268 /* FIXME: do something with parsed data */
3270 else
3272 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
3273 status = RPC_S_PROTOCOL_ERROR;
3274 goto fail;
3276 RPCRT4_FreeHeader(*Header);
3277 *Header = NULL;
3278 HeapFree(GetProcessHeap(), 0, *Payload);
3279 *Payload = NULL;
3280 goto again;
3283 /* success */
3284 status = RPC_S_OK;
3286 httpc->bytes_received += common_hdr.frag_len;
3288 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
3290 if (httpc->bytes_received > httpc->flow_control_mark)
3292 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
3293 httpc->bytes_received,
3294 httpc->flow_control_increment,
3295 &httpc->out_pipe_uuid);
3296 if (hdr)
3298 DWORD bytes_written;
3299 BOOL ret2;
3300 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
3301 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
3302 RPCRT4_FreeHeader(hdr);
3303 if (ret2)
3304 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
3308 fail:
3309 if (status != RPC_S_OK) {
3310 RPCRT4_FreeHeader(*Header);
3311 *Header = NULL;
3312 HeapFree(GetProcessHeap(), 0, *Payload);
3313 *Payload = NULL;
3315 return status;
3318 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
3319 const void *buffer, unsigned int count)
3321 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3322 DWORD bytes_written;
3323 BOOL ret;
3325 httpc->last_sent_time = ~0U; /* disable idle packet sending */
3326 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
3327 httpc->last_sent_time = GetTickCount();
3328 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
3329 return ret ? bytes_written : -1;
3332 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
3334 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3336 TRACE("\n");
3338 SetEvent(httpc->timer_cancelled);
3339 if (httpc->in_request)
3340 InternetCloseHandle(httpc->in_request);
3341 httpc->in_request = NULL;
3342 if (httpc->out_request)
3343 InternetCloseHandle(httpc->out_request);
3344 httpc->out_request = NULL;
3345 if (httpc->app_info)
3346 InternetCloseHandle(httpc->app_info);
3347 httpc->app_info = NULL;
3348 if (httpc->session)
3349 InternetCloseHandle(httpc->session);
3350 httpc->session = NULL;
3351 RpcHttpAsyncData_Release(httpc->async_data);
3352 if (httpc->cancel_event)
3353 CloseHandle(httpc->cancel_event);
3354 HeapFree(GetProcessHeap(), 0, httpc->servername);
3355 httpc->servername = NULL;
3357 return 0;
3360 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
3362 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3364 SetEvent(httpc->cancel_event);
3367 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint)
3369 FIXME("\n");
3370 return RPC_S_ACCESS_DENIED;
3373 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
3375 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3376 BOOL ret;
3377 RPC_STATUS status;
3379 prepare_async_request(httpc->async_data);
3380 ret = InternetQueryDataAvailable(httpc->out_request,
3381 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
3382 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
3383 return status == RPC_S_OK ? 0 : -1;
3386 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
3387 const char *networkaddr,
3388 const char *endpoint)
3390 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
3391 EPM_PROTOCOL_HTTP, endpoint);
3394 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
3395 size_t tower_size,
3396 char **networkaddr,
3397 char **endpoint)
3399 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
3400 networkaddr, EPM_PROTOCOL_HTTP,
3401 endpoint);
3404 static const struct connection_ops conn_protseq_list[] = {
3405 { "ncacn_np",
3406 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
3407 rpcrt4_conn_np_alloc,
3408 rpcrt4_ncacn_np_open,
3409 rpcrt4_ncacn_np_handoff,
3410 rpcrt4_conn_np_read,
3411 rpcrt4_conn_np_write,
3412 rpcrt4_conn_np_close,
3413 rpcrt4_conn_np_cancel_call,
3414 rpcrt4_ncacn_np_is_server_listening,
3415 rpcrt4_conn_np_wait_for_incoming_data,
3416 rpcrt4_ncacn_np_get_top_of_tower,
3417 rpcrt4_ncacn_np_parse_top_of_tower,
3418 NULL,
3419 RPCRT4_default_is_authorized,
3420 RPCRT4_default_authorize,
3421 RPCRT4_default_secure_packet,
3422 rpcrt4_conn_np_impersonate_client,
3423 rpcrt4_conn_np_revert_to_self,
3424 RPCRT4_default_inquire_auth_client,
3426 { "ncalrpc",
3427 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
3428 rpcrt4_conn_np_alloc,
3429 rpcrt4_ncalrpc_open,
3430 rpcrt4_ncalrpc_handoff,
3431 rpcrt4_conn_np_read,
3432 rpcrt4_conn_np_write,
3433 rpcrt4_conn_np_close,
3434 rpcrt4_conn_np_cancel_call,
3435 rpcrt4_ncalrpc_np_is_server_listening,
3436 rpcrt4_conn_np_wait_for_incoming_data,
3437 rpcrt4_ncalrpc_get_top_of_tower,
3438 rpcrt4_ncalrpc_parse_top_of_tower,
3439 NULL,
3440 rpcrt4_ncalrpc_is_authorized,
3441 rpcrt4_ncalrpc_authorize,
3442 rpcrt4_ncalrpc_secure_packet,
3443 rpcrt4_conn_np_impersonate_client,
3444 rpcrt4_conn_np_revert_to_self,
3445 rpcrt4_ncalrpc_inquire_auth_client,
3447 { "ncacn_ip_tcp",
3448 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
3449 rpcrt4_conn_tcp_alloc,
3450 rpcrt4_ncacn_ip_tcp_open,
3451 rpcrt4_conn_tcp_handoff,
3452 rpcrt4_conn_tcp_read,
3453 rpcrt4_conn_tcp_write,
3454 rpcrt4_conn_tcp_close,
3455 rpcrt4_conn_tcp_cancel_call,
3456 rpcrt4_conn_tcp_is_server_listening,
3457 rpcrt4_conn_tcp_wait_for_incoming_data,
3458 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
3459 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
3460 NULL,
3461 RPCRT4_default_is_authorized,
3462 RPCRT4_default_authorize,
3463 RPCRT4_default_secure_packet,
3464 RPCRT4_default_impersonate_client,
3465 RPCRT4_default_revert_to_self,
3466 RPCRT4_default_inquire_auth_client,
3468 { "ncacn_http",
3469 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
3470 rpcrt4_ncacn_http_alloc,
3471 rpcrt4_ncacn_http_open,
3472 rpcrt4_ncacn_http_handoff,
3473 rpcrt4_ncacn_http_read,
3474 rpcrt4_ncacn_http_write,
3475 rpcrt4_ncacn_http_close,
3476 rpcrt4_ncacn_http_cancel_call,
3477 rpcrt4_ncacn_http_is_server_listening,
3478 rpcrt4_ncacn_http_wait_for_incoming_data,
3479 rpcrt4_ncacn_http_get_top_of_tower,
3480 rpcrt4_ncacn_http_parse_top_of_tower,
3481 rpcrt4_ncacn_http_receive_fragment,
3482 RPCRT4_default_is_authorized,
3483 RPCRT4_default_authorize,
3484 RPCRT4_default_secure_packet,
3485 RPCRT4_default_impersonate_client,
3486 RPCRT4_default_revert_to_self,
3487 RPCRT4_default_inquire_auth_client,
3492 static const struct protseq_ops protseq_list[] =
3495 "ncacn_np",
3496 rpcrt4_protseq_np_alloc,
3497 rpcrt4_protseq_np_signal_state_changed,
3498 rpcrt4_protseq_np_get_wait_array,
3499 rpcrt4_protseq_np_free_wait_array,
3500 rpcrt4_protseq_np_wait_for_new_connection,
3501 rpcrt4_protseq_ncacn_np_open_endpoint,
3504 "ncalrpc",
3505 rpcrt4_protseq_np_alloc,
3506 rpcrt4_protseq_np_signal_state_changed,
3507 rpcrt4_protseq_np_get_wait_array,
3508 rpcrt4_protseq_np_free_wait_array,
3509 rpcrt4_protseq_np_wait_for_new_connection,
3510 rpcrt4_protseq_ncalrpc_open_endpoint,
3513 "ncacn_ip_tcp",
3514 rpcrt4_protseq_sock_alloc,
3515 rpcrt4_protseq_sock_signal_state_changed,
3516 rpcrt4_protseq_sock_get_wait_array,
3517 rpcrt4_protseq_sock_free_wait_array,
3518 rpcrt4_protseq_sock_wait_for_new_connection,
3519 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
3523 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
3525 unsigned int i;
3526 for(i=0; i<ARRAYSIZE(protseq_list); i++)
3527 if (!strcmp(protseq_list[i].name, protseq))
3528 return &protseq_list[i];
3529 return NULL;
3532 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
3534 unsigned int i;
3535 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
3536 if (!strcmp(conn_protseq_list[i].name, protseq))
3537 return &conn_protseq_list[i];
3538 return NULL;
3541 /**** interface to rest of code ****/
3543 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
3545 TRACE("(Connection == ^%p)\n", Connection);
3547 assert(!Connection->server);
3548 return Connection->ops->open_connection_client(Connection);
3551 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
3553 TRACE("(Connection == ^%p)\n", Connection);
3554 if (SecIsValidHandle(&Connection->ctx))
3556 DeleteSecurityContext(&Connection->ctx);
3557 SecInvalidateHandle(&Connection->ctx);
3559 rpcrt4_conn_close(Connection);
3560 return RPC_S_OK;
3563 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
3564 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
3565 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth)
3567 static LONG next_id;
3568 const struct connection_ops *ops;
3569 RpcConnection* NewConnection;
3571 ops = rpcrt4_get_conn_protseq_ops(Protseq);
3572 if (!ops)
3574 FIXME("not supported for protseq %s\n", Protseq);
3575 return RPC_S_PROTSEQ_NOT_SUPPORTED;
3578 NewConnection = ops->alloc();
3579 NewConnection->ref = 1;
3580 NewConnection->Next = NULL;
3581 NewConnection->server_binding = NULL;
3582 NewConnection->server = server;
3583 NewConnection->ops = ops;
3584 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
3585 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
3586 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
3587 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth);
3588 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
3589 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
3590 NewConnection->NextCallId = 1;
3592 SecInvalidateHandle(&NewConnection->ctx);
3593 memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
3594 NewConnection->attr = 0;
3595 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
3596 NewConnection->AuthInfo = AuthInfo;
3597 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
3598 NewConnection->encryption_auth_len = 0;
3599 NewConnection->signature_auth_len = 0;
3600 if (QOS) RpcQualityOfService_AddRef(QOS);
3601 NewConnection->QOS = QOS;
3603 list_init(&NewConnection->conn_pool_entry);
3604 NewConnection->async_state = NULL;
3606 TRACE("connection: %p\n", NewConnection);
3607 *Connection = NewConnection;
3609 return RPC_S_OK;
3612 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
3614 RPC_STATUS err;
3616 err = RPCRT4_CreateConnection(Connection, OldConnection->server, rpcrt4_conn_get_name(OldConnection),
3617 OldConnection->NetworkAddr, OldConnection->Endpoint, NULL,
3618 OldConnection->AuthInfo, OldConnection->QOS, OldConnection->CookieAuth);
3619 if (err == RPC_S_OK)
3620 rpcrt4_conn_handoff(OldConnection, *Connection);
3621 return err;
3624 RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn )
3626 InterlockedIncrement( &conn->ref );
3627 return conn;
3630 RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
3632 if (InterlockedDecrement( &Connection->ref ) > 0) return RPC_S_OK;
3634 TRACE("destroying connection %p\n", Connection);
3636 RPCRT4_CloseConnection(Connection);
3637 RPCRT4_strfree(Connection->Endpoint);
3638 RPCRT4_strfree(Connection->NetworkAddr);
3639 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
3640 HeapFree(GetProcessHeap(), 0, Connection->CookieAuth);
3641 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
3642 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
3644 /* server-only */
3645 if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
3647 HeapFree(GetProcessHeap(), 0, Connection);
3648 return RPC_S_OK;
3651 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)
3653 const struct connection_ops *ops;
3655 ops = rpcrt4_get_conn_protseq_ops(protseq);
3656 if (!ops)
3658 FIXME("not supported for protseq %s\n", protseq);
3659 return RPC_S_INVALID_BINDING;
3662 return ops->is_server_listening(endpoint);
3665 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3666 size_t *tower_size,
3667 const char *protseq,
3668 const char *networkaddr,
3669 const char *endpoint)
3671 twr_empty_floor_t *protocol_floor;
3672 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3674 *tower_size = 0;
3676 if (!protseq_ops)
3677 return RPC_S_INVALID_RPC_PROTSEQ;
3679 if (!tower_data)
3681 *tower_size = sizeof(*protocol_floor);
3682 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3683 return RPC_S_OK;
3686 protocol_floor = (twr_empty_floor_t *)tower_data;
3687 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3688 protocol_floor->protid = protseq_ops->epm_protocols[0];
3689 protocol_floor->count_rhs = 0;
3691 tower_data += sizeof(*protocol_floor);
3693 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3694 if (!*tower_size)
3695 return EPT_S_NOT_REGISTERED;
3697 *tower_size += sizeof(*protocol_floor);
3699 return RPC_S_OK;
3702 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3703 size_t tower_size,
3704 char **protseq,
3705 char **networkaddr,
3706 char **endpoint)
3708 const twr_empty_floor_t *protocol_floor;
3709 const twr_empty_floor_t *floor4;
3710 const struct connection_ops *protseq_ops = NULL;
3711 RPC_STATUS status;
3712 unsigned int i;
3714 if (tower_size < sizeof(*protocol_floor))
3715 return EPT_S_NOT_REGISTERED;
3717 protocol_floor = (const twr_empty_floor_t *)tower_data;
3718 tower_data += sizeof(*protocol_floor);
3719 tower_size -= sizeof(*protocol_floor);
3720 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3721 (protocol_floor->count_rhs > tower_size))
3722 return EPT_S_NOT_REGISTERED;
3723 tower_data += protocol_floor->count_rhs;
3724 tower_size -= protocol_floor->count_rhs;
3726 floor4 = (const twr_empty_floor_t *)tower_data;
3727 if ((tower_size < sizeof(*floor4)) ||
3728 (floor4->count_lhs != sizeof(floor4->protid)))
3729 return EPT_S_NOT_REGISTERED;
3731 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
3732 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3733 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3735 protseq_ops = &conn_protseq_list[i];
3736 break;
3739 if (!protseq_ops)
3740 return EPT_S_NOT_REGISTERED;
3742 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3744 if ((status == RPC_S_OK) && protseq)
3746 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3747 strcpy(*protseq, protseq_ops->name);
3750 return status;
3753 /***********************************************************************
3754 * RpcNetworkIsProtseqValidW (RPCRT4.@)
3756 * Checks if the given protocol sequence is known by the RPC system.
3757 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3760 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3762 char ps[0x10];
3764 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3765 ps, sizeof ps, NULL, NULL);
3766 if (rpcrt4_get_conn_protseq_ops(ps))
3767 return RPC_S_OK;
3769 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3771 return RPC_S_INVALID_RPC_PROTSEQ;
3774 /***********************************************************************
3775 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3777 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3779 UNICODE_STRING protseqW;
3781 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3783 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3784 RtlFreeUnicodeString(&protseqW);
3785 return ret;
3787 return RPC_S_OUT_OF_MEMORY;
3790 /***********************************************************************
3791 * RpcProtseqVectorFreeA (RPCRT4.@)
3793 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
3795 TRACE("(%p)\n", protseqs);
3797 if (*protseqs)
3799 unsigned int i;
3800 for (i = 0; i < (*protseqs)->Count; i++)
3801 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3802 HeapFree(GetProcessHeap(), 0, *protseqs);
3803 *protseqs = NULL;
3805 return RPC_S_OK;
3808 /***********************************************************************
3809 * RpcProtseqVectorFreeW (RPCRT4.@)
3811 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
3813 TRACE("(%p)\n", protseqs);
3815 if (*protseqs)
3817 unsigned int i;
3818 for (i = 0; i < (*protseqs)->Count; i++)
3819 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3820 HeapFree(GetProcessHeap(), 0, *protseqs);
3821 *protseqs = NULL;
3823 return RPC_S_OK;
3826 /***********************************************************************
3827 * RpcNetworkInqProtseqsW (RPCRT4.@)
3829 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
3831 RPC_PROTSEQ_VECTORW *pvector;
3832 unsigned int i;
3833 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3835 TRACE("(%p)\n", protseqs);
3837 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAYSIZE(protseq_list)));
3838 if (!*protseqs)
3839 goto end;
3840 pvector = *protseqs;
3841 pvector->Count = 0;
3842 for (i = 0; i < ARRAYSIZE(protseq_list); i++)
3844 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
3845 if (pvector->Protseq[i] == NULL)
3846 goto end;
3847 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
3848 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
3849 pvector->Count++;
3851 status = RPC_S_OK;
3853 end:
3854 if (status != RPC_S_OK)
3855 RpcProtseqVectorFreeW(protseqs);
3856 return status;
3859 /***********************************************************************
3860 * RpcNetworkInqProtseqsA (RPCRT4.@)
3862 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
3864 RPC_PROTSEQ_VECTORA *pvector;
3865 unsigned int i;
3866 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3868 TRACE("(%p)\n", protseqs);
3870 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAYSIZE(protseq_list)));
3871 if (!*protseqs)
3872 goto end;
3873 pvector = *protseqs;
3874 pvector->Count = 0;
3875 for (i = 0; i < ARRAYSIZE(protseq_list); i++)
3877 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
3878 if (pvector->Protseq[i] == NULL)
3879 goto end;
3880 strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
3881 pvector->Count++;
3883 status = RPC_S_OK;
3885 end:
3886 if (status != RPC_S_OK)
3887 RpcProtseqVectorFreeA(protseqs);
3888 return status;