Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / rpcrt4 / rpc_transport.c
bloba36937069f81798f0924d640610b78f84bbbdb83
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>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_TCP_H
47 # include <netinet/tcp.h>
48 #endif
49 #ifdef HAVE_ARPA_INET_H
50 # include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NETDB_H
53 #include <netdb.h>
54 #endif
55 #ifdef HAVE_SYS_POLL_H
56 #include <sys/poll.h>
57 #endif
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winnls.h"
62 #include "winerror.h"
63 #include "winreg.h"
64 #include "wininet.h"
65 #include "winternl.h"
66 #include "wine/unicode.h"
68 #include "rpc.h"
69 #include "rpcndr.h"
71 #include "wine/debug.h"
73 #include "rpc_binding.h"
74 #include "rpc_message.h"
75 #include "rpc_server.h"
76 #include "epm_towers.h"
78 #ifndef SOL_TCP
79 # define SOL_TCP IPPROTO_TCP
80 #endif
82 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
84 static CRITICAL_SECTION assoc_list_cs;
85 static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
87 0, 0, &assoc_list_cs,
88 { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
89 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
91 static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
93 static struct list assoc_list = LIST_INIT(assoc_list);
95 /**** ncacn_np support ****/
97 typedef struct _RpcConnection_np
99 RpcConnection common;
100 HANDLE pipe;
101 OVERLAPPED ovl;
102 BOOL listening;
103 } RpcConnection_np;
105 static RpcConnection *rpcrt4_conn_np_alloc(void)
107 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
108 if (npc)
110 npc->pipe = NULL;
111 memset(&npc->ovl, 0, sizeof(npc->ovl));
112 npc->listening = FALSE;
114 return &npc->common;
117 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
119 if (npc->listening)
120 return RPC_S_OK;
122 npc->listening = TRUE;
123 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
124 return RPC_S_OK;
126 if (GetLastError() == ERROR_PIPE_CONNECTED) {
127 SetEvent(npc->ovl.hEvent);
128 return RPC_S_OK;
130 if (GetLastError() == ERROR_IO_PENDING) {
131 /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
132 return RPC_S_OK;
134 npc->listening = FALSE;
135 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
136 return RPC_S_OUT_OF_RESOURCES;
139 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
141 RpcConnection_np *npc = (RpcConnection_np *) Connection;
142 TRACE("listening on %s\n", pname);
144 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
145 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
146 PIPE_UNLIMITED_INSTANCES,
147 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
148 if (npc->pipe == INVALID_HANDLE_VALUE) {
149 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
150 if (GetLastError() == ERROR_FILE_EXISTS)
151 return RPC_S_DUPLICATE_ENDPOINT;
152 else
153 return RPC_S_CANT_CREATE_ENDPOINT;
156 memset(&npc->ovl, 0, sizeof(npc->ovl));
157 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
159 /* Note: we don't call ConnectNamedPipe here because it must be done in the
160 * server thread as the thread must be alertable */
161 return RPC_S_OK;
164 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
166 RpcConnection_np *npc = (RpcConnection_np *) Connection;
167 HANDLE pipe;
168 DWORD err, dwMode;
170 TRACE("connecting to %s\n", pname);
172 while (TRUE) {
173 DWORD dwFlags = 0;
174 if (Connection->QOS)
176 dwFlags = SECURITY_SQOS_PRESENT;
177 switch (Connection->QOS->qos->ImpersonationType)
179 case RPC_C_IMP_LEVEL_DEFAULT:
180 /* FIXME: what to do here? */
181 break;
182 case RPC_C_IMP_LEVEL_ANONYMOUS:
183 dwFlags |= SECURITY_ANONYMOUS;
184 break;
185 case RPC_C_IMP_LEVEL_IDENTIFY:
186 dwFlags |= SECURITY_IDENTIFICATION;
187 break;
188 case RPC_C_IMP_LEVEL_IMPERSONATE:
189 dwFlags |= SECURITY_IMPERSONATION;
190 break;
191 case RPC_C_IMP_LEVEL_DELEGATE:
192 dwFlags |= SECURITY_DELEGATION;
193 break;
195 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
196 dwFlags |= SECURITY_CONTEXT_TRACKING;
198 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
199 OPEN_EXISTING, dwFlags, 0);
200 if (pipe != INVALID_HANDLE_VALUE) break;
201 err = GetLastError();
202 if (err == ERROR_PIPE_BUSY) {
203 TRACE("connection failed, error=%x\n", err);
204 return RPC_S_SERVER_TOO_BUSY;
206 if (!wait)
207 return RPC_S_SERVER_UNAVAILABLE;
208 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
209 err = GetLastError();
210 WARN("connection failed, error=%x\n", err);
211 return RPC_S_SERVER_UNAVAILABLE;
215 /* success */
216 memset(&npc->ovl, 0, sizeof(npc->ovl));
217 /* pipe is connected; change to message-read mode. */
218 dwMode = PIPE_READMODE_MESSAGE;
219 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
220 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
221 npc->pipe = pipe;
223 return RPC_S_OK;
226 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
228 RpcConnection_np *npc = (RpcConnection_np *) Connection;
229 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
230 RPC_STATUS r;
231 LPSTR pname;
233 /* already connected? */
234 if (npc->pipe)
235 return RPC_S_OK;
237 /* protseq=ncalrpc: supposed to use NT LPC ports,
238 * but we'll implement it with named pipes for now */
239 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
240 strcat(strcpy(pname, prefix), Connection->Endpoint);
241 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
242 I_RpcFree(pname);
244 return r;
247 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
249 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
250 RPC_STATUS r;
251 LPSTR pname;
252 RpcConnection *Connection;
254 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
255 endpoint, NULL, NULL, NULL, NULL);
256 if (r != RPC_S_OK)
257 return r;
259 /* protseq=ncalrpc: supposed to use NT LPC ports,
260 * but we'll implement it with named pipes for now */
261 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
262 strcat(strcpy(pname, prefix), Connection->Endpoint);
263 r = rpcrt4_conn_create_pipe(Connection, pname);
264 I_RpcFree(pname);
266 EnterCriticalSection(&protseq->cs);
267 Connection->Next = protseq->conn;
268 protseq->conn = Connection;
269 LeaveCriticalSection(&protseq->cs);
271 return r;
274 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
276 RpcConnection_np *npc = (RpcConnection_np *) Connection;
277 static const char prefix[] = "\\\\.";
278 RPC_STATUS r;
279 LPSTR pname;
281 /* already connected? */
282 if (npc->pipe)
283 return RPC_S_OK;
285 /* protseq=ncacn_np: named pipes */
286 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
287 strcat(strcpy(pname, prefix), Connection->Endpoint);
288 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
289 I_RpcFree(pname);
291 return r;
294 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
296 static const char prefix[] = "\\\\.";
297 RPC_STATUS r;
298 LPSTR pname;
299 RpcConnection *Connection;
301 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
302 endpoint, NULL, NULL, NULL, NULL);
303 if (r != RPC_S_OK)
304 return r;
306 /* protseq=ncacn_np: named pipes */
307 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
308 strcat(strcpy(pname, prefix), Connection->Endpoint);
309 r = rpcrt4_conn_create_pipe(Connection, pname);
310 I_RpcFree(pname);
312 EnterCriticalSection(&protseq->cs);
313 Connection->Next = protseq->conn;
314 protseq->conn = Connection;
315 LeaveCriticalSection(&protseq->cs);
317 return r;
320 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
322 /* because of the way named pipes work, we'll transfer the connected pipe
323 * to the child, then reopen the server binding to continue listening */
325 new_npc->pipe = old_npc->pipe;
326 new_npc->ovl = old_npc->ovl;
327 old_npc->pipe = 0;
328 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
329 old_npc->listening = FALSE;
332 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
334 RPC_STATUS status;
335 LPSTR pname;
336 static const char prefix[] = "\\\\.";
338 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
340 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
341 strcat(strcpy(pname, prefix), old_conn->Endpoint);
342 status = rpcrt4_conn_create_pipe(old_conn, pname);
343 I_RpcFree(pname);
345 return status;
348 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
350 RPC_STATUS status;
351 LPSTR pname;
352 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
354 TRACE("%s\n", old_conn->Endpoint);
356 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
358 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
359 strcat(strcpy(pname, prefix), old_conn->Endpoint);
360 status = rpcrt4_conn_create_pipe(old_conn, pname);
361 I_RpcFree(pname);
363 return status;
366 static int rpcrt4_conn_np_read(RpcConnection *Connection,
367 void *buffer, unsigned int count)
369 RpcConnection_np *npc = (RpcConnection_np *) Connection;
370 char *buf = buffer;
371 BOOL ret = TRUE;
372 unsigned int bytes_left = count;
374 while (bytes_left)
376 DWORD bytes_read;
377 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
378 if (!ret || !bytes_read)
379 break;
380 bytes_left -= bytes_read;
381 buf += bytes_read;
383 return ret ? count : -1;
386 static int rpcrt4_conn_np_write(RpcConnection *Connection,
387 const void *buffer, unsigned int count)
389 RpcConnection_np *npc = (RpcConnection_np *) Connection;
390 const char *buf = buffer;
391 BOOL ret = TRUE;
392 unsigned int bytes_left = count;
394 while (bytes_left)
396 DWORD bytes_written;
397 ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
398 if (!ret || !bytes_written)
399 break;
400 bytes_left -= bytes_written;
401 buf += bytes_written;
403 return ret ? count : -1;
406 static int rpcrt4_conn_np_close(RpcConnection *Connection)
408 RpcConnection_np *npc = (RpcConnection_np *) Connection;
409 if (npc->pipe) {
410 FlushFileBuffers(npc->pipe);
411 CloseHandle(npc->pipe);
412 npc->pipe = 0;
414 if (npc->ovl.hEvent) {
415 CloseHandle(npc->ovl.hEvent);
416 npc->ovl.hEvent = 0;
418 return 0;
421 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
422 const char *networkaddr,
423 const char *endpoint)
425 twr_empty_floor_t *smb_floor;
426 twr_empty_floor_t *nb_floor;
427 size_t size;
428 size_t networkaddr_size;
429 size_t endpoint_size;
431 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
433 networkaddr_size = strlen(networkaddr) + 1;
434 endpoint_size = strlen(endpoint) + 1;
435 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
437 if (!tower_data)
438 return size;
440 smb_floor = (twr_empty_floor_t *)tower_data;
442 tower_data += sizeof(*smb_floor);
444 smb_floor->count_lhs = sizeof(smb_floor->protid);
445 smb_floor->protid = EPM_PROTOCOL_SMB;
446 smb_floor->count_rhs = endpoint_size;
448 memcpy(tower_data, endpoint, endpoint_size);
449 tower_data += endpoint_size;
451 nb_floor = (twr_empty_floor_t *)tower_data;
453 tower_data += sizeof(*nb_floor);
455 nb_floor->count_lhs = sizeof(nb_floor->protid);
456 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
457 nb_floor->count_rhs = networkaddr_size;
459 memcpy(tower_data, networkaddr, networkaddr_size);
460 tower_data += networkaddr_size;
462 return size;
465 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
466 size_t tower_size,
467 char **networkaddr,
468 char **endpoint)
470 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
471 const twr_empty_floor_t *nb_floor;
473 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
475 if (tower_size < sizeof(*smb_floor))
476 return EPT_S_NOT_REGISTERED;
478 tower_data += sizeof(*smb_floor);
479 tower_size -= sizeof(*smb_floor);
481 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
482 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
483 (smb_floor->count_rhs > tower_size))
484 return EPT_S_NOT_REGISTERED;
486 if (endpoint)
488 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
489 if (!*endpoint)
490 return RPC_S_OUT_OF_RESOURCES;
491 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
493 tower_data += smb_floor->count_rhs;
494 tower_size -= smb_floor->count_rhs;
496 if (tower_size < sizeof(*nb_floor))
497 return EPT_S_NOT_REGISTERED;
499 nb_floor = (const twr_empty_floor_t *)tower_data;
501 tower_data += sizeof(*nb_floor);
502 tower_size -= sizeof(*nb_floor);
504 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
505 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
506 (nb_floor->count_rhs > tower_size))
507 return EPT_S_NOT_REGISTERED;
509 if (networkaddr)
511 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
512 if (!*networkaddr)
514 if (endpoint)
516 I_RpcFree(*endpoint);
517 *endpoint = NULL;
519 return RPC_S_OUT_OF_RESOURCES;
521 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
524 return RPC_S_OK;
527 typedef struct _RpcServerProtseq_np
529 RpcServerProtseq common;
530 HANDLE mgr_event;
531 } RpcServerProtseq_np;
533 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
535 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
536 if (ps)
537 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
538 return &ps->common;
541 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
543 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
544 SetEvent(npps->mgr_event);
547 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
549 HANDLE *objs = prev_array;
550 RpcConnection_np *conn;
551 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
553 EnterCriticalSection(&protseq->cs);
555 /* open and count connections */
556 *count = 1;
557 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
558 while (conn) {
559 rpcrt4_conn_listen_pipe(conn);
560 if (conn->ovl.hEvent)
561 (*count)++;
562 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
565 /* make array of connections */
566 if (objs)
567 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
568 else
569 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
570 if (!objs)
572 ERR("couldn't allocate objs\n");
573 LeaveCriticalSection(&protseq->cs);
574 return NULL;
577 objs[0] = npps->mgr_event;
578 *count = 1;
579 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
580 while (conn) {
581 if ((objs[*count] = conn->ovl.hEvent))
582 (*count)++;
583 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
585 LeaveCriticalSection(&protseq->cs);
586 return objs;
589 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
591 HeapFree(GetProcessHeap(), 0, array);
594 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
596 HANDLE b_handle;
597 HANDLE *objs = wait_array;
598 DWORD res;
599 RpcConnection *cconn;
600 RpcConnection_np *conn;
602 if (!objs)
603 return -1;
605 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
606 if (res == WAIT_OBJECT_0)
607 return 0;
608 else if (res == WAIT_FAILED)
610 ERR("wait failed with error %d\n", GetLastError());
611 return -1;
613 else
615 b_handle = objs[res - WAIT_OBJECT_0];
616 /* find which connection got a RPC */
617 EnterCriticalSection(&protseq->cs);
618 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
619 while (conn) {
620 if (b_handle == conn->ovl.hEvent) break;
621 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
623 cconn = NULL;
624 if (conn)
625 RPCRT4_SpawnConnection(&cconn, &conn->common);
626 else
627 ERR("failed to locate connection for handle %p\n", b_handle);
628 LeaveCriticalSection(&protseq->cs);
629 if (cconn)
631 RPCRT4_new_client(cconn);
632 return 1;
634 else return -1;
638 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
639 const char *networkaddr,
640 const char *endpoint)
642 twr_empty_floor_t *pipe_floor;
643 size_t size;
644 size_t endpoint_size;
646 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
648 endpoint_size = strlen(networkaddr) + 1;
649 size = sizeof(*pipe_floor) + endpoint_size;
651 if (!tower_data)
652 return size;
654 pipe_floor = (twr_empty_floor_t *)tower_data;
656 tower_data += sizeof(*pipe_floor);
658 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
659 pipe_floor->protid = EPM_PROTOCOL_SMB;
660 pipe_floor->count_rhs = endpoint_size;
662 memcpy(tower_data, endpoint, endpoint_size);
663 tower_data += endpoint_size;
665 return size;
668 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
669 size_t tower_size,
670 char **networkaddr,
671 char **endpoint)
673 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
675 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
677 *networkaddr = NULL;
678 *endpoint = NULL;
680 if (tower_size < sizeof(*pipe_floor))
681 return EPT_S_NOT_REGISTERED;
683 tower_data += sizeof(*pipe_floor);
684 tower_size -= sizeof(*pipe_floor);
686 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
687 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
688 (pipe_floor->count_rhs > tower_size))
689 return EPT_S_NOT_REGISTERED;
691 if (endpoint)
693 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
694 if (!*endpoint)
695 return RPC_S_OUT_OF_RESOURCES;
696 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
699 return RPC_S_OK;
702 /**** ncacn_ip_tcp support ****/
704 typedef struct _RpcConnection_tcp
706 RpcConnection common;
707 int sock;
708 } RpcConnection_tcp;
710 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
712 RpcConnection_tcp *tcpc;
713 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
714 if (tcpc == NULL)
715 return NULL;
716 tcpc->sock = -1;
717 return &tcpc->common;
720 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
722 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
723 int sock;
724 int ret;
725 struct addrinfo *ai;
726 struct addrinfo *ai_cur;
727 struct addrinfo hints;
729 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
731 if (tcpc->sock != -1)
732 return RPC_S_OK;
734 hints.ai_flags = 0;
735 hints.ai_family = PF_UNSPEC;
736 hints.ai_socktype = SOCK_STREAM;
737 hints.ai_protocol = IPPROTO_TCP;
738 hints.ai_addrlen = 0;
739 hints.ai_addr = NULL;
740 hints.ai_canonname = NULL;
741 hints.ai_next = NULL;
743 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
744 if (ret)
746 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
747 Connection->Endpoint, gai_strerror(ret));
748 return RPC_S_SERVER_UNAVAILABLE;
751 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
753 int val;
755 if (TRACE_ON(rpc))
757 char host[256];
758 char service[256];
759 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
760 host, sizeof(host), service, sizeof(service),
761 NI_NUMERICHOST | NI_NUMERICSERV);
762 TRACE("trying %s:%s\n", host, service);
765 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
766 if (sock < 0)
768 WARN("socket() failed: %s\n", strerror(errno));
769 continue;
772 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
774 WARN("connect() failed: %s\n", strerror(errno));
775 close(sock);
776 continue;
779 /* RPC depends on having minimal latency so disable the Nagle algorithm */
780 val = 1;
781 setsockopt(sock, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
783 tcpc->sock = sock;
785 freeaddrinfo(ai);
786 TRACE("connected\n");
787 return RPC_S_OK;
790 freeaddrinfo(ai);
791 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
792 return RPC_S_SERVER_UNAVAILABLE;
795 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
797 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
798 int sock;
799 int ret;
800 struct addrinfo *ai;
801 struct addrinfo *ai_cur;
802 struct addrinfo hints;
803 RpcConnection *first_connection = NULL;
805 TRACE("(%p, %s)\n", protseq, endpoint);
807 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
808 hints.ai_family = PF_UNSPEC;
809 hints.ai_socktype = SOCK_STREAM;
810 hints.ai_protocol = IPPROTO_TCP;
811 hints.ai_addrlen = 0;
812 hints.ai_addr = NULL;
813 hints.ai_canonname = NULL;
814 hints.ai_next = NULL;
816 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
817 if (ret)
819 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
820 gai_strerror(ret));
821 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
822 return RPC_S_INVALID_ENDPOINT_FORMAT;
823 return RPC_S_CANT_CREATE_ENDPOINT;
826 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
828 RpcConnection_tcp *tcpc;
829 RPC_STATUS create_status;
831 if (TRACE_ON(rpc))
833 char host[256];
834 char service[256];
835 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
836 host, sizeof(host), service, sizeof(service),
837 NI_NUMERICHOST | NI_NUMERICSERV);
838 TRACE("trying %s:%s\n", host, service);
841 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
842 if (sock < 0)
844 WARN("socket() failed: %s\n", strerror(errno));
845 status = RPC_S_CANT_CREATE_ENDPOINT;
846 continue;
849 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
850 if (ret < 0)
852 WARN("bind failed: %s\n", strerror(errno));
853 close(sock);
854 if (errno == EADDRINUSE)
855 status = RPC_S_DUPLICATE_ENDPOINT;
856 else
857 status = RPC_S_CANT_CREATE_ENDPOINT;
858 continue;
860 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
861 protseq->Protseq, NULL,
862 endpoint, NULL, NULL, NULL,
863 NULL);
864 if (create_status != RPC_S_OK)
866 close(sock);
867 status = create_status;
868 continue;
871 tcpc->sock = sock;
872 ret = listen(sock, protseq->MaxCalls);
873 if (ret < 0)
875 WARN("listen failed: %s\n", strerror(errno));
876 RPCRT4_DestroyConnection(&tcpc->common);
877 status = RPC_S_OUT_OF_RESOURCES;
878 continue;
880 /* need a non-blocking socket, otherwise accept() has a potential
881 * race-condition (poll() says it is readable, connection drops,
882 * and accept() blocks until the next connection comes...)
884 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
885 if (ret < 0)
887 WARN("couldn't make socket non-blocking, error %d\n", ret);
888 RPCRT4_DestroyConnection(&tcpc->common);
889 status = RPC_S_OUT_OF_RESOURCES;
890 continue;
893 tcpc->common.Next = first_connection;
894 first_connection = &tcpc->common;
897 freeaddrinfo(ai);
899 /* if at least one connection was created for an endpoint then
900 * return success */
901 if (first_connection)
903 RpcConnection *conn;
905 /* find last element in list */
906 for (conn = first_connection; conn->Next; conn = conn->Next)
909 EnterCriticalSection(&protseq->cs);
910 conn->Next = protseq->conn;
911 protseq->conn = first_connection;
912 LeaveCriticalSection(&protseq->cs);
914 TRACE("listening on %s\n", endpoint);
915 return RPC_S_OK;
918 ERR("couldn't listen on port %s\n", endpoint);
919 return status;
922 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
924 int ret;
925 struct sockaddr_in address;
926 socklen_t addrsize;
927 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
928 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
930 addrsize = sizeof(address);
931 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
932 if (ret < 0)
934 ERR("Failed to accept a TCP connection: error %d\n", ret);
935 return RPC_S_OUT_OF_RESOURCES;
937 /* reset to blocking behaviour */
938 fcntl(ret, F_SETFL, 0);
939 client->sock = ret;
940 TRACE("Accepted a new TCP connection\n");
941 return RPC_S_OK;
944 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
945 void *buffer, unsigned int count)
947 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
948 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
949 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
950 return r;
953 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
954 const void *buffer, unsigned int count)
956 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
957 int r = write(tcpc->sock, buffer, count);
958 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
959 return r;
962 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
964 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
966 TRACE("%d\n", tcpc->sock);
968 if (tcpc->sock != -1)
969 close(tcpc->sock);
970 tcpc->sock = -1;
971 return 0;
974 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
975 const char *networkaddr,
976 unsigned char tcp_protid,
977 const char *endpoint)
979 twr_tcp_floor_t *tcp_floor;
980 twr_ipv4_floor_t *ipv4_floor;
981 struct addrinfo *ai;
982 struct addrinfo hints;
983 int ret;
984 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
986 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
988 if (!tower_data)
989 return size;
991 tcp_floor = (twr_tcp_floor_t *)tower_data;
992 tower_data += sizeof(*tcp_floor);
994 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
996 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
997 tcp_floor->protid = tcp_protid;
998 tcp_floor->count_rhs = sizeof(tcp_floor->port);
1000 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
1001 ipv4_floor->protid = EPM_PROTOCOL_IP;
1002 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
1004 hints.ai_flags = AI_NUMERICHOST;
1005 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
1006 hints.ai_family = PF_INET;
1007 hints.ai_socktype = SOCK_STREAM;
1008 hints.ai_protocol = IPPROTO_TCP;
1009 hints.ai_addrlen = 0;
1010 hints.ai_addr = NULL;
1011 hints.ai_canonname = NULL;
1012 hints.ai_next = NULL;
1014 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
1015 if (ret)
1017 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
1018 if (ret)
1020 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1021 return 0;
1025 if (ai->ai_family == PF_INET)
1027 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1028 tcp_floor->port = sin->sin_port;
1029 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1031 else
1033 ERR("unexpected protocol family %d\n", ai->ai_family);
1034 return 0;
1037 freeaddrinfo(ai);
1039 return size;
1042 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1043 const char *networkaddr,
1044 const char *endpoint)
1046 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1047 EPM_PROTOCOL_TCP, endpoint);
1050 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1051 size_t tower_size,
1052 char **networkaddr,
1053 unsigned char tcp_protid,
1054 char **endpoint)
1056 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1057 const twr_ipv4_floor_t *ipv4_floor;
1058 struct in_addr in_addr;
1060 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1062 if (tower_size < sizeof(*tcp_floor))
1063 return EPT_S_NOT_REGISTERED;
1065 tower_data += sizeof(*tcp_floor);
1066 tower_size -= sizeof(*tcp_floor);
1068 if (tower_size < sizeof(*ipv4_floor))
1069 return EPT_S_NOT_REGISTERED;
1071 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1073 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1074 (tcp_floor->protid != tcp_protid) ||
1075 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1076 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1077 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1078 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1079 return EPT_S_NOT_REGISTERED;
1081 if (endpoint)
1083 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1084 if (!*endpoint)
1085 return RPC_S_OUT_OF_RESOURCES;
1086 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1089 if (networkaddr)
1091 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1092 if (!*networkaddr)
1094 if (endpoint)
1096 I_RpcFree(*endpoint);
1097 *endpoint = NULL;
1099 return RPC_S_OUT_OF_RESOURCES;
1101 in_addr.s_addr = ipv4_floor->ipv4addr;
1102 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1104 ERR("inet_ntop: %s\n", strerror(errno));
1105 I_RpcFree(*networkaddr);
1106 *networkaddr = NULL;
1107 if (endpoint)
1109 I_RpcFree(*endpoint);
1110 *endpoint = NULL;
1112 return EPT_S_NOT_REGISTERED;
1116 return RPC_S_OK;
1119 typedef struct _RpcServerProtseq_sock
1121 RpcServerProtseq common;
1122 int mgr_event_rcv;
1123 int mgr_event_snd;
1124 } RpcServerProtseq_sock;
1126 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1128 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1129 if (ps)
1131 int fds[2];
1132 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1134 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1135 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1136 ps->mgr_event_rcv = fds[0];
1137 ps->mgr_event_snd = fds[1];
1139 else
1141 ERR("socketpair failed with error %s\n", strerror(errno));
1142 HeapFree(GetProcessHeap(), 0, ps);
1143 return NULL;
1146 return &ps->common;
1149 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1151 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1152 char dummy = 1;
1153 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1156 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1158 struct pollfd *poll_info = prev_array;
1159 RpcConnection_tcp *conn;
1160 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1162 EnterCriticalSection(&protseq->cs);
1164 /* open and count connections */
1165 *count = 1;
1166 conn = (RpcConnection_tcp *)protseq->conn;
1167 while (conn) {
1168 if (conn->sock != -1)
1169 (*count)++;
1170 conn = (RpcConnection_tcp *)conn->common.Next;
1173 /* make array of connections */
1174 if (poll_info)
1175 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1176 else
1177 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1178 if (!poll_info)
1180 ERR("couldn't allocate poll_info\n");
1181 LeaveCriticalSection(&protseq->cs);
1182 return NULL;
1185 poll_info[0].fd = sockps->mgr_event_rcv;
1186 poll_info[0].events = POLLIN;
1187 *count = 1;
1188 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1189 while (conn) {
1190 if (conn->sock != -1)
1192 poll_info[*count].fd = conn->sock;
1193 poll_info[*count].events = POLLIN;
1194 (*count)++;
1196 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1198 LeaveCriticalSection(&protseq->cs);
1199 return poll_info;
1202 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1204 HeapFree(GetProcessHeap(), 0, array);
1207 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1209 struct pollfd *poll_info = wait_array;
1210 int ret, i;
1211 RpcConnection *cconn;
1212 RpcConnection_tcp *conn;
1214 if (!poll_info)
1215 return -1;
1217 ret = poll(poll_info, count, -1);
1218 if (ret < 0)
1220 ERR("poll failed with error %d\n", ret);
1221 return -1;
1224 for (i = 0; i < count; i++)
1225 if (poll_info[i].revents & POLLIN)
1227 /* RPC server event */
1228 if (i == 0)
1230 char dummy;
1231 read(poll_info[0].fd, &dummy, sizeof(dummy));
1232 return 0;
1235 /* find which connection got a RPC */
1236 EnterCriticalSection(&protseq->cs);
1237 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1238 while (conn) {
1239 if (poll_info[i].fd == conn->sock) break;
1240 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1242 cconn = NULL;
1243 if (conn)
1244 RPCRT4_SpawnConnection(&cconn, &conn->common);
1245 else
1246 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1247 LeaveCriticalSection(&protseq->cs);
1248 if (cconn)
1249 RPCRT4_new_client(cconn);
1250 else
1251 return -1;
1254 return 1;
1257 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1258 size_t tower_size,
1259 char **networkaddr,
1260 char **endpoint)
1262 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1263 networkaddr, EPM_PROTOCOL_TCP,
1264 endpoint);
1267 /**** ncacn_http support ****/
1269 /* 60 seconds is the period native uses */
1270 #define HTTP_IDLE_TIME 60000
1272 typedef struct _RpcConnection_http
1274 RpcConnection common;
1275 HINTERNET in_request;
1276 HINTERNET out_request;
1277 HANDLE timer_cancelled;
1278 DWORD last_sent_time;
1279 ULONG bytes_received;
1280 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1281 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1282 UUID connection_uuid;
1283 UUID in_pipe_uuid;
1284 UUID out_pipe_uuid;
1285 } RpcConnection_http;
1287 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1289 RpcConnection_http *httpc;
1290 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1291 return &httpc->common;
1294 typedef struct _HttpTimerThreadData
1296 PVOID timer_param;
1297 DWORD *last_sent_time;
1298 HANDLE timer_cancelled;
1299 } HttpTimerThreadData;
1301 static VOID CALLBACK rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1303 HINTERNET in_request = param;
1304 RpcPktHdr *idle_pkt;
1306 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1307 0, 0);
1308 if (idle_pkt)
1310 DWORD bytes_written;
1311 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1312 RPCRT4_FreeHeader(idle_pkt);
1316 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1318 DWORD cur_time = GetTickCount();
1319 DWORD cached_last_sent_time = *last_sent_time;
1320 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1323 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1325 HttpTimerThreadData *data_in = param;
1326 HttpTimerThreadData data;
1327 DWORD timeout;
1329 data = *data_in;
1330 HeapFree(GetProcessHeap(), 0, data_in);
1332 for (timeout = HTTP_IDLE_TIME;
1333 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1334 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1336 /* are we too soon after last send? */
1337 if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time)
1338 continue;
1339 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1342 CloseHandle(data.timer_cancelled);
1343 return 0;
1346 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1348 BOOL ret;
1349 DWORD status_code;
1350 DWORD size;
1351 DWORD index;
1352 WCHAR status_text[32];
1354 TRACE("\n");
1356 index = 0;
1357 size = sizeof(status_code);
1358 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1359 if (!ret)
1360 return GetLastError();
1361 if (status_code < 400)
1362 return RPC_S_OK;
1363 index = 0;
1364 size = sizeof(status_text);
1365 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1366 if (!ret)
1367 return GetLastError();
1368 ERR("server returned: %d %s\n", status_code, debugstr_w(status_text));
1369 if (status_code == HTTP_STATUS_DENIED)
1370 return ERROR_ACCESS_DENIED;
1371 return RPC_S_SERVER_UNAVAILABLE;
1374 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc, HINTERNET *hi, HINTERNET *hic)
1376 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
1377 LPWSTR proxy = NULL;
1378 LPWSTR user = NULL;
1379 LPWSTR password = NULL;
1380 LPWSTR servername = NULL;
1381 const WCHAR *option;
1382 INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */
1384 *hic = NULL;
1386 if (httpc->common.QOS &&
1387 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1389 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1390 if (http_cred->TransportCredentials)
1392 WCHAR *p;
1393 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1394 ULONG len = cred->DomainLength + 1 + cred->UserLength;
1395 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1396 if (!user)
1397 return RPC_S_OUT_OF_RESOURCES;
1398 p = user;
1399 if (cred->DomainLength)
1401 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1402 p += cred->DomainLength;
1403 *p = '\\';
1404 p++;
1406 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1407 p[cred->UserLength] = 0;
1409 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1413 for (option = httpc->common.NetworkOptions; option;
1414 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
1416 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
1417 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
1419 if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
1421 const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
1422 const WCHAR *value_end;
1423 const WCHAR *p;
1425 value_end = strchrW(option, ',');
1426 if (!value_end)
1427 value_end = value_start + strlenW(value_start);
1428 for (p = value_start; p < value_end; p++)
1429 if (*p == ':')
1431 port = atoiW(p+1);
1432 value_end = p;
1433 break;
1435 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1436 servername = RPCRT4_strndupW(value_start, value_end-value_start);
1438 else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
1440 const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
1441 const WCHAR *value_end;
1443 value_end = strchrW(option, ',');
1444 if (!value_end)
1445 value_end = value_start + strlenW(value_start);
1446 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1447 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
1449 else
1450 FIXME("unhandled option %s\n", debugstr_w(option));
1453 *hi = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
1454 if (!*hi)
1456 HeapFree(GetProcessHeap(), 0, password);
1457 HeapFree(GetProcessHeap(), 0, user);
1458 ERR("InternetOpenW failed with error %d\n", GetLastError());
1459 return RPC_S_SERVER_UNAVAILABLE;
1462 /* if no RpcProxy option specified, set the HTTP server address to the
1463 * RPC server address */
1464 if (!servername)
1466 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
1467 if (!servername)
1469 HeapFree(GetProcessHeap(), 0, password);
1470 HeapFree(GetProcessHeap(), 0, user);
1471 return RPC_S_OUT_OF_RESOURCES;
1473 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
1476 *hic = InternetConnectW(*hi, servername, port, user, password,
1477 INTERNET_SERVICE_HTTP, 0, 0);
1479 HeapFree(GetProcessHeap(), 0, password);
1480 HeapFree(GetProcessHeap(), 0, user);
1481 HeapFree(GetProcessHeap(), 0, servername);
1483 if (!*hic)
1485 InternetCloseHandle(*hi);
1486 ERR("InternetConnectW failed with error %d\n", GetLastError());
1487 return RPC_S_SERVER_UNAVAILABLE;
1490 return RPC_S_OK;
1493 /* prepare the in pipe for use by RPC packets */
1494 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, const UUID *connection_uuid, const UUID *in_pipe_uuid)
1496 BYTE packet[44];
1497 BOOL ret;
1498 RPC_STATUS status;
1499 RpcPktHdr *hdr;
1500 INTERNET_BUFFERSW buffers_in;
1501 DWORD bytes_read, bytes_written;
1503 /* prepare in pipe */
1504 ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0);
1505 if (!ret)
1507 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
1508 return RPC_S_SERVER_UNAVAILABLE;
1510 status = rpcrt4_http_check_response(in_request);
1511 if (status != RPC_S_OK) return status;
1513 InternetReadFile(in_request, packet, 20, &bytes_read);
1514 /* FIXME: do something with retrieved data */
1516 memset(&buffers_in, 0, sizeof(buffers_in));
1517 buffers_in.dwStructSize = sizeof(buffers_in);
1518 /* FIXME: get this from the registry */
1519 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
1520 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
1521 if (!ret)
1523 ERR("HttpSendRequestExW failed with error %d\n", GetLastError());
1524 return RPC_S_SERVER_UNAVAILABLE;
1527 TRACE("sending HTTP connect header to server\n");
1528 hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid);
1529 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
1530 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
1531 RPCRT4_FreeHeader(hdr);
1532 if (!ret)
1534 ERR("InternetWriteFile failed with error %d\n", GetLastError());
1535 return RPC_S_SERVER_UNAVAILABLE;
1538 return RPC_S_OK;
1541 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data)
1543 BOOL ret;
1544 DWORD bytes_read;
1545 unsigned short data_len;
1547 ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read);
1548 if (!ret)
1549 return RPC_S_SERVER_UNAVAILABLE;
1550 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
1552 ERR("wrong packet type received %d or wrong frag_len %d\n",
1553 hdr->common.ptype, hdr->common.frag_len);
1554 return RPC_S_PROTOCOL_ERROR;
1557 ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read);
1558 if (!ret)
1559 return RPC_S_SERVER_UNAVAILABLE;
1561 data_len = hdr->common.frag_len - sizeof(hdr->http);
1562 if (data_len)
1564 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
1565 if (!*data)
1566 return RPC_S_OUT_OF_RESOURCES;
1567 ret = InternetReadFile(request, *data, data_len, &bytes_read);
1568 if (!ret)
1570 HeapFree(GetProcessHeap(), 0, *data);
1571 return RPC_S_SERVER_UNAVAILABLE;
1574 else
1575 *data = NULL;
1577 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
1579 ERR("invalid http packet\n");
1580 return RPC_S_PROTOCOL_ERROR;
1583 return RPC_S_OK;
1586 /* prepare the out pipe for use by RPC packets */
1587 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
1588 const UUID *connection_uuid,
1589 const UUID *out_pipe_uuid,
1590 ULONG *flow_control_increment)
1592 BYTE packet[20];
1593 BOOL ret;
1594 RPC_STATUS status;
1595 RpcPktHdr *hdr;
1596 DWORD bytes_read;
1597 BYTE *data_from_server;
1598 RpcPktHdr pkt_from_server;
1599 ULONG field1, field3;
1601 ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0);
1602 if (!ret)
1604 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
1605 return RPC_S_SERVER_UNAVAILABLE;
1607 status = rpcrt4_http_check_response(out_request);
1608 if (status != RPC_S_OK) return status;
1610 InternetReadFile(out_request, packet, 20, &bytes_read);
1611 /* FIXME: do something with retrieved data */
1613 hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid);
1614 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
1615 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
1616 RPCRT4_FreeHeader(hdr);
1617 if (!ret)
1619 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
1620 return RPC_S_SERVER_UNAVAILABLE;
1622 status = rpcrt4_http_check_response(out_request);
1623 if (status != RPC_S_OK) return status;
1625 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
1626 &data_from_server);
1627 if (status != RPC_S_OK) return status;
1628 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
1629 &field1);
1630 HeapFree(GetProcessHeap(), 0, data_from_server);
1631 if (status != RPC_S_OK) return status;
1632 TRACE("received (%d) from first prepare header\n", field1);
1634 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
1635 &data_from_server);
1636 if (status != RPC_S_OK) return status;
1637 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
1638 &field1, flow_control_increment,
1639 &field3);
1640 HeapFree(GetProcessHeap(), 0, data_from_server);
1641 if (status != RPC_S_OK) return status;
1642 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
1644 return RPC_S_OK;
1647 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
1649 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
1650 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
1651 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
1652 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
1653 static const WCHAR wszColon[] = {':',0};
1654 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
1655 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
1656 HINTERNET hi;
1657 HINTERNET hic;
1658 WCHAR *url;
1659 RPC_STATUS status;
1660 BOOL secure;
1661 HttpTimerThreadData *timer_data;
1662 HANDLE thread;
1664 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1666 if (Connection->server)
1668 ERR("ncacn_http servers not supported yet\n");
1669 return RPC_S_SERVER_UNAVAILABLE;
1672 if (httpc->in_request)
1673 return RPC_S_OK;
1675 status = UuidCreate(&httpc->connection_uuid);
1676 status = UuidCreate(&httpc->in_pipe_uuid);
1677 status = UuidCreate(&httpc->out_pipe_uuid);
1679 status = rpcrt4_http_internet_connect(httpc, &hi, &hic);
1680 if (status != RPC_S_OK)
1681 return status;
1682 InternetCloseHandle(hi);
1684 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
1685 if (!url)
1687 InternetCloseHandle(hic);
1688 return RPC_S_OUT_OF_MEMORY;
1690 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
1691 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
1692 strcatW(url, wszColon);
1693 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
1695 secure = httpc->common.QOS &&
1696 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
1697 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
1699 httpc->in_request = HttpOpenRequestW(hic, wszVerbIn, url, NULL, NULL,
1700 wszAcceptTypes,
1701 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
1703 if (!httpc->in_request)
1705 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
1706 InternetCloseHandle(hic);
1707 return RPC_S_SERVER_UNAVAILABLE;
1709 httpc->out_request = HttpOpenRequestW(hic, wszVerbOut, url, NULL, NULL,
1710 wszAcceptTypes,
1711 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
1713 InternetCloseHandle(hic);
1714 if (!httpc->in_request)
1716 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
1717 InternetCloseHandle(httpc->in_request);
1718 httpc->in_request = NULL;
1719 return RPC_S_SERVER_UNAVAILABLE;
1722 status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
1723 &httpc->connection_uuid,
1724 &httpc->in_pipe_uuid);
1725 if (status != RPC_S_OK)
1726 goto error;
1728 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, &httpc->connection_uuid,
1729 &httpc->out_pipe_uuid,
1730 &httpc->flow_control_increment);
1731 if (status != RPC_S_OK)
1732 goto error;
1734 httpc->flow_control_mark = httpc->flow_control_increment / 2;
1735 httpc->last_sent_time = GetTickCount();
1736 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
1738 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
1739 timer_data->timer_param = httpc->in_request;
1740 timer_data->last_sent_time = &httpc->last_sent_time;
1741 timer_data->timer_cancelled = httpc->timer_cancelled;
1742 /* FIXME: should use CreateTimerQueueTimer when implemented */
1743 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
1744 CloseHandle(thread);
1746 return RPC_S_OK;
1748 error:
1749 InternetCloseHandle(httpc->in_request);
1750 httpc->in_request = NULL;
1751 InternetCloseHandle(httpc->out_request);
1752 httpc->out_request = NULL;
1753 return status;
1756 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1758 assert(0);
1759 return RPC_S_SERVER_UNAVAILABLE;
1762 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
1763 void *buffer, unsigned int count)
1765 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
1766 char *buf = buffer;
1767 BOOL ret = TRUE;
1768 unsigned int bytes_left = count;
1770 while (bytes_left)
1772 DWORD bytes_read;
1773 ret = InternetReadFile(httpc->out_request, buf, bytes_left, &bytes_read);
1774 if (!ret || !bytes_read)
1775 break;
1776 bytes_left -= bytes_read;
1777 buf += bytes_read;
1779 TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE");
1780 if (ret) httpc->bytes_received += count;
1782 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
1783 /* FIXME: we should be more careful not to send this packet in the middle of receiving a fragment */
1784 if (httpc->bytes_received > httpc->flow_control_mark)
1786 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
1787 httpc->bytes_received,
1788 httpc->flow_control_increment,
1789 &httpc->out_pipe_uuid);
1790 if (hdr)
1792 DWORD bytes_written;
1793 BOOL ret2;
1794 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
1795 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
1796 RPCRT4_FreeHeader(hdr);
1797 if (ret2)
1798 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
1801 return ret ? count : -1;
1804 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
1805 const void *buffer, unsigned int count)
1807 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
1808 DWORD bytes_written;
1809 BOOL ret;
1811 httpc->last_sent_time = ~0UL; /* disable idle packet sending */
1812 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
1813 httpc->last_sent_time = GetTickCount();
1814 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
1815 return ret ? bytes_written : -1;
1818 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
1820 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
1822 TRACE("\n");
1824 SetEvent(httpc->timer_cancelled);
1825 if (httpc->in_request)
1826 InternetCloseHandle(httpc->in_request);
1827 httpc->in_request = NULL;
1828 if (httpc->out_request)
1829 InternetCloseHandle(httpc->out_request);
1830 httpc->out_request = NULL;
1832 return 0;
1835 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
1836 const char *networkaddr,
1837 const char *endpoint)
1839 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1840 EPM_PROTOCOL_HTTP, endpoint);
1843 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
1844 size_t tower_size,
1845 char **networkaddr,
1846 char **endpoint)
1848 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1849 networkaddr, EPM_PROTOCOL_HTTP,
1850 endpoint);
1853 static const struct connection_ops conn_protseq_list[] = {
1854 { "ncacn_np",
1855 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1856 rpcrt4_conn_np_alloc,
1857 rpcrt4_ncacn_np_open,
1858 rpcrt4_ncacn_np_handoff,
1859 rpcrt4_conn_np_read,
1860 rpcrt4_conn_np_write,
1861 rpcrt4_conn_np_close,
1862 rpcrt4_ncacn_np_get_top_of_tower,
1863 rpcrt4_ncacn_np_parse_top_of_tower,
1865 { "ncalrpc",
1866 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1867 rpcrt4_conn_np_alloc,
1868 rpcrt4_ncalrpc_open,
1869 rpcrt4_ncalrpc_handoff,
1870 rpcrt4_conn_np_read,
1871 rpcrt4_conn_np_write,
1872 rpcrt4_conn_np_close,
1873 rpcrt4_ncalrpc_get_top_of_tower,
1874 rpcrt4_ncalrpc_parse_top_of_tower,
1876 { "ncacn_ip_tcp",
1877 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1878 rpcrt4_conn_tcp_alloc,
1879 rpcrt4_ncacn_ip_tcp_open,
1880 rpcrt4_conn_tcp_handoff,
1881 rpcrt4_conn_tcp_read,
1882 rpcrt4_conn_tcp_write,
1883 rpcrt4_conn_tcp_close,
1884 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1885 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1887 { "ncacn_http",
1888 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
1889 rpcrt4_ncacn_http_alloc,
1890 rpcrt4_ncacn_http_open,
1891 rpcrt4_ncacn_http_handoff,
1892 rpcrt4_ncacn_http_read,
1893 rpcrt4_ncacn_http_write,
1894 rpcrt4_ncacn_http_close,
1895 rpcrt4_ncacn_http_get_top_of_tower,
1896 rpcrt4_ncacn_http_parse_top_of_tower,
1901 static const struct protseq_ops protseq_list[] =
1904 "ncacn_np",
1905 rpcrt4_protseq_np_alloc,
1906 rpcrt4_protseq_np_signal_state_changed,
1907 rpcrt4_protseq_np_get_wait_array,
1908 rpcrt4_protseq_np_free_wait_array,
1909 rpcrt4_protseq_np_wait_for_new_connection,
1910 rpcrt4_protseq_ncacn_np_open_endpoint,
1913 "ncalrpc",
1914 rpcrt4_protseq_np_alloc,
1915 rpcrt4_protseq_np_signal_state_changed,
1916 rpcrt4_protseq_np_get_wait_array,
1917 rpcrt4_protseq_np_free_wait_array,
1918 rpcrt4_protseq_np_wait_for_new_connection,
1919 rpcrt4_protseq_ncalrpc_open_endpoint,
1922 "ncacn_ip_tcp",
1923 rpcrt4_protseq_sock_alloc,
1924 rpcrt4_protseq_sock_signal_state_changed,
1925 rpcrt4_protseq_sock_get_wait_array,
1926 rpcrt4_protseq_sock_free_wait_array,
1927 rpcrt4_protseq_sock_wait_for_new_connection,
1928 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1932 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1934 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1936 int i;
1937 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1938 if (!strcmp(protseq_list[i].name, protseq))
1939 return &protseq_list[i];
1940 return NULL;
1943 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1945 int i;
1946 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1947 if (!strcmp(conn_protseq_list[i].name, protseq))
1948 return &conn_protseq_list[i];
1949 return NULL;
1952 /**** interface to rest of code ****/
1954 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1956 TRACE("(Connection == ^%p)\n", Connection);
1958 assert(!Connection->server);
1959 return Connection->ops->open_connection_client(Connection);
1962 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1964 TRACE("(Connection == ^%p)\n", Connection);
1965 if (SecIsValidHandle(&Connection->ctx))
1967 DeleteSecurityContext(&Connection->ctx);
1968 SecInvalidateHandle(&Connection->ctx);
1970 rpcrt4_conn_close(Connection);
1971 return RPC_S_OK;
1974 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1975 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1976 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS,
1977 RpcBinding* Binding)
1979 const struct connection_ops *ops;
1980 RpcConnection* NewConnection;
1982 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1983 if (!ops)
1985 FIXME("not supported for protseq %s\n", Protseq);
1986 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1989 NewConnection = ops->alloc();
1990 NewConnection->Next = NULL;
1991 NewConnection->server = server;
1992 NewConnection->ops = ops;
1993 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1994 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1995 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1996 NewConnection->Used = Binding;
1997 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1998 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1999 NewConnection->NextCallId = 1;
2001 SecInvalidateHandle(&NewConnection->ctx);
2002 memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
2003 NewConnection->attr = 0;
2004 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
2005 NewConnection->AuthInfo = AuthInfo;
2006 NewConnection->encryption_auth_len = 0;
2007 NewConnection->signature_auth_len = 0;
2008 if (QOS) RpcQualityOfService_AddRef(QOS);
2009 NewConnection->QOS = QOS;
2011 list_init(&NewConnection->conn_pool_entry);
2013 TRACE("connection: %p\n", NewConnection);
2014 *Connection = NewConnection;
2016 return RPC_S_OK;
2019 RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
2020 LPCSTR Endpoint, LPCWSTR NetworkOptions,
2021 RpcAssoc **assoc_out)
2023 RpcAssoc *assoc;
2025 EnterCriticalSection(&assoc_list_cs);
2026 LIST_FOR_EACH_ENTRY(assoc, &assoc_list, RpcAssoc, entry)
2028 if (!strcmp(Protseq, assoc->Protseq) &&
2029 !strcmp(NetworkAddr, assoc->NetworkAddr) &&
2030 !strcmp(Endpoint, assoc->Endpoint) &&
2031 ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions)))
2033 assoc->refs++;
2034 *assoc_out = assoc;
2035 LeaveCriticalSection(&assoc_list_cs);
2036 TRACE("using existing assoc %p\n", assoc);
2037 return RPC_S_OK;
2041 assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
2042 if (!assoc)
2044 LeaveCriticalSection(&assoc_list_cs);
2045 return RPC_S_OUT_OF_RESOURCES;
2047 assoc->refs = 1;
2048 list_init(&assoc->connection_pool);
2049 InitializeCriticalSection(&assoc->cs);
2050 assoc->Protseq = RPCRT4_strdupA(Protseq);
2051 assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
2052 assoc->Endpoint = RPCRT4_strdupA(Endpoint);
2053 assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
2054 list_add_head(&assoc_list, &assoc->entry);
2055 *assoc_out = assoc;
2057 LeaveCriticalSection(&assoc_list_cs);
2059 TRACE("new assoc %p\n", assoc);
2061 return RPC_S_OK;
2064 ULONG RpcAssoc_Release(RpcAssoc *assoc)
2066 ULONG refs;
2068 EnterCriticalSection(&assoc_list_cs);
2069 refs = --assoc->refs;
2070 if (!refs)
2071 list_remove(&assoc->entry);
2072 LeaveCriticalSection(&assoc_list_cs);
2074 if (!refs)
2076 RpcConnection *Connection, *cursor2;
2078 TRACE("destroying assoc %p\n", assoc);
2080 LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->connection_pool, RpcConnection, conn_pool_entry)
2082 list_remove(&Connection->conn_pool_entry);
2083 RPCRT4_DestroyConnection(Connection);
2086 HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
2087 HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
2088 HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
2089 HeapFree(GetProcessHeap(), 0, assoc->Protseq);
2091 HeapFree(GetProcessHeap(), 0, assoc);
2094 return refs;
2097 RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
2098 const RPC_SYNTAX_IDENTIFIER *InterfaceId,
2099 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
2100 const RpcQualityOfService *QOS)
2102 RpcConnection *Connection;
2103 /* try to find a compatible connection from the connection pool */
2104 EnterCriticalSection(&assoc->cs);
2105 LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry)
2106 if ((Connection->AuthInfo == AuthInfo) &&
2107 (Connection->QOS == QOS) &&
2108 !memcmp(&Connection->ActiveInterface, InterfaceId,
2109 sizeof(RPC_SYNTAX_IDENTIFIER)))
2111 list_remove(&Connection->conn_pool_entry);
2112 LeaveCriticalSection(&assoc->cs);
2113 TRACE("got connection from pool %p\n", Connection);
2114 return Connection;
2117 LeaveCriticalSection(&assoc->cs);
2118 return NULL;
2121 void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
2123 assert(!Connection->server);
2124 EnterCriticalSection(&assoc->cs);
2125 list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry);
2126 LeaveCriticalSection(&assoc->cs);
2130 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
2132 RPC_STATUS err;
2134 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
2135 rpcrt4_conn_get_name(OldConnection),
2136 OldConnection->NetworkAddr,
2137 OldConnection->Endpoint, NULL,
2138 OldConnection->AuthInfo, OldConnection->QOS,
2139 NULL);
2140 if (err == RPC_S_OK)
2141 rpcrt4_conn_handoff(OldConnection, *Connection);
2142 return err;
2145 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
2147 TRACE("connection: %p\n", Connection);
2149 RPCRT4_CloseConnection(Connection);
2150 RPCRT4_strfree(Connection->Endpoint);
2151 RPCRT4_strfree(Connection->NetworkAddr);
2152 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
2153 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
2154 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
2155 HeapFree(GetProcessHeap(), 0, Connection);
2156 return RPC_S_OK;
2159 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
2160 size_t *tower_size,
2161 const char *protseq,
2162 const char *networkaddr,
2163 const char *endpoint)
2165 twr_empty_floor_t *protocol_floor;
2166 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
2168 *tower_size = 0;
2170 if (!protseq_ops)
2171 return RPC_S_INVALID_RPC_PROTSEQ;
2173 if (!tower_data)
2175 *tower_size = sizeof(*protocol_floor);
2176 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
2177 return RPC_S_OK;
2180 protocol_floor = (twr_empty_floor_t *)tower_data;
2181 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
2182 protocol_floor->protid = protseq_ops->epm_protocols[0];
2183 protocol_floor->count_rhs = 0;
2185 tower_data += sizeof(*protocol_floor);
2187 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
2188 if (!*tower_size)
2189 return EPT_S_NOT_REGISTERED;
2191 *tower_size += sizeof(*protocol_floor);
2193 return RPC_S_OK;
2196 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
2197 size_t tower_size,
2198 char **protseq,
2199 char **networkaddr,
2200 char **endpoint)
2202 const twr_empty_floor_t *protocol_floor;
2203 const twr_empty_floor_t *floor4;
2204 const struct connection_ops *protseq_ops = NULL;
2205 RPC_STATUS status;
2206 int i;
2208 if (tower_size < sizeof(*protocol_floor))
2209 return EPT_S_NOT_REGISTERED;
2211 protocol_floor = (const twr_empty_floor_t *)tower_data;
2212 tower_data += sizeof(*protocol_floor);
2213 tower_size -= sizeof(*protocol_floor);
2214 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
2215 (protocol_floor->count_rhs > tower_size))
2216 return EPT_S_NOT_REGISTERED;
2217 tower_data += protocol_floor->count_rhs;
2218 tower_size -= protocol_floor->count_rhs;
2220 floor4 = (const twr_empty_floor_t *)tower_data;
2221 if ((tower_size < sizeof(*floor4)) ||
2222 (floor4->count_lhs != sizeof(floor4->protid)))
2223 return EPT_S_NOT_REGISTERED;
2225 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
2226 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
2227 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
2229 protseq_ops = &conn_protseq_list[i];
2230 break;
2233 if (!protseq_ops)
2234 return EPT_S_NOT_REGISTERED;
2236 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
2238 if ((status == RPC_S_OK) && protseq)
2240 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
2241 strcpy(*protseq, protseq_ops->name);
2244 return status;
2247 /***********************************************************************
2248 * RpcNetworkIsProtseqValidW (RPCRT4.@)
2250 * Checks if the given protocol sequence is known by the RPC system.
2251 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
2254 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
2256 char ps[0x10];
2258 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
2259 ps, sizeof ps, NULL, NULL);
2260 if (rpcrt4_get_conn_protseq_ops(ps))
2261 return RPC_S_OK;
2263 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
2265 return RPC_S_INVALID_RPC_PROTSEQ;
2268 /***********************************************************************
2269 * RpcNetworkIsProtseqValidA (RPCRT4.@)
2271 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
2273 UNICODE_STRING protseqW;
2275 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
2277 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
2278 RtlFreeUnicodeString(&protseqW);
2279 return ret;
2281 return RPC_S_OUT_OF_MEMORY;