dwrite: Ignore fonts with dot-prefixed names.
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blob54cef0798010f946755d67f07fd297a819598b65
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 #if defined(__MINGW32__) || defined (_MSC_VER)
37 # include <ws2tcpip.h>
38 # ifndef EADDRINUSE
39 # define EADDRINUSE WSAEADDRINUSE
40 # endif
41 # ifndef EAGAIN
42 # define EAGAIN WSAEWOULDBLOCK
43 # endif
44 # undef errno
45 # define errno WSAGetLastError()
46 #else
47 # include <errno.h>
48 # ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 # endif
51 # include <fcntl.h>
52 # ifdef HAVE_SYS_SOCKET_H
53 # include <sys/socket.h>
54 # endif
55 # ifdef HAVE_NETINET_IN_H
56 # include <netinet/in.h>
57 # endif
58 # ifdef HAVE_NETINET_TCP_H
59 # include <netinet/tcp.h>
60 # endif
61 # ifdef HAVE_ARPA_INET_H
62 # include <arpa/inet.h>
63 # endif
64 # ifdef HAVE_NETDB_H
65 # include <netdb.h>
66 # endif
67 # ifdef HAVE_SYS_POLL_H
68 # include <sys/poll.h>
69 # endif
70 # ifdef HAVE_SYS_FILIO_H
71 # include <sys/filio.h>
72 # endif
73 # ifdef HAVE_SYS_IOCTL_H
74 # include <sys/ioctl.h>
75 # endif
76 # define closesocket close
77 # define ioctlsocket ioctl
78 #endif /* defined(__MINGW32__) || defined (_MSC_VER) */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winnls.h"
83 #include "winerror.h"
84 #include "wininet.h"
85 #include "winternl.h"
86 #include "wine/unicode.h"
88 #include "rpc.h"
89 #include "rpcndr.h"
91 #include "wine/debug.h"
93 #include "rpc_binding.h"
94 #include "rpc_assoc.h"
95 #include "rpc_message.h"
96 #include "rpc_server.h"
97 #include "epm_towers.h"
99 #ifndef SOL_TCP
100 # define SOL_TCP IPPROTO_TCP
101 #endif
103 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
105 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
107 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
109 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
111 /**** ncacn_np support ****/
113 typedef struct _RpcConnection_np
115 RpcConnection common;
116 HANDLE pipe;
117 HANDLE listen_thread;
118 BOOL listening;
119 } RpcConnection_np;
121 static RpcConnection *rpcrt4_conn_np_alloc(void)
123 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
124 return &npc->common;
127 static DWORD CALLBACK listen_thread(void *arg)
129 RpcConnection_np *npc = arg;
130 for (;;)
132 if (ConnectNamedPipe(npc->pipe, NULL))
133 return RPC_S_OK;
135 switch(GetLastError())
137 case ERROR_PIPE_CONNECTED:
138 return RPC_S_OK;
139 case ERROR_HANDLES_CLOSED:
140 /* connection closed during listen */
141 return RPC_S_NO_CONTEXT_AVAILABLE;
142 case ERROR_NO_DATA_DETECTED:
143 /* client has disconnected, retry */
144 DisconnectNamedPipe( npc->pipe );
145 break;
146 default:
147 npc->listening = FALSE;
148 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
149 return RPC_S_OUT_OF_RESOURCES;
154 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
156 if (npc->listening)
157 return RPC_S_OK;
159 npc->listening = TRUE;
160 npc->listen_thread = CreateThread(NULL, 0, listen_thread, npc, 0, NULL);
161 if (!npc->listen_thread)
163 npc->listening = FALSE;
164 ERR("Couldn't create listen thread (error was %d)\n", GetLastError());
165 return RPC_S_OUT_OF_RESOURCES;
167 return RPC_S_OK;
170 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
172 RpcConnection_np *npc = (RpcConnection_np *) Connection;
173 TRACE("listening on %s\n", pname);
175 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
176 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
177 PIPE_UNLIMITED_INSTANCES,
178 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
179 if (npc->pipe == INVALID_HANDLE_VALUE) {
180 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
181 if (GetLastError() == ERROR_FILE_EXISTS)
182 return RPC_S_DUPLICATE_ENDPOINT;
183 else
184 return RPC_S_CANT_CREATE_ENDPOINT;
187 /* Note: we don't call ConnectNamedPipe here because it must be done in the
188 * server thread as the thread must be alertable */
189 return RPC_S_OK;
192 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
194 RpcConnection_np *npc = (RpcConnection_np *) Connection;
195 HANDLE pipe;
196 DWORD err, dwMode;
198 TRACE("connecting to %s\n", pname);
200 while (TRUE) {
201 DWORD dwFlags = 0;
202 if (Connection->QOS)
204 dwFlags = SECURITY_SQOS_PRESENT;
205 switch (Connection->QOS->qos->ImpersonationType)
207 case RPC_C_IMP_LEVEL_DEFAULT:
208 /* FIXME: what to do here? */
209 break;
210 case RPC_C_IMP_LEVEL_ANONYMOUS:
211 dwFlags |= SECURITY_ANONYMOUS;
212 break;
213 case RPC_C_IMP_LEVEL_IDENTIFY:
214 dwFlags |= SECURITY_IDENTIFICATION;
215 break;
216 case RPC_C_IMP_LEVEL_IMPERSONATE:
217 dwFlags |= SECURITY_IMPERSONATION;
218 break;
219 case RPC_C_IMP_LEVEL_DELEGATE:
220 dwFlags |= SECURITY_DELEGATION;
221 break;
223 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
224 dwFlags |= SECURITY_CONTEXT_TRACKING;
226 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
227 OPEN_EXISTING, dwFlags, 0);
228 if (pipe != INVALID_HANDLE_VALUE) break;
229 err = GetLastError();
230 if (err == ERROR_PIPE_BUSY) {
231 TRACE("connection failed, error=%x\n", err);
232 return RPC_S_SERVER_TOO_BUSY;
234 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
235 err = GetLastError();
236 WARN("connection failed, error=%x\n", err);
237 return RPC_S_SERVER_UNAVAILABLE;
241 /* success */
242 /* pipe is connected; change to message-read mode. */
243 dwMode = PIPE_READMODE_MESSAGE;
244 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
245 npc->pipe = pipe;
247 return RPC_S_OK;
250 static char *ncalrpc_pipe_name(const char *endpoint)
252 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
253 char *pipe_name;
255 /* protseq=ncalrpc: supposed to use NT LPC ports,
256 * but we'll implement it with named pipes for now */
257 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
258 strcat(strcpy(pipe_name, prefix), endpoint);
259 return pipe_name;
262 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
264 RpcConnection_np *npc = (RpcConnection_np *) Connection;
265 RPC_STATUS r;
266 LPSTR pname;
268 /* already connected? */
269 if (npc->pipe)
270 return RPC_S_OK;
272 pname = ncalrpc_pipe_name(Connection->Endpoint);
273 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
274 I_RpcFree(pname);
276 return r;
279 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
281 RPC_STATUS r;
282 LPSTR pname;
283 RpcConnection *Connection;
284 char generated_endpoint[22];
286 if (!endpoint)
288 static LONG lrpc_nameless_id;
289 DWORD process_id = GetCurrentProcessId();
290 ULONG id = InterlockedIncrement(&lrpc_nameless_id);
291 snprintf(generated_endpoint, sizeof(generated_endpoint),
292 "LRPC%08x.%08x", process_id, id);
293 endpoint = generated_endpoint;
296 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
297 endpoint, NULL, NULL, NULL, NULL);
298 if (r != RPC_S_OK)
299 return r;
301 pname = ncalrpc_pipe_name(Connection->Endpoint);
302 r = rpcrt4_conn_create_pipe(Connection, pname);
303 I_RpcFree(pname);
305 EnterCriticalSection(&protseq->cs);
306 Connection->Next = protseq->conn;
307 protseq->conn = Connection;
308 LeaveCriticalSection(&protseq->cs);
310 return r;
313 static char *ncacn_pipe_name(const char *endpoint)
315 static const char prefix[] = "\\\\.";
316 char *pipe_name;
318 /* protseq=ncacn_np: named pipes */
319 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
320 strcat(strcpy(pipe_name, prefix), endpoint);
321 return pipe_name;
324 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
326 RpcConnection_np *npc = (RpcConnection_np *) Connection;
327 RPC_STATUS r;
328 LPSTR pname;
330 /* already connected? */
331 if (npc->pipe)
332 return RPC_S_OK;
334 pname = ncacn_pipe_name(Connection->Endpoint);
335 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
336 I_RpcFree(pname);
338 return r;
341 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
343 RPC_STATUS r;
344 LPSTR pname;
345 RpcConnection *Connection;
346 char generated_endpoint[21];
348 if (!endpoint)
350 static LONG np_nameless_id;
351 DWORD process_id = GetCurrentProcessId();
352 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
353 snprintf(generated_endpoint, sizeof(generated_endpoint),
354 "\\\\pipe\\\\%08x.%03x", process_id, id);
355 endpoint = generated_endpoint;
358 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
359 endpoint, NULL, NULL, NULL, NULL);
360 if (r != RPC_S_OK)
361 return r;
363 pname = ncacn_pipe_name(Connection->Endpoint);
364 r = rpcrt4_conn_create_pipe(Connection, pname);
365 I_RpcFree(pname);
367 EnterCriticalSection(&protseq->cs);
368 Connection->Next = protseq->conn;
369 protseq->conn = Connection;
370 LeaveCriticalSection(&protseq->cs);
372 return r;
375 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
377 /* because of the way named pipes work, we'll transfer the connected pipe
378 * to the child, then reopen the server binding to continue listening */
380 new_npc->pipe = old_npc->pipe;
381 new_npc->listen_thread = old_npc->listen_thread;
382 old_npc->pipe = 0;
383 old_npc->listen_thread = 0;
384 old_npc->listening = FALSE;
387 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
389 RPC_STATUS status;
390 LPSTR pname;
392 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
394 pname = ncacn_pipe_name(old_conn->Endpoint);
395 status = rpcrt4_conn_create_pipe(old_conn, pname);
396 I_RpcFree(pname);
398 return status;
401 static RPC_STATUS is_pipe_listening(const char *pipe_name)
403 return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING;
406 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint)
408 char *pipe_name;
409 RPC_STATUS status;
411 pipe_name = ncacn_pipe_name(endpoint);
412 status = is_pipe_listening(pipe_name);
413 I_RpcFree(pipe_name);
414 return status;
417 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint)
419 char *pipe_name;
420 RPC_STATUS status;
422 pipe_name = ncalrpc_pipe_name(endpoint);
423 status = is_pipe_listening(pipe_name);
424 I_RpcFree(pipe_name);
425 return status;
428 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
430 RPC_STATUS status;
431 LPSTR pname;
433 TRACE("%s\n", old_conn->Endpoint);
435 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
437 pname = ncalrpc_pipe_name(old_conn->Endpoint);
438 status = rpcrt4_conn_create_pipe(old_conn, pname);
439 I_RpcFree(pname);
441 return status;
444 static int rpcrt4_conn_np_read(RpcConnection *Connection,
445 void *buffer, unsigned int count)
447 RpcConnection_np *npc = (RpcConnection_np *) Connection;
448 char *buf = buffer;
449 BOOL ret = TRUE;
450 unsigned int bytes_left = count;
452 while (bytes_left)
454 DWORD bytes_read;
455 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
456 if (!ret && GetLastError() == ERROR_MORE_DATA)
457 ret = TRUE;
458 if (!ret || !bytes_read)
459 break;
460 bytes_left -= bytes_read;
461 buf += bytes_read;
463 return ret ? count : -1;
466 static int rpcrt4_conn_np_write(RpcConnection *Connection,
467 const void *buffer, unsigned int count)
469 RpcConnection_np *npc = (RpcConnection_np *) Connection;
470 const char *buf = buffer;
471 BOOL ret = TRUE;
472 unsigned int bytes_left = count;
474 while (bytes_left)
476 DWORD bytes_written;
477 ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, NULL);
478 if (!ret || !bytes_written)
479 break;
480 bytes_left -= bytes_written;
481 buf += bytes_written;
483 return ret ? count : -1;
486 static int rpcrt4_conn_np_close(RpcConnection *Connection)
488 RpcConnection_np *npc = (RpcConnection_np *) Connection;
489 if (npc->pipe) {
490 FlushFileBuffers(npc->pipe);
491 CloseHandle(npc->pipe);
492 npc->pipe = 0;
494 if (npc->listen_thread) {
495 CloseHandle(npc->listen_thread);
496 npc->listen_thread = 0;
498 return 0;
501 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
503 /* FIXME: implement when named pipe writes use overlapped I/O */
506 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
508 /* FIXME: implement when named pipe writes use overlapped I/O */
509 return -1;
512 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
513 const char *networkaddr,
514 const char *endpoint)
516 twr_empty_floor_t *smb_floor;
517 twr_empty_floor_t *nb_floor;
518 size_t size;
519 size_t networkaddr_size;
520 size_t endpoint_size;
522 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
524 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
525 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
526 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
528 if (!tower_data)
529 return size;
531 smb_floor = (twr_empty_floor_t *)tower_data;
533 tower_data += sizeof(*smb_floor);
535 smb_floor->count_lhs = sizeof(smb_floor->protid);
536 smb_floor->protid = EPM_PROTOCOL_SMB;
537 smb_floor->count_rhs = endpoint_size;
539 if (endpoint)
540 memcpy(tower_data, endpoint, endpoint_size);
541 else
542 tower_data[0] = 0;
543 tower_data += endpoint_size;
545 nb_floor = (twr_empty_floor_t *)tower_data;
547 tower_data += sizeof(*nb_floor);
549 nb_floor->count_lhs = sizeof(nb_floor->protid);
550 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
551 nb_floor->count_rhs = networkaddr_size;
553 if (networkaddr)
554 memcpy(tower_data, networkaddr, networkaddr_size);
555 else
556 tower_data[0] = 0;
558 return size;
561 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
562 size_t tower_size,
563 char **networkaddr,
564 char **endpoint)
566 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
567 const twr_empty_floor_t *nb_floor;
569 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
571 if (tower_size < sizeof(*smb_floor))
572 return EPT_S_NOT_REGISTERED;
574 tower_data += sizeof(*smb_floor);
575 tower_size -= sizeof(*smb_floor);
577 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
578 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
579 (smb_floor->count_rhs > tower_size) ||
580 (tower_data[smb_floor->count_rhs - 1] != '\0'))
581 return EPT_S_NOT_REGISTERED;
583 if (endpoint)
585 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
586 if (!*endpoint)
587 return RPC_S_OUT_OF_RESOURCES;
588 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
590 tower_data += smb_floor->count_rhs;
591 tower_size -= smb_floor->count_rhs;
593 if (tower_size < sizeof(*nb_floor))
594 return EPT_S_NOT_REGISTERED;
596 nb_floor = (const twr_empty_floor_t *)tower_data;
598 tower_data += sizeof(*nb_floor);
599 tower_size -= sizeof(*nb_floor);
601 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
602 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
603 (nb_floor->count_rhs > tower_size) ||
604 (tower_data[nb_floor->count_rhs - 1] != '\0'))
605 return EPT_S_NOT_REGISTERED;
607 if (networkaddr)
609 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
610 if (!*networkaddr)
612 if (endpoint)
614 I_RpcFree(*endpoint);
615 *endpoint = NULL;
617 return RPC_S_OUT_OF_RESOURCES;
619 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
622 return RPC_S_OK;
625 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
627 RpcConnection_np *npc = (RpcConnection_np *)conn;
628 BOOL ret;
630 TRACE("(%p)\n", conn);
632 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
633 return RPCRT4_default_impersonate_client(conn);
635 ret = ImpersonateNamedPipeClient(npc->pipe);
636 if (!ret)
638 DWORD error = GetLastError();
639 WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
640 switch (error)
642 case ERROR_CANNOT_IMPERSONATE:
643 return RPC_S_NO_CONTEXT_AVAILABLE;
646 return RPC_S_OK;
649 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
651 BOOL ret;
653 TRACE("(%p)\n", conn);
655 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
656 return RPCRT4_default_revert_to_self(conn);
658 ret = RevertToSelf();
659 if (!ret)
661 WARN("RevertToSelf failed with error %u\n", GetLastError());
662 return RPC_S_NO_CONTEXT_AVAILABLE;
664 return RPC_S_OK;
667 typedef struct _RpcServerProtseq_np
669 RpcServerProtseq common;
670 HANDLE mgr_event;
671 } RpcServerProtseq_np;
673 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
675 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
676 if (ps)
677 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
678 return &ps->common;
681 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
683 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
684 SetEvent(npps->mgr_event);
687 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
689 HANDLE *objs = prev_array;
690 RpcConnection_np *conn;
691 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
693 EnterCriticalSection(&protseq->cs);
695 /* open and count connections */
696 *count = 1;
697 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
698 while (conn) {
699 rpcrt4_conn_listen_pipe(conn);
700 if (conn->listen_thread)
701 (*count)++;
702 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
705 /* make array of connections */
706 if (objs)
707 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
708 else
709 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
710 if (!objs)
712 ERR("couldn't allocate objs\n");
713 LeaveCriticalSection(&protseq->cs);
714 return NULL;
717 objs[0] = npps->mgr_event;
718 *count = 1;
719 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
720 while (conn) {
721 if ((objs[*count] = conn->listen_thread))
722 (*count)++;
723 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
725 LeaveCriticalSection(&protseq->cs);
726 return objs;
729 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
731 HeapFree(GetProcessHeap(), 0, array);
734 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
736 HANDLE b_handle;
737 HANDLE *objs = wait_array;
738 DWORD res;
739 RpcConnection *cconn;
740 RpcConnection_np *conn;
742 if (!objs)
743 return -1;
747 /* an alertable wait isn't strictly necessary, but due to our
748 * overlapped I/O implementation in Wine we need to free some memory
749 * by the file user APC being called, even if no completion routine was
750 * specified at the time of starting the async operation */
751 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
752 } while (res == WAIT_IO_COMPLETION);
754 if (res == WAIT_OBJECT_0)
755 return 0;
756 else if (res == WAIT_FAILED)
758 ERR("wait failed with error %d\n", GetLastError());
759 return -1;
761 else
763 b_handle = objs[res - WAIT_OBJECT_0];
764 /* find which connection got a RPC */
765 EnterCriticalSection(&protseq->cs);
766 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
767 while (conn) {
768 if (b_handle == conn->listen_thread) break;
769 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
771 cconn = NULL;
772 if (conn)
774 DWORD exit_code;
775 if (GetExitCodeThread(conn->listen_thread, &exit_code) && exit_code == RPC_S_OK)
776 RPCRT4_SpawnConnection(&cconn, &conn->common);
777 CloseHandle(conn->listen_thread);
778 conn->listen_thread = 0;
780 else
781 ERR("failed to locate connection for handle %p\n", b_handle);
782 LeaveCriticalSection(&protseq->cs);
783 if (cconn)
785 RPCRT4_new_client(cconn);
786 return 1;
788 else return -1;
792 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
793 const char *networkaddr,
794 const char *endpoint)
796 twr_empty_floor_t *pipe_floor;
797 size_t size;
798 size_t endpoint_size;
800 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
802 endpoint_size = strlen(endpoint) + 1;
803 size = sizeof(*pipe_floor) + endpoint_size;
805 if (!tower_data)
806 return size;
808 pipe_floor = (twr_empty_floor_t *)tower_data;
810 tower_data += sizeof(*pipe_floor);
812 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
813 pipe_floor->protid = EPM_PROTOCOL_PIPE;
814 pipe_floor->count_rhs = endpoint_size;
816 memcpy(tower_data, endpoint, endpoint_size);
818 return size;
821 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
822 size_t tower_size,
823 char **networkaddr,
824 char **endpoint)
826 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
828 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
830 if (tower_size < sizeof(*pipe_floor))
831 return EPT_S_NOT_REGISTERED;
833 tower_data += sizeof(*pipe_floor);
834 tower_size -= sizeof(*pipe_floor);
836 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
837 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
838 (pipe_floor->count_rhs > tower_size) ||
839 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
840 return EPT_S_NOT_REGISTERED;
842 if (networkaddr)
843 *networkaddr = NULL;
845 if (endpoint)
847 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
848 if (!*endpoint)
849 return RPC_S_OUT_OF_RESOURCES;
850 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
853 return RPC_S_OK;
856 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
858 return FALSE;
861 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
862 unsigned char *in_buffer,
863 unsigned int in_size,
864 unsigned char *out_buffer,
865 unsigned int *out_size)
867 /* since this protocol is local to the machine there is no need to
868 * authenticate the caller */
869 *out_size = 0;
870 return RPC_S_OK;
873 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
874 enum secure_packet_direction dir,
875 RpcPktHdr *hdr, unsigned int hdr_size,
876 unsigned char *stub_data, unsigned int stub_data_size,
877 RpcAuthVerifier *auth_hdr,
878 unsigned char *auth_value, unsigned int auth_value_size)
880 /* since this protocol is local to the machine there is no need to secure
881 * the packet */
882 return RPC_S_OK;
885 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
886 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
887 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
889 TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
890 server_princ_name, authn_level, authn_svc, authz_svc, flags);
892 if (privs)
894 FIXME("privs not implemented\n");
895 *privs = NULL;
897 if (server_princ_name)
899 FIXME("server_princ_name not implemented\n");
900 *server_princ_name = NULL;
902 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
903 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
904 if (authz_svc)
906 FIXME("authorization service not implemented\n");
907 *authz_svc = RPC_C_AUTHZ_NONE;
909 if (flags)
910 FIXME("flags 0x%x not implemented\n", flags);
912 return RPC_S_OK;
915 /**** ncacn_ip_tcp support ****/
917 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
918 const char *networkaddr,
919 unsigned char tcp_protid,
920 const char *endpoint)
922 twr_tcp_floor_t *tcp_floor;
923 twr_ipv4_floor_t *ipv4_floor;
924 struct addrinfo *ai;
925 struct addrinfo hints;
926 int ret;
927 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
929 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
931 if (!tower_data)
932 return size;
934 tcp_floor = (twr_tcp_floor_t *)tower_data;
935 tower_data += sizeof(*tcp_floor);
937 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
939 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
940 tcp_floor->protid = tcp_protid;
941 tcp_floor->count_rhs = sizeof(tcp_floor->port);
943 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
944 ipv4_floor->protid = EPM_PROTOCOL_IP;
945 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
947 hints.ai_flags = AI_NUMERICHOST;
948 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
949 hints.ai_family = PF_INET;
950 hints.ai_socktype = SOCK_STREAM;
951 hints.ai_protocol = IPPROTO_TCP;
952 hints.ai_addrlen = 0;
953 hints.ai_addr = NULL;
954 hints.ai_canonname = NULL;
955 hints.ai_next = NULL;
957 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
958 if (ret)
960 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
961 if (ret)
963 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
964 return 0;
968 if (ai->ai_family == PF_INET)
970 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
971 tcp_floor->port = sin->sin_port;
972 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
974 else
976 ERR("unexpected protocol family %d\n", ai->ai_family);
977 freeaddrinfo(ai);
978 return 0;
981 freeaddrinfo(ai);
983 return size;
986 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
987 size_t tower_size,
988 char **networkaddr,
989 unsigned char tcp_protid,
990 char **endpoint)
992 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
993 const twr_ipv4_floor_t *ipv4_floor;
994 struct in_addr in_addr;
996 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
998 if (tower_size < sizeof(*tcp_floor))
999 return EPT_S_NOT_REGISTERED;
1001 tower_data += sizeof(*tcp_floor);
1002 tower_size -= sizeof(*tcp_floor);
1004 if (tower_size < sizeof(*ipv4_floor))
1005 return EPT_S_NOT_REGISTERED;
1007 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1009 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1010 (tcp_floor->protid != tcp_protid) ||
1011 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1012 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1013 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1014 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1015 return EPT_S_NOT_REGISTERED;
1017 if (endpoint)
1019 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1020 if (!*endpoint)
1021 return RPC_S_OUT_OF_RESOURCES;
1022 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1025 if (networkaddr)
1027 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1028 if (!*networkaddr)
1030 if (endpoint)
1032 I_RpcFree(*endpoint);
1033 *endpoint = NULL;
1035 return RPC_S_OUT_OF_RESOURCES;
1037 in_addr.s_addr = ipv4_floor->ipv4addr;
1038 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1040 ERR("inet_ntop: %s\n", strerror(errno));
1041 I_RpcFree(*networkaddr);
1042 *networkaddr = NULL;
1043 if (endpoint)
1045 I_RpcFree(*endpoint);
1046 *endpoint = NULL;
1048 return EPT_S_NOT_REGISTERED;
1052 return RPC_S_OK;
1055 typedef struct _RpcConnection_tcp
1057 RpcConnection common;
1058 int sock;
1059 #ifdef HAVE_SOCKETPAIR
1060 int cancel_fds[2];
1061 #else
1062 HANDLE sock_event;
1063 HANDLE cancel_event;
1064 #endif
1065 } RpcConnection_tcp;
1067 #ifdef HAVE_SOCKETPAIR
1069 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1071 if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
1073 ERR("socketpair() failed: %s\n", strerror(errno));
1074 return FALSE;
1076 return TRUE;
1079 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1081 struct pollfd pfds[2];
1082 pfds[0].fd = tcpc->sock;
1083 pfds[0].events = POLLIN;
1084 pfds[1].fd = tcpc->cancel_fds[0];
1085 pfds[1].events = POLLIN;
1086 if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
1088 ERR("poll() failed: %s\n", strerror(errno));
1089 return FALSE;
1091 if (pfds[1].revents & POLLIN) /* canceled */
1093 char dummy;
1094 read(pfds[1].fd, &dummy, sizeof(dummy));
1095 return FALSE;
1097 return TRUE;
1100 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1102 struct pollfd pfd;
1103 pfd.fd = tcpc->sock;
1104 pfd.events = POLLOUT;
1105 if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
1107 ERR("poll() failed: %s\n", strerror(errno));
1108 return FALSE;
1110 return TRUE;
1113 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1115 char dummy = 1;
1117 write(tcpc->cancel_fds[1], &dummy, 1);
1120 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1122 close(tcpc->cancel_fds[0]);
1123 close(tcpc->cancel_fds[1]);
1126 #else /* HAVE_SOCKETPAIR */
1128 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1130 static BOOL wsa_inited;
1131 if (!wsa_inited)
1133 WSADATA wsadata;
1134 WSAStartup(MAKEWORD(2, 2), &wsadata);
1135 /* Note: WSAStartup can be called more than once so we don't bother with
1136 * making accesses to wsa_inited thread-safe */
1137 wsa_inited = TRUE;
1139 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1140 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1141 if (!tcpc->sock_event || !tcpc->cancel_event)
1143 ERR("event creation failed\n");
1144 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1145 return FALSE;
1147 return TRUE;
1150 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1152 HANDLE wait_handles[2];
1153 DWORD res;
1154 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1156 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1157 return FALSE;
1159 wait_handles[0] = tcpc->sock_event;
1160 wait_handles[1] = tcpc->cancel_event;
1161 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1162 switch (res)
1164 case WAIT_OBJECT_0:
1165 return TRUE;
1166 case WAIT_OBJECT_0 + 1:
1167 return FALSE;
1168 default:
1169 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1170 return FALSE;
1174 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1176 DWORD res;
1177 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1179 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1180 return FALSE;
1182 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1183 switch (res)
1185 case WAIT_OBJECT_0:
1186 return TRUE;
1187 default:
1188 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1189 return FALSE;
1193 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1195 SetEvent(tcpc->cancel_event);
1198 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1200 CloseHandle(tcpc->sock_event);
1201 CloseHandle(tcpc->cancel_event);
1204 #endif
1206 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1208 RpcConnection_tcp *tcpc;
1209 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
1210 if (tcpc == NULL)
1211 return NULL;
1212 tcpc->sock = -1;
1213 if (!rpcrt4_sock_wait_init(tcpc))
1215 HeapFree(GetProcessHeap(), 0, tcpc);
1216 return NULL;
1218 return &tcpc->common;
1221 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1223 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1224 int sock;
1225 int ret;
1226 struct addrinfo *ai;
1227 struct addrinfo *ai_cur;
1228 struct addrinfo hints;
1230 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1232 if (tcpc->sock != -1)
1233 return RPC_S_OK;
1235 hints.ai_flags = 0;
1236 hints.ai_family = PF_UNSPEC;
1237 hints.ai_socktype = SOCK_STREAM;
1238 hints.ai_protocol = IPPROTO_TCP;
1239 hints.ai_addrlen = 0;
1240 hints.ai_addr = NULL;
1241 hints.ai_canonname = NULL;
1242 hints.ai_next = NULL;
1244 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1245 if (ret)
1247 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1248 Connection->Endpoint, gai_strerror(ret));
1249 return RPC_S_SERVER_UNAVAILABLE;
1252 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1254 int val;
1255 u_long nonblocking;
1257 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1259 TRACE("skipping non-IP/IPv6 address family\n");
1260 continue;
1263 if (TRACE_ON(rpc))
1265 char host[256];
1266 char service[256];
1267 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1268 host, sizeof(host), service, sizeof(service),
1269 NI_NUMERICHOST | NI_NUMERICSERV);
1270 TRACE("trying %s:%s\n", host, service);
1273 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1274 if (sock == -1)
1276 WARN("socket() failed: %s\n", strerror(errno));
1277 continue;
1280 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1282 WARN("connect() failed: %s\n", strerror(errno));
1283 closesocket(sock);
1284 continue;
1287 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1288 val = 1;
1289 setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1290 nonblocking = 1;
1291 ioctlsocket(sock, FIONBIO, &nonblocking);
1293 tcpc->sock = sock;
1295 freeaddrinfo(ai);
1296 TRACE("connected\n");
1297 return RPC_S_OK;
1300 freeaddrinfo(ai);
1301 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1302 return RPC_S_SERVER_UNAVAILABLE;
1305 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1307 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1308 int sock;
1309 int ret;
1310 struct addrinfo *ai;
1311 struct addrinfo *ai_cur;
1312 struct addrinfo hints;
1313 RpcConnection *first_connection = NULL;
1315 TRACE("(%p, %s)\n", protseq, endpoint);
1317 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1318 hints.ai_family = PF_UNSPEC;
1319 hints.ai_socktype = SOCK_STREAM;
1320 hints.ai_protocol = IPPROTO_TCP;
1321 hints.ai_addrlen = 0;
1322 hints.ai_addr = NULL;
1323 hints.ai_canonname = NULL;
1324 hints.ai_next = NULL;
1326 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1327 if (ret)
1329 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1330 gai_strerror(ret));
1331 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1332 return RPC_S_INVALID_ENDPOINT_FORMAT;
1333 return RPC_S_CANT_CREATE_ENDPOINT;
1336 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1338 RpcConnection_tcp *tcpc;
1339 RPC_STATUS create_status;
1340 struct sockaddr_storage sa;
1341 socklen_t sa_len;
1342 char service[NI_MAXSERV];
1343 u_long nonblocking;
1345 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1347 TRACE("skipping non-IP/IPv6 address family\n");
1348 continue;
1351 if (TRACE_ON(rpc))
1353 char host[256];
1354 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1355 host, sizeof(host), service, sizeof(service),
1356 NI_NUMERICHOST | NI_NUMERICSERV);
1357 TRACE("trying %s:%s\n", host, service);
1360 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1361 if (sock == -1)
1363 WARN("socket() failed: %s\n", strerror(errno));
1364 status = RPC_S_CANT_CREATE_ENDPOINT;
1365 continue;
1368 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1369 if (ret < 0)
1371 WARN("bind failed: %s\n", strerror(errno));
1372 closesocket(sock);
1373 if (errno == EADDRINUSE)
1374 status = RPC_S_DUPLICATE_ENDPOINT;
1375 else
1376 status = RPC_S_CANT_CREATE_ENDPOINT;
1377 continue;
1380 sa_len = sizeof(sa);
1381 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1383 WARN("getsockname() failed: %s\n", strerror(errno));
1384 closesocket(sock);
1385 status = RPC_S_CANT_CREATE_ENDPOINT;
1386 continue;
1389 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1390 NULL, 0, service, sizeof(service),
1391 NI_NUMERICSERV);
1392 if (ret)
1394 WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1395 closesocket(sock);
1396 status = RPC_S_CANT_CREATE_ENDPOINT;
1397 continue;
1400 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1401 protseq->Protseq, NULL,
1402 service, NULL, NULL, NULL, NULL);
1403 if (create_status != RPC_S_OK)
1405 closesocket(sock);
1406 status = create_status;
1407 continue;
1410 tcpc->sock = sock;
1411 ret = listen(sock, protseq->MaxCalls);
1412 if (ret < 0)
1414 WARN("listen failed: %s\n", strerror(errno));
1415 RPCRT4_ReleaseConnection(&tcpc->common);
1416 status = RPC_S_OUT_OF_RESOURCES;
1417 continue;
1419 /* need a non-blocking socket, otherwise accept() has a potential
1420 * race-condition (poll() says it is readable, connection drops,
1421 * and accept() blocks until the next connection comes...)
1423 nonblocking = 1;
1424 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1425 if (ret < 0)
1427 WARN("couldn't make socket non-blocking, error %d\n", ret);
1428 RPCRT4_ReleaseConnection(&tcpc->common);
1429 status = RPC_S_OUT_OF_RESOURCES;
1430 continue;
1433 tcpc->common.Next = first_connection;
1434 first_connection = &tcpc->common;
1436 /* since IPv4 and IPv6 share the same port space, we only need one
1437 * successful bind to listen for both */
1438 break;
1441 freeaddrinfo(ai);
1443 /* if at least one connection was created for an endpoint then
1444 * return success */
1445 if (first_connection)
1447 RpcConnection *conn;
1449 /* find last element in list */
1450 for (conn = first_connection; conn->Next; conn = conn->Next)
1453 EnterCriticalSection(&protseq->cs);
1454 conn->Next = protseq->conn;
1455 protseq->conn = first_connection;
1456 LeaveCriticalSection(&protseq->cs);
1458 TRACE("listening on %s\n", endpoint);
1459 return RPC_S_OK;
1462 ERR("couldn't listen on port %s\n", endpoint);
1463 return status;
1466 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1468 int ret;
1469 struct sockaddr_in address;
1470 socklen_t addrsize;
1471 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1472 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1473 u_long nonblocking;
1475 addrsize = sizeof(address);
1476 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1477 if (ret < 0)
1479 ERR("Failed to accept a TCP connection: error %d\n", ret);
1480 return RPC_S_OUT_OF_RESOURCES;
1482 nonblocking = 1;
1483 ioctlsocket(ret, FIONBIO, &nonblocking);
1484 client->sock = ret;
1485 TRACE("Accepted a new TCP connection\n");
1486 return RPC_S_OK;
1489 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1490 void *buffer, unsigned int count)
1492 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1493 int bytes_read = 0;
1494 while (bytes_read != count)
1496 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1497 if (!r)
1498 return -1;
1499 else if (r > 0)
1500 bytes_read += r;
1501 else if (errno == EINTR)
1502 continue;
1503 else if (errno != EAGAIN)
1505 WARN("recv() failed: %s\n", strerror(errno));
1506 return -1;
1508 else
1510 if (!rpcrt4_sock_wait_for_recv(tcpc))
1511 return -1;
1514 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1515 return bytes_read;
1518 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1519 const void *buffer, unsigned int count)
1521 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1522 int bytes_written = 0;
1523 while (bytes_written != count)
1525 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1526 if (r >= 0)
1527 bytes_written += r;
1528 else if (errno == EINTR)
1529 continue;
1530 else if (errno != EAGAIN)
1531 return -1;
1532 else
1534 if (!rpcrt4_sock_wait_for_send(tcpc))
1535 return -1;
1538 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1539 return bytes_written;
1542 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1544 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1546 TRACE("%d\n", tcpc->sock);
1548 if (tcpc->sock != -1)
1549 closesocket(tcpc->sock);
1550 tcpc->sock = -1;
1551 rpcrt4_sock_wait_destroy(tcpc);
1552 return 0;
1555 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1557 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1558 TRACE("%p\n", Connection);
1559 rpcrt4_sock_wait_cancel(tcpc);
1562 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint)
1564 FIXME("\n");
1565 return RPC_S_ACCESS_DENIED;
1568 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1570 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1572 TRACE("%p\n", Connection);
1574 if (!rpcrt4_sock_wait_for_recv(tcpc))
1575 return -1;
1576 return 0;
1579 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1580 const char *networkaddr,
1581 const char *endpoint)
1583 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1584 EPM_PROTOCOL_TCP, endpoint);
1587 #ifdef HAVE_SOCKETPAIR
1589 typedef struct _RpcServerProtseq_sock
1591 RpcServerProtseq common;
1592 int mgr_event_rcv;
1593 int mgr_event_snd;
1594 } RpcServerProtseq_sock;
1596 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1598 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1599 if (ps)
1601 int fds[2];
1602 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1604 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1605 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1606 ps->mgr_event_rcv = fds[0];
1607 ps->mgr_event_snd = fds[1];
1609 else
1611 ERR("socketpair failed with error %s\n", strerror(errno));
1612 HeapFree(GetProcessHeap(), 0, ps);
1613 return NULL;
1616 return &ps->common;
1619 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1621 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1622 char dummy = 1;
1623 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1626 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1628 struct pollfd *poll_info = prev_array;
1629 RpcConnection_tcp *conn;
1630 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1632 EnterCriticalSection(&protseq->cs);
1634 /* open and count connections */
1635 *count = 1;
1636 conn = (RpcConnection_tcp *)protseq->conn;
1637 while (conn) {
1638 if (conn->sock != -1)
1639 (*count)++;
1640 conn = (RpcConnection_tcp *)conn->common.Next;
1643 /* make array of connections */
1644 if (poll_info)
1645 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1646 else
1647 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1648 if (!poll_info)
1650 ERR("couldn't allocate poll_info\n");
1651 LeaveCriticalSection(&protseq->cs);
1652 return NULL;
1655 poll_info[0].fd = sockps->mgr_event_rcv;
1656 poll_info[0].events = POLLIN;
1657 *count = 1;
1658 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1659 while (conn) {
1660 if (conn->sock != -1)
1662 poll_info[*count].fd = conn->sock;
1663 poll_info[*count].events = POLLIN;
1664 (*count)++;
1666 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1668 LeaveCriticalSection(&protseq->cs);
1669 return poll_info;
1672 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1674 HeapFree(GetProcessHeap(), 0, array);
1677 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1679 struct pollfd *poll_info = wait_array;
1680 int ret;
1681 unsigned int i;
1682 RpcConnection *cconn;
1683 RpcConnection_tcp *conn;
1685 if (!poll_info)
1686 return -1;
1688 ret = poll(poll_info, count, -1);
1689 if (ret < 0)
1691 ERR("poll failed with error %d\n", ret);
1692 return -1;
1695 for (i = 0; i < count; i++)
1696 if (poll_info[i].revents & POLLIN)
1698 /* RPC server event */
1699 if (i == 0)
1701 char dummy;
1702 read(poll_info[0].fd, &dummy, sizeof(dummy));
1703 return 0;
1706 /* find which connection got a RPC */
1707 EnterCriticalSection(&protseq->cs);
1708 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1709 while (conn) {
1710 if (poll_info[i].fd == conn->sock) break;
1711 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1713 cconn = NULL;
1714 if (conn)
1715 RPCRT4_SpawnConnection(&cconn, &conn->common);
1716 else
1717 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1718 LeaveCriticalSection(&protseq->cs);
1719 if (cconn)
1720 RPCRT4_new_client(cconn);
1721 else
1722 return -1;
1725 return 1;
1728 #else /* HAVE_SOCKETPAIR */
1730 typedef struct _RpcServerProtseq_sock
1732 RpcServerProtseq common;
1733 HANDLE mgr_event;
1734 } RpcServerProtseq_sock;
1736 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1738 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1739 if (ps)
1741 static BOOL wsa_inited;
1742 if (!wsa_inited)
1744 WSADATA wsadata;
1745 WSAStartup(MAKEWORD(2, 2), &wsadata);
1746 /* Note: WSAStartup can be called more than once so we don't bother with
1747 * making accesses to wsa_inited thread-safe */
1748 wsa_inited = TRUE;
1750 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1752 return &ps->common;
1755 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1757 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1758 SetEvent(sockps->mgr_event);
1761 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1763 HANDLE *objs = prev_array;
1764 RpcConnection_tcp *conn;
1765 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1767 EnterCriticalSection(&protseq->cs);
1769 /* open and count connections */
1770 *count = 1;
1771 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1772 while (conn)
1774 if (conn->sock != -1)
1775 (*count)++;
1776 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1779 /* make array of connections */
1780 if (objs)
1781 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1782 else
1783 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1784 if (!objs)
1786 ERR("couldn't allocate objs\n");
1787 LeaveCriticalSection(&protseq->cs);
1788 return NULL;
1791 objs[0] = sockps->mgr_event;
1792 *count = 1;
1793 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1794 while (conn)
1796 if (conn->sock != -1)
1798 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1799 if (res == SOCKET_ERROR)
1800 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1801 else
1803 objs[*count] = conn->sock_event;
1804 (*count)++;
1807 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1809 LeaveCriticalSection(&protseq->cs);
1810 return objs;
1813 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1815 HeapFree(GetProcessHeap(), 0, array);
1818 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1820 HANDLE b_handle;
1821 HANDLE *objs = wait_array;
1822 DWORD res;
1823 RpcConnection *cconn;
1824 RpcConnection_tcp *conn;
1826 if (!objs)
1827 return -1;
1831 /* an alertable wait isn't strictly necessary, but due to our
1832 * overlapped I/O implementation in Wine we need to free some memory
1833 * by the file user APC being called, even if no completion routine was
1834 * specified at the time of starting the async operation */
1835 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1836 } while (res == WAIT_IO_COMPLETION);
1838 if (res == WAIT_OBJECT_0)
1839 return 0;
1840 else if (res == WAIT_FAILED)
1842 ERR("wait failed with error %d\n", GetLastError());
1843 return -1;
1845 else
1847 b_handle = objs[res - WAIT_OBJECT_0];
1848 /* find which connection got a RPC */
1849 EnterCriticalSection(&protseq->cs);
1850 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1851 while (conn)
1853 if (b_handle == conn->sock_event) break;
1854 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1856 cconn = NULL;
1857 if (conn)
1858 RPCRT4_SpawnConnection(&cconn, &conn->common);
1859 else
1860 ERR("failed to locate connection for handle %p\n", b_handle);
1861 LeaveCriticalSection(&protseq->cs);
1862 if (cconn)
1864 RPCRT4_new_client(cconn);
1865 return 1;
1867 else return -1;
1871 #endif /* HAVE_SOCKETPAIR */
1873 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1874 size_t tower_size,
1875 char **networkaddr,
1876 char **endpoint)
1878 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1879 networkaddr, EPM_PROTOCOL_TCP,
1880 endpoint);
1883 /**** ncacn_http support ****/
1885 /* 60 seconds is the period native uses */
1886 #define HTTP_IDLE_TIME 60000
1888 /* reference counted to avoid a race between a cancelled call's connection
1889 * being destroyed and the asynchronous InternetReadFileEx call being
1890 * completed */
1891 typedef struct _RpcHttpAsyncData
1893 LONG refs;
1894 HANDLE completion_event;
1895 WORD async_result;
1896 INTERNET_BUFFERSW inet_buffers;
1897 CRITICAL_SECTION cs;
1898 } RpcHttpAsyncData;
1900 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1902 return InterlockedIncrement(&data->refs);
1905 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1907 ULONG refs = InterlockedDecrement(&data->refs);
1908 if (!refs)
1910 TRACE("destroying async data %p\n", data);
1911 CloseHandle(data->completion_event);
1912 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1913 data->cs.DebugInfo->Spare[0] = 0;
1914 DeleteCriticalSection(&data->cs);
1915 HeapFree(GetProcessHeap(), 0, data);
1917 return refs;
1920 static void prepare_async_request(RpcHttpAsyncData *async_data)
1922 ResetEvent(async_data->completion_event);
1923 RpcHttpAsyncData_AddRef(async_data);
1926 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event)
1928 HANDLE handles[2] = { async_data->completion_event, cancel_event };
1929 DWORD res;
1931 if(call_ret) {
1932 RpcHttpAsyncData_Release(async_data);
1933 return RPC_S_OK;
1936 if(GetLastError() != ERROR_IO_PENDING) {
1937 RpcHttpAsyncData_Release(async_data);
1938 ERR("Request failed with error %d\n", GetLastError());
1939 return RPC_S_SERVER_UNAVAILABLE;
1942 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
1943 if(res != WAIT_OBJECT_0) {
1944 TRACE("Cancelled\n");
1945 return RPC_S_CALL_CANCELLED;
1948 if(async_data->async_result) {
1949 ERR("Async request failed with error %d\n", async_data->async_result);
1950 return RPC_S_SERVER_UNAVAILABLE;
1953 return RPC_S_OK;
1956 struct authinfo
1958 DWORD scheme;
1959 CredHandle cred;
1960 CtxtHandle ctx;
1961 TimeStamp exp;
1962 ULONG attr;
1963 ULONG max_token;
1964 char *data;
1965 unsigned int data_len;
1966 BOOL finished; /* finished authenticating */
1969 typedef struct _RpcConnection_http
1971 RpcConnection common;
1972 HINTERNET app_info;
1973 HINTERNET session;
1974 HINTERNET in_request;
1975 HINTERNET out_request;
1976 WCHAR *servername;
1977 HANDLE timer_cancelled;
1978 HANDLE cancel_event;
1979 DWORD last_sent_time;
1980 ULONG bytes_received;
1981 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1982 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1983 UUID connection_uuid;
1984 UUID in_pipe_uuid;
1985 UUID out_pipe_uuid;
1986 RpcHttpAsyncData *async_data;
1987 } RpcConnection_http;
1989 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1991 RpcConnection_http *httpc;
1992 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1993 if (!httpc) return NULL;
1994 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1995 if (!httpc->async_data)
1997 HeapFree(GetProcessHeap(), 0, httpc);
1998 return NULL;
2000 TRACE("async data = %p\n", httpc->async_data);
2001 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2002 httpc->async_data->refs = 1;
2003 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW);
2004 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2005 InitializeCriticalSection(&httpc->async_data->cs);
2006 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs");
2007 return &httpc->common;
2010 typedef struct _HttpTimerThreadData
2012 PVOID timer_param;
2013 DWORD *last_sent_time;
2014 HANDLE timer_cancelled;
2015 } HttpTimerThreadData;
2017 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
2019 HINTERNET in_request = param;
2020 RpcPktHdr *idle_pkt;
2022 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
2023 0, 0);
2024 if (idle_pkt)
2026 DWORD bytes_written;
2027 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
2028 RPCRT4_FreeHeader(idle_pkt);
2032 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
2034 DWORD cur_time = GetTickCount();
2035 DWORD cached_last_sent_time = *last_sent_time;
2036 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
2039 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
2041 HttpTimerThreadData *data_in = param;
2042 HttpTimerThreadData data;
2043 DWORD timeout;
2045 data = *data_in;
2046 HeapFree(GetProcessHeap(), 0, data_in);
2048 for (timeout = HTTP_IDLE_TIME;
2049 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
2050 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
2052 /* are we too soon after last send? */
2053 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME)
2054 continue;
2055 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
2058 CloseHandle(data.timer_cancelled);
2059 return 0;
2062 static VOID WINAPI rpcrt4_http_internet_callback(
2063 HINTERNET hInternet,
2064 DWORD_PTR dwContext,
2065 DWORD dwInternetStatus,
2066 LPVOID lpvStatusInformation,
2067 DWORD dwStatusInformationLength)
2069 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
2071 switch (dwInternetStatus)
2073 case INTERNET_STATUS_REQUEST_COMPLETE:
2074 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
2075 if (async_data)
2077 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation;
2079 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError;
2080 SetEvent(async_data->completion_event);
2081 RpcHttpAsyncData_Release(async_data);
2083 break;
2087 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
2089 BOOL ret;
2090 DWORD status_code;
2091 DWORD size;
2092 DWORD index;
2093 WCHAR buf[32];
2094 WCHAR *status_text = buf;
2095 TRACE("\n");
2097 index = 0;
2098 size = sizeof(status_code);
2099 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
2100 if (!ret)
2101 return GetLastError();
2102 if (status_code == HTTP_STATUS_OK)
2103 return RPC_S_OK;
2104 index = 0;
2105 size = sizeof(buf);
2106 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2107 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2109 status_text = HeapAlloc(GetProcessHeap(), 0, size);
2110 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2113 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
2114 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
2116 if (status_code == HTTP_STATUS_DENIED)
2117 return ERROR_ACCESS_DENIED;
2118 return RPC_S_SERVER_UNAVAILABLE;
2121 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
2123 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
2124 LPWSTR proxy = NULL;
2125 LPWSTR user = NULL;
2126 LPWSTR password = NULL;
2127 LPWSTR servername = NULL;
2128 const WCHAR *option;
2129 INTERNET_PORT port;
2131 if (httpc->common.QOS &&
2132 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
2134 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
2135 if (http_cred->TransportCredentials)
2137 WCHAR *p;
2138 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
2139 ULONG len = cred->DomainLength + 1 + cred->UserLength;
2140 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2141 if (!user)
2142 return RPC_S_OUT_OF_RESOURCES;
2143 p = user;
2144 if (cred->DomainLength)
2146 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
2147 p += cred->DomainLength;
2148 *p = '\\';
2149 p++;
2151 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
2152 p[cred->UserLength] = 0;
2154 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
2158 for (option = httpc->common.NetworkOptions; option;
2159 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
2161 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
2162 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
2164 if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
2166 const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
2167 const WCHAR *value_end;
2168 const WCHAR *p;
2170 value_end = strchrW(option, ',');
2171 if (!value_end)
2172 value_end = value_start + strlenW(value_start);
2173 for (p = value_start; p < value_end; p++)
2174 if (*p == ':')
2176 port = atoiW(p+1);
2177 value_end = p;
2178 break;
2180 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2181 servername = RPCRT4_strndupW(value_start, value_end-value_start);
2183 else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
2185 const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
2186 const WCHAR *value_end;
2188 value_end = strchrW(option, ',');
2189 if (!value_end)
2190 value_end = value_start + strlenW(value_start);
2191 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2192 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
2194 else
2195 FIXME("unhandled option %s\n", debugstr_w(option));
2198 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
2199 NULL, NULL, INTERNET_FLAG_ASYNC);
2200 if (!httpc->app_info)
2202 HeapFree(GetProcessHeap(), 0, password);
2203 HeapFree(GetProcessHeap(), 0, user);
2204 HeapFree(GetProcessHeap(), 0, proxy);
2205 HeapFree(GetProcessHeap(), 0, servername);
2206 ERR("InternetOpenW failed with error %d\n", GetLastError());
2207 return RPC_S_SERVER_UNAVAILABLE;
2209 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
2211 /* if no RpcProxy option specified, set the HTTP server address to the
2212 * RPC server address */
2213 if (!servername)
2215 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
2216 if (!servername)
2218 HeapFree(GetProcessHeap(), 0, password);
2219 HeapFree(GetProcessHeap(), 0, user);
2220 HeapFree(GetProcessHeap(), 0, proxy);
2221 return RPC_S_OUT_OF_RESOURCES;
2223 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
2226 port = (httpc->common.QOS &&
2227 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2228 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ?
2229 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
2231 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
2232 INTERNET_SERVICE_HTTP, 0, 0);
2234 HeapFree(GetProcessHeap(), 0, password);
2235 HeapFree(GetProcessHeap(), 0, user);
2236 HeapFree(GetProcessHeap(), 0, proxy);
2238 if (!httpc->session)
2240 ERR("InternetConnectW failed with error %d\n", GetLastError());
2241 HeapFree(GetProcessHeap(), 0, servername);
2242 return RPC_S_SERVER_UNAVAILABLE;
2244 httpc->servername = servername;
2245 return RPC_S_OK;
2248 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2249 void *buffer, unsigned int count)
2251 char *buf = buffer;
2252 BOOL ret;
2253 unsigned int bytes_left = count;
2254 RPC_STATUS status = RPC_S_OK;
2256 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count);
2258 while (bytes_left)
2260 async_data->inet_buffers.dwBufferLength = bytes_left;
2261 prepare_async_request(async_data);
2262 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0);
2263 status = wait_async_request(async_data, ret, cancel_event);
2264 if (status != RPC_S_OK)
2266 if (status == RPC_S_CALL_CANCELLED)
2267 TRACE("call cancelled\n");
2268 break;
2271 if (!async_data->inet_buffers.dwBufferLength)
2272 break;
2273 memcpy(buf, async_data->inet_buffers.lpvBuffer,
2274 async_data->inet_buffers.dwBufferLength);
2276 bytes_left -= async_data->inet_buffers.dwBufferLength;
2277 buf += async_data->inet_buffers.dwBufferLength;
2280 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
2281 async_data->inet_buffers.lpvBuffer = NULL;
2283 TRACE("%p %p %u -> %u\n", req, buffer, count, status);
2284 return status == RPC_S_OK ? count : -1;
2287 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2289 BYTE buf[20];
2290 BOOL ret;
2291 RPC_STATUS status;
2293 TRACE("sending echo request to server\n");
2295 prepare_async_request(async_data);
2296 ret = HttpSendRequestW(req, NULL, 0, NULL, 0);
2297 status = wait_async_request(async_data, ret, cancel_event);
2298 if (status != RPC_S_OK) return status;
2300 status = rpcrt4_http_check_response(req);
2301 if (status != RPC_S_OK) return status;
2303 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf));
2304 /* FIXME: do something with retrieved data */
2306 return RPC_S_OK;
2309 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len)
2311 static const WCHAR fmtW[] =
2312 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0};
2313 WCHAR header[sizeof(fmtW) / sizeof(fmtW[0]) + 10];
2315 sprintfW(header, fmtW, len);
2316 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK;
2317 return RPC_S_SERVER_UNAVAILABLE;
2320 /* prepare the in pipe for use by RPC packets */
2321 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2322 const UUID *connection_uuid, const UUID *in_pipe_uuid,
2323 const UUID *association_uuid, BOOL authorized)
2325 BOOL ret;
2326 RPC_STATUS status;
2327 RpcPktHdr *hdr;
2328 INTERNET_BUFFERSW buffers_in;
2329 DWORD bytes_written;
2331 if (!authorized)
2333 /* ask wininet to authorize, if necessary */
2334 status = send_echo_request(in_request, async_data, cancel_event);
2335 if (status != RPC_S_OK) return status;
2337 memset(&buffers_in, 0, sizeof(buffers_in));
2338 buffers_in.dwStructSize = sizeof(buffers_in);
2339 /* FIXME: get this from the registry */
2340 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2341 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal);
2342 if (status != RPC_S_OK) return status;
2344 prepare_async_request(async_data);
2345 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2346 status = wait_async_request(async_data, ret, cancel_event);
2347 if (status != RPC_S_OK) return status;
2349 TRACE("sending HTTP connect header to server\n");
2350 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2351 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2352 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2353 RPCRT4_FreeHeader(hdr);
2354 if (!ret)
2356 ERR("InternetWriteFile failed with error %d\n", GetLastError());
2357 return RPC_S_SERVER_UNAVAILABLE;
2360 return RPC_S_OK;
2363 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data,
2364 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data)
2366 unsigned short data_len;
2367 unsigned int size;
2369 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0)
2370 return RPC_S_SERVER_UNAVAILABLE;
2371 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2373 ERR("wrong packet type received %d or wrong frag_len %d\n",
2374 hdr->common.ptype, hdr->common.frag_len);
2375 return RPC_S_PROTOCOL_ERROR;
2378 size = sizeof(hdr->http) - sizeof(hdr->common);
2379 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0)
2380 return RPC_S_SERVER_UNAVAILABLE;
2382 data_len = hdr->common.frag_len - sizeof(hdr->http);
2383 if (data_len)
2385 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2386 if (!*data)
2387 return RPC_S_OUT_OF_RESOURCES;
2388 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0)
2390 HeapFree(GetProcessHeap(), 0, *data);
2391 return RPC_S_SERVER_UNAVAILABLE;
2394 else
2395 *data = NULL;
2397 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2399 ERR("invalid http packet\n");
2400 HeapFree(GetProcessHeap(), 0, *data);
2401 return RPC_S_PROTOCOL_ERROR;
2404 return RPC_S_OK;
2407 /* prepare the out pipe for use by RPC packets */
2408 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data,
2409 HANDLE cancel_event, const UUID *connection_uuid,
2410 const UUID *out_pipe_uuid, ULONG *flow_control_increment,
2411 BOOL authorized)
2413 BOOL ret;
2414 RPC_STATUS status;
2415 RpcPktHdr *hdr;
2416 BYTE *data_from_server;
2417 RpcPktHdr pkt_from_server;
2418 ULONG field1, field3;
2419 BYTE buf[20];
2421 if (!authorized)
2423 /* ask wininet to authorize, if necessary */
2424 status = send_echo_request(out_request, async_data, cancel_event);
2425 if (status != RPC_S_OK) return status;
2427 else
2428 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf));
2430 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL);
2431 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2433 status = insert_content_length_header(out_request, hdr->common.frag_len);
2434 if (status != RPC_S_OK)
2436 RPCRT4_FreeHeader(hdr);
2437 return status;
2440 TRACE("sending HTTP connect header to server\n");
2441 prepare_async_request(async_data);
2442 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2443 status = wait_async_request(async_data, ret, cancel_event);
2444 RPCRT4_FreeHeader(hdr);
2445 if (status != RPC_S_OK) return status;
2447 status = rpcrt4_http_check_response(out_request);
2448 if (status != RPC_S_OK) return status;
2450 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2451 &pkt_from_server, &data_from_server);
2452 if (status != RPC_S_OK) return status;
2453 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2454 &field1);
2455 HeapFree(GetProcessHeap(), 0, data_from_server);
2456 if (status != RPC_S_OK) return status;
2457 TRACE("received (%d) from first prepare header\n", field1);
2459 for (;;)
2461 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2462 &pkt_from_server, &data_from_server);
2463 if (status != RPC_S_OK) return status;
2464 if (pkt_from_server.http.flags != 0x0001) break;
2466 TRACE("http idle packet, waiting for real packet\n");
2467 HeapFree(GetProcessHeap(), 0, data_from_server);
2468 if (pkt_from_server.http.num_data_items != 0)
2470 ERR("HTTP idle packet should have no data items instead of %d\n",
2471 pkt_from_server.http.num_data_items);
2472 return RPC_S_PROTOCOL_ERROR;
2475 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2476 &field1, flow_control_increment,
2477 &field3);
2478 HeapFree(GetProcessHeap(), 0, data_from_server);
2479 if (status != RPC_S_OK) return status;
2480 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2482 return RPC_S_OK;
2485 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
2487 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2488 UINT i = 0, x;
2490 while (len > 0)
2492 /* first 6 bits, all from bin[0] */
2493 base64[i++] = enc[(bin[0] & 0xfc) >> 2];
2494 x = (bin[0] & 3) << 4;
2496 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
2497 if (len == 1)
2499 base64[i++] = enc[x];
2500 base64[i++] = '=';
2501 base64[i++] = '=';
2502 break;
2504 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
2505 x = (bin[1] & 0x0f) << 2;
2507 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
2508 if (len == 2)
2510 base64[i++] = enc[x];
2511 base64[i++] = '=';
2512 break;
2514 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
2516 /* last 6 bits, all from bin [2] */
2517 base64[i++] = enc[bin[2] & 0x3f];
2518 bin += 3;
2519 len -= 3;
2521 base64[i] = 0;
2522 return i;
2525 static inline char decode_char( WCHAR c )
2527 if (c >= 'A' && c <= 'Z') return c - 'A';
2528 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2529 if (c >= '0' && c <= '9') return c - '0' + 52;
2530 if (c == '+') return 62;
2531 if (c == '/') return 63;
2532 return 64;
2535 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
2537 unsigned int i = 0;
2538 char c0, c1, c2, c3;
2539 const WCHAR *p = base64;
2541 while (len > 4)
2543 if ((c0 = decode_char( p[0] )) > 63) return 0;
2544 if ((c1 = decode_char( p[1] )) > 63) return 0;
2545 if ((c2 = decode_char( p[2] )) > 63) return 0;
2546 if ((c3 = decode_char( p[3] )) > 63) return 0;
2548 if (buf)
2550 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2551 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2552 buf[i + 2] = (c2 << 6) | c3;
2554 len -= 4;
2555 i += 3;
2556 p += 4;
2558 if (p[2] == '=')
2560 if ((c0 = decode_char( p[0] )) > 63) return 0;
2561 if ((c1 = decode_char( p[1] )) > 63) return 0;
2563 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
2564 i++;
2566 else if (p[3] == '=')
2568 if ((c0 = decode_char( p[0] )) > 63) return 0;
2569 if ((c1 = decode_char( p[1] )) > 63) return 0;
2570 if ((c2 = decode_char( p[2] )) > 63) return 0;
2572 if (buf)
2574 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2575 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2577 i += 2;
2579 else
2581 if ((c0 = decode_char( p[0] )) > 63) return 0;
2582 if ((c1 = decode_char( p[1] )) > 63) return 0;
2583 if ((c2 = decode_char( p[2] )) > 63) return 0;
2584 if ((c3 = decode_char( p[3] )) > 63) return 0;
2586 if (buf)
2588 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2589 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2590 buf[i + 2] = (c2 << 6) | c3;
2592 i += 3;
2594 return i;
2597 static struct authinfo *alloc_authinfo(void)
2599 struct authinfo *ret;
2601 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL;
2603 SecInvalidateHandle(&ret->cred);
2604 SecInvalidateHandle(&ret->ctx);
2605 memset(&ret->exp, 0, sizeof(ret->exp));
2606 ret->scheme = 0;
2607 ret->attr = 0;
2608 ret->max_token = 0;
2609 ret->data = NULL;
2610 ret->data_len = 0;
2611 ret->finished = FALSE;
2612 return ret;
2615 static void destroy_authinfo(struct authinfo *info)
2617 if (!info) return;
2619 if (SecIsValidHandle(&info->ctx))
2620 DeleteSecurityContext(&info->ctx);
2621 if (SecIsValidHandle(&info->cred))
2622 FreeCredentialsHandle(&info->cred);
2624 HeapFree(GetProcessHeap(), 0, info->data);
2625 HeapFree(GetProcessHeap(), 0, info);
2628 static const WCHAR basicW[] = {'B','a','s','i','c',0};
2629 static const WCHAR ntlmW[] = {'N','T','L','M',0};
2630 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0};
2631 static const WCHAR digestW[] = {'D','i','g','e','s','t',0};
2632 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2634 static const struct
2636 const WCHAR *str;
2637 unsigned int len;
2638 DWORD scheme;
2640 auth_schemes[] =
2642 { basicW, ARRAYSIZE(basicW) - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC },
2643 { ntlmW, ARRAYSIZE(ntlmW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM },
2644 { passportW, ARRAYSIZE(passportW) - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT },
2645 { digestW, ARRAYSIZE(digestW) - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST },
2646 { negotiateW, ARRAYSIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE }
2648 static const unsigned int num_auth_schemes = sizeof(auth_schemes)/sizeof(auth_schemes[0]);
2650 static DWORD auth_scheme_from_header( const WCHAR *header )
2652 unsigned int i;
2653 for (i = 0; i < num_auth_schemes; i++)
2655 if (!strncmpiW( header, auth_schemes[i].str, auth_schemes[i].len ) &&
2656 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
2658 return 0;
2661 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen)
2663 DWORD len, index = 0;
2664 for (;;)
2666 len = buflen;
2667 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE;
2668 if (auth_scheme_from_header(buffer) == scheme) break;
2670 return TRUE;
2673 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername,
2674 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr)
2676 struct authinfo *info = *auth_ptr;
2677 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials;
2678 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2680 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE;
2682 switch (creds->AuthnSchemes[0])
2684 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2686 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
2687 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
2689 info->data_len = userlen + passlen + 1;
2690 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len)))
2692 status = RPC_S_OUT_OF_MEMORY;
2693 break;
2695 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL);
2696 info->data[userlen] = ':';
2697 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL);
2699 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC;
2700 info->finished = TRUE;
2701 status = RPC_S_OK;
2702 break;
2704 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2705 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2708 static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2709 SECURITY_STATUS ret;
2710 SecBufferDesc out_desc, in_desc;
2711 SecBuffer out, in;
2712 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE;
2713 SEC_WCHAR *scheme;
2714 int scheme_len;
2715 const WCHAR *p;
2716 WCHAR auth_value[2048];
2717 DWORD size = sizeof(auth_value);
2718 BOOL first = FALSE;
2720 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW;
2721 else scheme = negotiateW;
2722 scheme_len = strlenW( scheme );
2724 if (!*auth_ptr)
2726 TimeStamp exp;
2727 SecPkgInfoW *pkg_info;
2729 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp);
2730 if (ret != SEC_E_OK) break;
2732 ret = QuerySecurityPackageInfoW(scheme, &pkg_info);
2733 if (ret != SEC_E_OK) break;
2735 info->max_token = pkg_info->cbMaxToken;
2736 FreeContextBuffer(pkg_info);
2737 first = TRUE;
2739 else
2741 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break;
2742 if (auth_scheme_from_header(auth_value) != info->scheme)
2744 ERR("authentication scheme changed\n");
2745 break;
2748 in.BufferType = SECBUFFER_TOKEN;
2749 in.cbBuffer = 0;
2750 in.pvBuffer = NULL;
2752 in_desc.ulVersion = 0;
2753 in_desc.cBuffers = 1;
2754 in_desc.pBuffers = &in;
2756 p = auth_value + scheme_len;
2757 if (!first && *p == ' ')
2759 int len = strlenW(++p);
2760 in.cbBuffer = decode_base64(p, len, NULL);
2761 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break;
2762 decode_base64(p, len, in.pvBuffer);
2764 out.BufferType = SECBUFFER_TOKEN;
2765 out.cbBuffer = info->max_token;
2766 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer)))
2768 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2769 break;
2771 out_desc.ulVersion = 0;
2772 out_desc.cBuffers = 1;
2773 out_desc.pBuffers = &out;
2775 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx,
2776 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP,
2777 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc,
2778 &info->attr, &info->exp);
2779 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2780 if (ret == SEC_E_OK)
2782 HeapFree(GetProcessHeap(), 0, info->data);
2783 info->data = out.pvBuffer;
2784 info->data_len = out.cbBuffer;
2785 info->finished = TRUE;
2786 TRACE("sending last auth packet\n");
2787 status = RPC_S_OK;
2789 else if (ret == SEC_I_CONTINUE_NEEDED)
2791 HeapFree(GetProcessHeap(), 0, info->data);
2792 info->data = out.pvBuffer;
2793 info->data_len = out.cbBuffer;
2794 TRACE("sending next auth packet\n");
2795 status = RPC_S_OK;
2797 else
2799 ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret);
2800 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
2801 break;
2803 info->scheme = creds->AuthnSchemes[0];
2804 break;
2806 default:
2807 FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]);
2808 break;
2811 if (status != RPC_S_OK)
2813 destroy_authinfo(info);
2814 *auth_ptr = NULL;
2815 return status;
2817 *auth_ptr = info;
2818 return RPC_S_OK;
2821 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len)
2823 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '};
2824 static const WCHAR basicW[] = {'B','a','s','i','c',' '};
2825 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '};
2826 static const WCHAR ntlmW[] = {'N','T','L','M',' '};
2827 int scheme_len, auth_len = sizeof(authW) / sizeof(authW[0]), len = ((data_len + 2) * 4) / 3;
2828 const WCHAR *scheme_str;
2829 WCHAR *header, *ptr;
2830 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2832 switch (scheme)
2834 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2835 scheme_str = basicW;
2836 scheme_len = sizeof(basicW) / sizeof(basicW[0]);
2837 break;
2838 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2839 scheme_str = negotiateW;
2840 scheme_len = sizeof(negotiateW) / sizeof(negotiateW[0]);
2841 break;
2842 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2843 scheme_str = ntlmW;
2844 scheme_len = sizeof(ntlmW) / sizeof(ntlmW[0]);
2845 break;
2846 default:
2847 ERR("unknown scheme %u\n", scheme);
2848 return RPC_S_SERVER_UNAVAILABLE;
2850 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR))))
2852 memcpy(header, authW, auth_len * sizeof(WCHAR));
2853 ptr = header + auth_len;
2854 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR));
2855 ptr += scheme_len;
2856 len = encode_base64(data, data_len, ptr);
2857 ptr[len++] = '\r';
2858 ptr[len++] = '\n';
2859 ptr[len] = 0;
2860 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE))
2861 status = RPC_S_OK;
2862 HeapFree(GetProcessHeap(), 0, header);
2864 return status;
2867 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2869 DWORD count, len = 0, size = sizeof(len);
2870 char buf[2048];
2872 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL);
2873 if (!len) return;
2874 for (;;)
2876 count = min(sizeof(buf), len);
2877 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return;
2878 len -= count;
2882 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request)
2884 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0};
2885 struct authinfo *info = NULL;
2886 RPC_STATUS status;
2887 BOOL ret;
2889 for (;;)
2891 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info);
2892 if (status != RPC_S_OK) break;
2894 status = insert_authorization_header(request, info->scheme, info->data, info->data_len);
2895 if (status != RPC_S_OK) break;
2897 prepare_async_request(httpc->async_data);
2898 ret = HttpSendRequestW(request, NULL, 0, NULL, 0);
2899 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
2900 if (status != RPC_S_OK || info->finished) break;
2902 status = rpcrt4_http_check_response(request);
2903 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break;
2904 drain_content(request, httpc->async_data, httpc->cancel_event);
2907 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
2908 HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
2910 destroy_authinfo(info);
2911 return status;
2914 static BOOL has_credentials(RpcConnection_http *httpc)
2916 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
2917 SEC_WINNT_AUTH_IDENTITY_W *id;
2919 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
2920 return FALSE;
2922 creds = httpc->common.QOS->qos->u.HttpCredentials;
2923 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
2924 return FALSE;
2926 id = creds->TransportCredentials;
2927 if (!id || !id->User || !id->Password) return FALSE;
2929 return TRUE;
2932 static BOOL is_secure(RpcConnection_http *httpc)
2934 return httpc->common.QOS &&
2935 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2936 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2939 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value)
2941 static WCHAR httpW[] = {'h','t','t','p',0};
2942 static WCHAR httpsW[] = {'h','t','t','p','s',0};
2943 URL_COMPONENTSW uc;
2944 DWORD len;
2945 WCHAR *url;
2946 BOOL ret;
2948 if (!value) return RPC_S_OK;
2950 uc.dwStructSize = sizeof(uc);
2951 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW;
2952 uc.dwSchemeLength = 0;
2953 uc.lpszHostName = httpc->servername;
2954 uc.dwHostNameLength = 0;
2955 uc.nPort = 0;
2956 uc.lpszUserName = NULL;
2957 uc.dwUserNameLength = 0;
2958 uc.lpszPassword = NULL;
2959 uc.dwPasswordLength = 0;
2960 uc.lpszUrlPath = NULL;
2961 uc.dwUrlPathLength = 0;
2962 uc.lpszExtraInfo = NULL;
2963 uc.dwExtraInfoLength = 0;
2965 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
2966 return RPC_S_SERVER_UNAVAILABLE;
2968 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY;
2970 len = len / sizeof(WCHAR) - 1;
2971 if (!InternetCreateUrlW(&uc, 0, url, &len))
2973 HeapFree(GetProcessHeap(), 0, url);
2974 return RPC_S_SERVER_UNAVAILABLE;
2977 ret = InternetSetCookieW(url, NULL, value);
2978 HeapFree(GetProcessHeap(), 0, url);
2979 if (!ret) return RPC_S_SERVER_UNAVAILABLE;
2981 return RPC_S_OK;
2984 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2986 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2987 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2988 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2989 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2990 static const WCHAR wszColon[] = {':',0};
2991 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2992 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2993 DWORD flags;
2994 WCHAR *url;
2995 RPC_STATUS status;
2996 BOOL secure, credentials;
2997 HttpTimerThreadData *timer_data;
2998 HANDLE thread;
3000 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
3002 if (Connection->server)
3004 ERR("ncacn_http servers not supported yet\n");
3005 return RPC_S_SERVER_UNAVAILABLE;
3008 if (httpc->in_request)
3009 return RPC_S_OK;
3011 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
3013 UuidCreate(&httpc->connection_uuid);
3014 UuidCreate(&httpc->in_pipe_uuid);
3015 UuidCreate(&httpc->out_pipe_uuid);
3017 status = rpcrt4_http_internet_connect(httpc);
3018 if (status != RPC_S_OK)
3019 return status;
3021 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
3022 if (!url)
3023 return RPC_S_OUT_OF_MEMORY;
3024 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
3025 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
3026 strcatW(url, wszColon);
3027 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
3029 secure = is_secure(httpc);
3030 credentials = has_credentials(httpc);
3032 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
3033 INTERNET_FLAG_NO_AUTO_REDIRECT;
3034 if (secure) flags |= INTERNET_FLAG_SECURE;
3035 if (credentials) flags |= INTERNET_FLAG_NO_AUTH;
3037 status = set_auth_cookie(httpc, Connection->CookieAuth);
3038 if (status != RPC_S_OK)
3040 HeapFree(GetProcessHeap(), 0, url);
3041 return status;
3043 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes,
3044 flags, (DWORD_PTR)httpc->async_data);
3045 if (!httpc->in_request)
3047 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
3048 HeapFree(GetProcessHeap(), 0, url);
3049 return RPC_S_SERVER_UNAVAILABLE;
3052 if (credentials)
3054 status = authorize_request(httpc, httpc->in_request);
3055 if (status != RPC_S_OK)
3057 HeapFree(GetProcessHeap(), 0, url);
3058 return status;
3060 status = rpcrt4_http_check_response(httpc->in_request);
3061 if (status != RPC_S_OK)
3063 HeapFree(GetProcessHeap(), 0, url);
3064 return status;
3066 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event);
3069 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes,
3070 flags, (DWORD_PTR)httpc->async_data);
3071 HeapFree(GetProcessHeap(), 0, url);
3072 if (!httpc->out_request)
3074 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
3075 return RPC_S_SERVER_UNAVAILABLE;
3078 if (credentials)
3080 status = authorize_request(httpc, httpc->out_request);
3081 if (status != RPC_S_OK)
3082 return status;
3085 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event,
3086 &httpc->connection_uuid, &httpc->in_pipe_uuid,
3087 &Connection->assoc->http_uuid, credentials);
3088 if (status != RPC_S_OK)
3089 return status;
3091 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event,
3092 &httpc->connection_uuid, &httpc->out_pipe_uuid,
3093 &httpc->flow_control_increment, credentials);
3094 if (status != RPC_S_OK)
3095 return status;
3097 httpc->flow_control_mark = httpc->flow_control_increment / 2;
3098 httpc->last_sent_time = GetTickCount();
3099 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
3101 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
3102 if (!timer_data)
3103 return ERROR_OUTOFMEMORY;
3104 timer_data->timer_param = httpc->in_request;
3105 timer_data->last_sent_time = &httpc->last_sent_time;
3106 timer_data->timer_cancelled = httpc->timer_cancelled;
3107 /* FIXME: should use CreateTimerQueueTimer when implemented */
3108 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
3109 if (!thread)
3111 HeapFree(GetProcessHeap(), 0, timer_data);
3112 return GetLastError();
3114 CloseHandle(thread);
3116 return RPC_S_OK;
3119 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
3121 assert(0);
3122 return RPC_S_SERVER_UNAVAILABLE;
3125 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
3126 void *buffer, unsigned int count)
3128 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3129 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count);
3132 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
3134 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3135 RPC_STATUS status;
3136 DWORD hdr_length;
3137 LONG dwRead;
3138 RpcPktCommonHdr common_hdr;
3140 *Header = NULL;
3142 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
3144 again:
3145 /* read packet common header */
3146 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
3147 if (dwRead != sizeof(common_hdr)) {
3148 WARN("Short read of header, %d bytes\n", dwRead);
3149 status = RPC_S_PROTOCOL_ERROR;
3150 goto fail;
3152 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
3153 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
3155 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
3156 status = RPC_S_PROTOCOL_ERROR;
3157 goto fail;
3160 status = RPCRT4_ValidateCommonHeader(&common_hdr);
3161 if (status != RPC_S_OK) goto fail;
3163 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
3164 if (hdr_length == 0) {
3165 WARN("header length == 0\n");
3166 status = RPC_S_PROTOCOL_ERROR;
3167 goto fail;
3170 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
3171 if (!*Header)
3173 status = RPC_S_OUT_OF_RESOURCES;
3174 goto fail;
3176 memcpy(*Header, &common_hdr, sizeof(common_hdr));
3178 /* read the rest of packet header */
3179 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
3180 if (dwRead != hdr_length - sizeof(common_hdr)) {
3181 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
3182 status = RPC_S_PROTOCOL_ERROR;
3183 goto fail;
3186 if (common_hdr.frag_len - hdr_length)
3188 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
3189 if (!*Payload)
3191 status = RPC_S_OUT_OF_RESOURCES;
3192 goto fail;
3195 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
3196 if (dwRead != common_hdr.frag_len - hdr_length)
3198 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
3199 status = RPC_S_PROTOCOL_ERROR;
3200 goto fail;
3203 else
3204 *Payload = NULL;
3206 if ((*Header)->common.ptype == PKT_HTTP)
3208 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
3210 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
3211 status = RPC_S_PROTOCOL_ERROR;
3212 goto fail;
3214 if ((*Header)->http.flags == 0x0001)
3216 TRACE("http idle packet, waiting for real packet\n");
3217 if ((*Header)->http.num_data_items != 0)
3219 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
3220 status = RPC_S_PROTOCOL_ERROR;
3221 goto fail;
3224 else if ((*Header)->http.flags == 0x0002)
3226 ULONG bytes_transmitted;
3227 ULONG flow_control_increment;
3228 UUID pipe_uuid;
3229 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
3230 Connection->server,
3231 &bytes_transmitted,
3232 &flow_control_increment,
3233 &pipe_uuid);
3234 if (status != RPC_S_OK)
3235 goto fail;
3236 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
3237 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
3238 /* FIXME: do something with parsed data */
3240 else
3242 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
3243 status = RPC_S_PROTOCOL_ERROR;
3244 goto fail;
3246 RPCRT4_FreeHeader(*Header);
3247 *Header = NULL;
3248 HeapFree(GetProcessHeap(), 0, *Payload);
3249 *Payload = NULL;
3250 goto again;
3253 /* success */
3254 status = RPC_S_OK;
3256 httpc->bytes_received += common_hdr.frag_len;
3258 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
3260 if (httpc->bytes_received > httpc->flow_control_mark)
3262 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
3263 httpc->bytes_received,
3264 httpc->flow_control_increment,
3265 &httpc->out_pipe_uuid);
3266 if (hdr)
3268 DWORD bytes_written;
3269 BOOL ret2;
3270 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
3271 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
3272 RPCRT4_FreeHeader(hdr);
3273 if (ret2)
3274 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
3278 fail:
3279 if (status != RPC_S_OK) {
3280 RPCRT4_FreeHeader(*Header);
3281 *Header = NULL;
3282 HeapFree(GetProcessHeap(), 0, *Payload);
3283 *Payload = NULL;
3285 return status;
3288 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
3289 const void *buffer, unsigned int count)
3291 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3292 DWORD bytes_written;
3293 BOOL ret;
3295 httpc->last_sent_time = ~0U; /* disable idle packet sending */
3296 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
3297 httpc->last_sent_time = GetTickCount();
3298 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
3299 return ret ? bytes_written : -1;
3302 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
3304 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3306 TRACE("\n");
3308 SetEvent(httpc->timer_cancelled);
3309 if (httpc->in_request)
3310 InternetCloseHandle(httpc->in_request);
3311 httpc->in_request = NULL;
3312 if (httpc->out_request)
3313 InternetCloseHandle(httpc->out_request);
3314 httpc->out_request = NULL;
3315 if (httpc->app_info)
3316 InternetCloseHandle(httpc->app_info);
3317 httpc->app_info = NULL;
3318 if (httpc->session)
3319 InternetCloseHandle(httpc->session);
3320 httpc->session = NULL;
3321 RpcHttpAsyncData_Release(httpc->async_data);
3322 if (httpc->cancel_event)
3323 CloseHandle(httpc->cancel_event);
3324 HeapFree(GetProcessHeap(), 0, httpc->servername);
3325 httpc->servername = NULL;
3327 return 0;
3330 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
3332 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3334 SetEvent(httpc->cancel_event);
3337 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint)
3339 FIXME("\n");
3340 return RPC_S_ACCESS_DENIED;
3343 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
3345 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3346 BOOL ret;
3347 RPC_STATUS status;
3349 prepare_async_request(httpc->async_data);
3350 ret = InternetQueryDataAvailable(httpc->out_request,
3351 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
3352 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
3353 return status == RPC_S_OK ? 0 : -1;
3356 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
3357 const char *networkaddr,
3358 const char *endpoint)
3360 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
3361 EPM_PROTOCOL_HTTP, endpoint);
3364 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
3365 size_t tower_size,
3366 char **networkaddr,
3367 char **endpoint)
3369 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
3370 networkaddr, EPM_PROTOCOL_HTTP,
3371 endpoint);
3374 static const struct connection_ops conn_protseq_list[] = {
3375 { "ncacn_np",
3376 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
3377 rpcrt4_conn_np_alloc,
3378 rpcrt4_ncacn_np_open,
3379 rpcrt4_ncacn_np_handoff,
3380 rpcrt4_conn_np_read,
3381 rpcrt4_conn_np_write,
3382 rpcrt4_conn_np_close,
3383 rpcrt4_conn_np_cancel_call,
3384 rpcrt4_ncacn_np_is_server_listening,
3385 rpcrt4_conn_np_wait_for_incoming_data,
3386 rpcrt4_ncacn_np_get_top_of_tower,
3387 rpcrt4_ncacn_np_parse_top_of_tower,
3388 NULL,
3389 RPCRT4_default_is_authorized,
3390 RPCRT4_default_authorize,
3391 RPCRT4_default_secure_packet,
3392 rpcrt4_conn_np_impersonate_client,
3393 rpcrt4_conn_np_revert_to_self,
3394 RPCRT4_default_inquire_auth_client,
3396 { "ncalrpc",
3397 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
3398 rpcrt4_conn_np_alloc,
3399 rpcrt4_ncalrpc_open,
3400 rpcrt4_ncalrpc_handoff,
3401 rpcrt4_conn_np_read,
3402 rpcrt4_conn_np_write,
3403 rpcrt4_conn_np_close,
3404 rpcrt4_conn_np_cancel_call,
3405 rpcrt4_ncalrpc_np_is_server_listening,
3406 rpcrt4_conn_np_wait_for_incoming_data,
3407 rpcrt4_ncalrpc_get_top_of_tower,
3408 rpcrt4_ncalrpc_parse_top_of_tower,
3409 NULL,
3410 rpcrt4_ncalrpc_is_authorized,
3411 rpcrt4_ncalrpc_authorize,
3412 rpcrt4_ncalrpc_secure_packet,
3413 rpcrt4_conn_np_impersonate_client,
3414 rpcrt4_conn_np_revert_to_self,
3415 rpcrt4_ncalrpc_inquire_auth_client,
3417 { "ncacn_ip_tcp",
3418 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
3419 rpcrt4_conn_tcp_alloc,
3420 rpcrt4_ncacn_ip_tcp_open,
3421 rpcrt4_conn_tcp_handoff,
3422 rpcrt4_conn_tcp_read,
3423 rpcrt4_conn_tcp_write,
3424 rpcrt4_conn_tcp_close,
3425 rpcrt4_conn_tcp_cancel_call,
3426 rpcrt4_conn_tcp_is_server_listening,
3427 rpcrt4_conn_tcp_wait_for_incoming_data,
3428 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
3429 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
3430 NULL,
3431 RPCRT4_default_is_authorized,
3432 RPCRT4_default_authorize,
3433 RPCRT4_default_secure_packet,
3434 RPCRT4_default_impersonate_client,
3435 RPCRT4_default_revert_to_self,
3436 RPCRT4_default_inquire_auth_client,
3438 { "ncacn_http",
3439 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
3440 rpcrt4_ncacn_http_alloc,
3441 rpcrt4_ncacn_http_open,
3442 rpcrt4_ncacn_http_handoff,
3443 rpcrt4_ncacn_http_read,
3444 rpcrt4_ncacn_http_write,
3445 rpcrt4_ncacn_http_close,
3446 rpcrt4_ncacn_http_cancel_call,
3447 rpcrt4_ncacn_http_is_server_listening,
3448 rpcrt4_ncacn_http_wait_for_incoming_data,
3449 rpcrt4_ncacn_http_get_top_of_tower,
3450 rpcrt4_ncacn_http_parse_top_of_tower,
3451 rpcrt4_ncacn_http_receive_fragment,
3452 RPCRT4_default_is_authorized,
3453 RPCRT4_default_authorize,
3454 RPCRT4_default_secure_packet,
3455 RPCRT4_default_impersonate_client,
3456 RPCRT4_default_revert_to_self,
3457 RPCRT4_default_inquire_auth_client,
3462 static const struct protseq_ops protseq_list[] =
3465 "ncacn_np",
3466 rpcrt4_protseq_np_alloc,
3467 rpcrt4_protseq_np_signal_state_changed,
3468 rpcrt4_protseq_np_get_wait_array,
3469 rpcrt4_protseq_np_free_wait_array,
3470 rpcrt4_protseq_np_wait_for_new_connection,
3471 rpcrt4_protseq_ncacn_np_open_endpoint,
3474 "ncalrpc",
3475 rpcrt4_protseq_np_alloc,
3476 rpcrt4_protseq_np_signal_state_changed,
3477 rpcrt4_protseq_np_get_wait_array,
3478 rpcrt4_protseq_np_free_wait_array,
3479 rpcrt4_protseq_np_wait_for_new_connection,
3480 rpcrt4_protseq_ncalrpc_open_endpoint,
3483 "ncacn_ip_tcp",
3484 rpcrt4_protseq_sock_alloc,
3485 rpcrt4_protseq_sock_signal_state_changed,
3486 rpcrt4_protseq_sock_get_wait_array,
3487 rpcrt4_protseq_sock_free_wait_array,
3488 rpcrt4_protseq_sock_wait_for_new_connection,
3489 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
3493 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
3495 unsigned int i;
3496 for(i=0; i<ARRAYSIZE(protseq_list); i++)
3497 if (!strcmp(protseq_list[i].name, protseq))
3498 return &protseq_list[i];
3499 return NULL;
3502 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
3504 unsigned int i;
3505 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
3506 if (!strcmp(conn_protseq_list[i].name, protseq))
3507 return &conn_protseq_list[i];
3508 return NULL;
3511 /**** interface to rest of code ****/
3513 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
3515 TRACE("(Connection == ^%p)\n", Connection);
3517 assert(!Connection->server);
3518 return Connection->ops->open_connection_client(Connection);
3521 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
3523 TRACE("(Connection == ^%p)\n", Connection);
3524 if (SecIsValidHandle(&Connection->ctx))
3526 DeleteSecurityContext(&Connection->ctx);
3527 SecInvalidateHandle(&Connection->ctx);
3529 rpcrt4_conn_close(Connection);
3530 return RPC_S_OK;
3533 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
3534 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
3535 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth)
3537 static LONG next_id;
3538 const struct connection_ops *ops;
3539 RpcConnection* NewConnection;
3541 ops = rpcrt4_get_conn_protseq_ops(Protseq);
3542 if (!ops)
3544 FIXME("not supported for protseq %s\n", Protseq);
3545 return RPC_S_PROTSEQ_NOT_SUPPORTED;
3548 NewConnection = ops->alloc();
3549 NewConnection->ref = 1;
3550 NewConnection->Next = NULL;
3551 NewConnection->server_binding = NULL;
3552 NewConnection->server = server;
3553 NewConnection->ops = ops;
3554 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
3555 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
3556 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
3557 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth);
3558 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
3559 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
3560 NewConnection->NextCallId = 1;
3562 SecInvalidateHandle(&NewConnection->ctx);
3563 memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
3564 NewConnection->attr = 0;
3565 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
3566 NewConnection->AuthInfo = AuthInfo;
3567 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
3568 NewConnection->encryption_auth_len = 0;
3569 NewConnection->signature_auth_len = 0;
3570 if (QOS) RpcQualityOfService_AddRef(QOS);
3571 NewConnection->QOS = QOS;
3573 list_init(&NewConnection->conn_pool_entry);
3574 NewConnection->async_state = NULL;
3576 TRACE("connection: %p\n", NewConnection);
3577 *Connection = NewConnection;
3579 return RPC_S_OK;
3582 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
3584 RPC_STATUS err;
3586 err = RPCRT4_CreateConnection(Connection, OldConnection->server, rpcrt4_conn_get_name(OldConnection),
3587 OldConnection->NetworkAddr, OldConnection->Endpoint, NULL,
3588 OldConnection->AuthInfo, OldConnection->QOS, OldConnection->CookieAuth);
3589 if (err == RPC_S_OK)
3590 rpcrt4_conn_handoff(OldConnection, *Connection);
3591 return err;
3594 RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn )
3596 InterlockedIncrement( &conn->ref );
3597 return conn;
3600 RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
3602 if (InterlockedDecrement( &Connection->ref ) > 0) return RPC_S_OK;
3604 TRACE("destroying connection %p\n", Connection);
3606 RPCRT4_CloseConnection(Connection);
3607 RPCRT4_strfree(Connection->Endpoint);
3608 RPCRT4_strfree(Connection->NetworkAddr);
3609 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
3610 HeapFree(GetProcessHeap(), 0, Connection->CookieAuth);
3611 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
3612 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
3614 /* server-only */
3615 if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
3617 HeapFree(GetProcessHeap(), 0, Connection);
3618 return RPC_S_OK;
3621 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)
3623 const struct connection_ops *ops;
3625 ops = rpcrt4_get_conn_protseq_ops(protseq);
3626 if (!ops)
3628 FIXME("not supported for protseq %s\n", protseq);
3629 return RPC_S_INVALID_BINDING;
3632 return ops->is_server_listening(endpoint);
3635 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3636 size_t *tower_size,
3637 const char *protseq,
3638 const char *networkaddr,
3639 const char *endpoint)
3641 twr_empty_floor_t *protocol_floor;
3642 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3644 *tower_size = 0;
3646 if (!protseq_ops)
3647 return RPC_S_INVALID_RPC_PROTSEQ;
3649 if (!tower_data)
3651 *tower_size = sizeof(*protocol_floor);
3652 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3653 return RPC_S_OK;
3656 protocol_floor = (twr_empty_floor_t *)tower_data;
3657 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3658 protocol_floor->protid = protseq_ops->epm_protocols[0];
3659 protocol_floor->count_rhs = 0;
3661 tower_data += sizeof(*protocol_floor);
3663 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3664 if (!*tower_size)
3665 return EPT_S_NOT_REGISTERED;
3667 *tower_size += sizeof(*protocol_floor);
3669 return RPC_S_OK;
3672 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3673 size_t tower_size,
3674 char **protseq,
3675 char **networkaddr,
3676 char **endpoint)
3678 const twr_empty_floor_t *protocol_floor;
3679 const twr_empty_floor_t *floor4;
3680 const struct connection_ops *protseq_ops = NULL;
3681 RPC_STATUS status;
3682 unsigned int i;
3684 if (tower_size < sizeof(*protocol_floor))
3685 return EPT_S_NOT_REGISTERED;
3687 protocol_floor = (const twr_empty_floor_t *)tower_data;
3688 tower_data += sizeof(*protocol_floor);
3689 tower_size -= sizeof(*protocol_floor);
3690 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3691 (protocol_floor->count_rhs > tower_size))
3692 return EPT_S_NOT_REGISTERED;
3693 tower_data += protocol_floor->count_rhs;
3694 tower_size -= protocol_floor->count_rhs;
3696 floor4 = (const twr_empty_floor_t *)tower_data;
3697 if ((tower_size < sizeof(*floor4)) ||
3698 (floor4->count_lhs != sizeof(floor4->protid)))
3699 return EPT_S_NOT_REGISTERED;
3701 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
3702 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3703 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3705 protseq_ops = &conn_protseq_list[i];
3706 break;
3709 if (!protseq_ops)
3710 return EPT_S_NOT_REGISTERED;
3712 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3714 if ((status == RPC_S_OK) && protseq)
3716 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3717 strcpy(*protseq, protseq_ops->name);
3720 return status;
3723 /***********************************************************************
3724 * RpcNetworkIsProtseqValidW (RPCRT4.@)
3726 * Checks if the given protocol sequence is known by the RPC system.
3727 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3730 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3732 char ps[0x10];
3734 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3735 ps, sizeof ps, NULL, NULL);
3736 if (rpcrt4_get_conn_protseq_ops(ps))
3737 return RPC_S_OK;
3739 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3741 return RPC_S_INVALID_RPC_PROTSEQ;
3744 /***********************************************************************
3745 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3747 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3749 UNICODE_STRING protseqW;
3751 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3753 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3754 RtlFreeUnicodeString(&protseqW);
3755 return ret;
3757 return RPC_S_OUT_OF_MEMORY;
3760 /***********************************************************************
3761 * RpcProtseqVectorFreeA (RPCRT4.@)
3763 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
3765 TRACE("(%p)\n", protseqs);
3767 if (*protseqs)
3769 unsigned int i;
3770 for (i = 0; i < (*protseqs)->Count; i++)
3771 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3772 HeapFree(GetProcessHeap(), 0, *protseqs);
3773 *protseqs = NULL;
3775 return RPC_S_OK;
3778 /***********************************************************************
3779 * RpcProtseqVectorFreeW (RPCRT4.@)
3781 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
3783 TRACE("(%p)\n", protseqs);
3785 if (*protseqs)
3787 unsigned int i;
3788 for (i = 0; i < (*protseqs)->Count; i++)
3789 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3790 HeapFree(GetProcessHeap(), 0, *protseqs);
3791 *protseqs = NULL;
3793 return RPC_S_OK;
3796 /***********************************************************************
3797 * RpcNetworkInqProtseqsW (RPCRT4.@)
3799 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
3801 RPC_PROTSEQ_VECTORW *pvector;
3802 unsigned int i;
3803 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3805 TRACE("(%p)\n", protseqs);
3807 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAYSIZE(protseq_list)));
3808 if (!*protseqs)
3809 goto end;
3810 pvector = *protseqs;
3811 pvector->Count = 0;
3812 for (i = 0; i < ARRAYSIZE(protseq_list); i++)
3814 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
3815 if (pvector->Protseq[i] == NULL)
3816 goto end;
3817 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
3818 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
3819 pvector->Count++;
3821 status = RPC_S_OK;
3823 end:
3824 if (status != RPC_S_OK)
3825 RpcProtseqVectorFreeW(protseqs);
3826 return status;
3829 /***********************************************************************
3830 * RpcNetworkInqProtseqsA (RPCRT4.@)
3832 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
3834 RPC_PROTSEQ_VECTORA *pvector;
3835 unsigned int i;
3836 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3838 TRACE("(%p)\n", protseqs);
3840 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAYSIZE(protseq_list)));
3841 if (!*protseqs)
3842 goto end;
3843 pvector = *protseqs;
3844 pvector->Count = 0;
3845 for (i = 0; i < ARRAYSIZE(protseq_list); i++)
3847 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
3848 if (pvector->Protseq[i] == NULL)
3849 goto end;
3850 strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
3851 pvector->Count++;
3853 status = RPC_S_OK;
3855 end:
3856 if (status != RPC_S_OK)
3857 RpcProtseqVectorFreeA(protseqs);
3858 return status;