tests: Add skip(), a function to warn that tests were skipped due to limitations...
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blobceae31d60ee21e7139a70c8a3660bc7ac9f947fd
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_ARPA_INET_H
47 # include <arpa/inet.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef HAVE_SYS_POLL_H
53 #include <sys/poll.h>
54 #endif
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winnls.h"
59 #include "winerror.h"
60 #include "winreg.h"
61 #include "winternl.h"
62 #include "wine/unicode.h"
64 #include "rpc.h"
65 #include "rpcndr.h"
67 #include "wine/debug.h"
69 #include "rpc_binding.h"
70 #include "rpc_message.h"
71 #include "rpc_server.h"
72 #include "epm_towers.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
76 static CRITICAL_SECTION connection_pool_cs;
77 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
79 0, 0, &connection_pool_cs,
80 { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
81 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
83 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
85 static struct list connection_pool = LIST_INIT(connection_pool);
87 /**** ncacn_np support ****/
89 typedef struct _RpcConnection_np
91 RpcConnection common;
92 HANDLE pipe;
93 OVERLAPPED ovl;
94 BOOL listening;
95 } RpcConnection_np;
97 static RpcConnection *rpcrt4_conn_np_alloc(void)
99 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
100 if (npc)
102 npc->pipe = NULL;
103 memset(&npc->ovl, 0, sizeof(npc->ovl));
104 npc->listening = FALSE;
106 return &npc->common;
109 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
111 if (npc->listening)
112 return RPC_S_OK;
114 npc->listening = TRUE;
115 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
116 return RPC_S_OK;
118 if (GetLastError() == ERROR_PIPE_CONNECTED) {
119 SetEvent(npc->ovl.hEvent);
120 return RPC_S_OK;
122 if (GetLastError() == ERROR_IO_PENDING) {
123 /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
124 return RPC_S_OK;
126 npc->listening = FALSE;
127 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
128 return RPC_S_OUT_OF_RESOURCES;
131 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
133 RpcConnection_np *npc = (RpcConnection_np *) Connection;
134 TRACE("listening on %s\n", pname);
136 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
137 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
138 PIPE_UNLIMITED_INSTANCES,
139 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
140 if (npc->pipe == INVALID_HANDLE_VALUE) {
141 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
142 if (GetLastError() == ERROR_FILE_EXISTS)
143 return RPC_S_DUPLICATE_ENDPOINT;
144 else
145 return RPC_S_CANT_CREATE_ENDPOINT;
148 memset(&npc->ovl, 0, sizeof(npc->ovl));
149 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
151 /* Note: we don't call ConnectNamedPipe here because it must be done in the
152 * server thread as the thread must be alertable */
153 return RPC_S_OK;
156 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
158 RpcConnection_np *npc = (RpcConnection_np *) Connection;
159 HANDLE pipe;
160 DWORD err, dwMode;
162 TRACE("connecting to %s\n", pname);
164 while (TRUE) {
165 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
166 OPEN_EXISTING, 0, 0);
167 if (pipe != INVALID_HANDLE_VALUE) break;
168 err = GetLastError();
169 if (err == ERROR_PIPE_BUSY) {
170 TRACE("connection failed, error=%x\n", err);
171 return RPC_S_SERVER_TOO_BUSY;
173 if (!wait)
174 return RPC_S_SERVER_UNAVAILABLE;
175 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
176 err = GetLastError();
177 WARN("connection failed, error=%x\n", err);
178 return RPC_S_SERVER_UNAVAILABLE;
182 /* success */
183 memset(&npc->ovl, 0, sizeof(npc->ovl));
184 /* pipe is connected; change to message-read mode. */
185 dwMode = PIPE_READMODE_MESSAGE;
186 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
187 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
188 npc->pipe = pipe;
190 return RPC_S_OK;
193 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
195 RpcConnection_np *npc = (RpcConnection_np *) Connection;
196 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
197 RPC_STATUS r;
198 LPSTR pname;
200 /* already connected? */
201 if (npc->pipe)
202 return RPC_S_OK;
204 /* protseq=ncalrpc: supposed to use NT LPC ports,
205 * but we'll implement it with named pipes for now */
206 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
207 strcat(strcpy(pname, prefix), Connection->Endpoint);
208 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
209 I_RpcFree(pname);
211 return r;
214 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
216 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
217 RPC_STATUS r;
218 LPSTR pname;
219 RpcConnection *Connection;
221 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
222 endpoint, NULL, NULL, NULL);
223 if (r != RPC_S_OK)
224 return r;
226 /* protseq=ncalrpc: supposed to use NT LPC ports,
227 * but we'll implement it with named pipes for now */
228 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
229 strcat(strcpy(pname, prefix), Connection->Endpoint);
230 r = rpcrt4_conn_create_pipe(Connection, pname);
231 I_RpcFree(pname);
233 EnterCriticalSection(&protseq->cs);
234 Connection->Next = protseq->conn;
235 protseq->conn = Connection;
236 LeaveCriticalSection(&protseq->cs);
238 return r;
241 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
243 RpcConnection_np *npc = (RpcConnection_np *) Connection;
244 static const char prefix[] = "\\\\.";
245 RPC_STATUS r;
246 LPSTR pname;
248 /* already connected? */
249 if (npc->pipe)
250 return RPC_S_OK;
252 /* protseq=ncacn_np: named pipes */
253 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
254 strcat(strcpy(pname, prefix), Connection->Endpoint);
255 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
256 I_RpcFree(pname);
258 return r;
261 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
263 static const char prefix[] = "\\\\.";
264 RPC_STATUS r;
265 LPSTR pname;
266 RpcConnection *Connection;
268 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
269 endpoint, NULL, NULL, NULL);
270 if (r != RPC_S_OK)
271 return r;
273 /* protseq=ncacn_np: named pipes */
274 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
275 strcat(strcpy(pname, prefix), Connection->Endpoint);
276 r = rpcrt4_conn_create_pipe(Connection, pname);
277 I_RpcFree(pname);
279 return r;
282 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
284 /* because of the way named pipes work, we'll transfer the connected pipe
285 * to the child, then reopen the server binding to continue listening */
287 new_npc->pipe = old_npc->pipe;
288 new_npc->ovl = old_npc->ovl;
289 old_npc->pipe = 0;
290 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
291 old_npc->listening = FALSE;
294 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
296 RPC_STATUS status;
297 LPSTR pname;
298 static const char prefix[] = "\\\\.";
300 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
302 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
303 strcat(strcpy(pname, prefix), old_conn->Endpoint);
304 status = rpcrt4_conn_create_pipe(old_conn, pname);
305 I_RpcFree(pname);
307 return status;
310 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
312 RPC_STATUS status;
313 LPSTR pname;
314 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
316 TRACE("%s\n", old_conn->Endpoint);
318 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
320 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
321 strcat(strcpy(pname, prefix), old_conn->Endpoint);
322 status = rpcrt4_conn_create_pipe(old_conn, pname);
323 I_RpcFree(pname);
325 return status;
328 static int rpcrt4_conn_np_read(RpcConnection *Connection,
329 void *buffer, unsigned int count)
331 RpcConnection_np *npc = (RpcConnection_np *) Connection;
332 DWORD dwRead = 0;
333 if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
334 (GetLastError() != ERROR_MORE_DATA))
335 return -1;
336 return dwRead;
339 static int rpcrt4_conn_np_write(RpcConnection *Connection,
340 const void *buffer, unsigned int count)
342 RpcConnection_np *npc = (RpcConnection_np *) Connection;
343 DWORD dwWritten = 0;
344 if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
345 return -1;
346 return dwWritten;
349 static int rpcrt4_conn_np_close(RpcConnection *Connection)
351 RpcConnection_np *npc = (RpcConnection_np *) Connection;
352 if (npc->pipe) {
353 FlushFileBuffers(npc->pipe);
354 CloseHandle(npc->pipe);
355 npc->pipe = 0;
357 if (npc->ovl.hEvent) {
358 CloseHandle(npc->ovl.hEvent);
359 npc->ovl.hEvent = 0;
361 return 0;
364 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
365 const char *networkaddr,
366 const char *endpoint)
368 twr_empty_floor_t *smb_floor;
369 twr_empty_floor_t *nb_floor;
370 size_t size;
371 size_t networkaddr_size;
372 size_t endpoint_size;
374 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
376 networkaddr_size = strlen(networkaddr) + 1;
377 endpoint_size = strlen(endpoint) + 1;
378 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
380 if (!tower_data)
381 return size;
383 smb_floor = (twr_empty_floor_t *)tower_data;
385 tower_data += sizeof(*smb_floor);
387 smb_floor->count_lhs = sizeof(smb_floor->protid);
388 smb_floor->protid = EPM_PROTOCOL_SMB;
389 smb_floor->count_rhs = endpoint_size;
391 memcpy(tower_data, endpoint, endpoint_size);
392 tower_data += endpoint_size;
394 nb_floor = (twr_empty_floor_t *)tower_data;
396 tower_data += sizeof(*nb_floor);
398 nb_floor->count_lhs = sizeof(nb_floor->protid);
399 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
400 nb_floor->count_rhs = networkaddr_size;
402 memcpy(tower_data, networkaddr, networkaddr_size);
403 tower_data += networkaddr_size;
405 return size;
408 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
409 size_t tower_size,
410 char **networkaddr,
411 char **endpoint)
413 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
414 const twr_empty_floor_t *nb_floor;
416 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
418 if (tower_size < sizeof(*smb_floor))
419 return EPT_S_NOT_REGISTERED;
421 tower_data += sizeof(*smb_floor);
422 tower_size -= sizeof(*smb_floor);
424 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
425 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
426 (smb_floor->count_rhs > tower_size))
427 return EPT_S_NOT_REGISTERED;
429 if (endpoint)
431 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
432 if (!*endpoint)
433 return RPC_S_OUT_OF_RESOURCES;
434 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
436 tower_data += smb_floor->count_rhs;
437 tower_size -= smb_floor->count_rhs;
439 if (tower_size < sizeof(*nb_floor))
440 return EPT_S_NOT_REGISTERED;
442 nb_floor = (const twr_empty_floor_t *)tower_data;
444 tower_data += sizeof(*nb_floor);
445 tower_size -= sizeof(*nb_floor);
447 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
448 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
449 (nb_floor->count_rhs > tower_size))
450 return EPT_S_NOT_REGISTERED;
452 if (networkaddr)
454 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
455 if (!*networkaddr)
457 if (endpoint)
459 I_RpcFree(*endpoint);
460 *endpoint = NULL;
462 return RPC_S_OUT_OF_RESOURCES;
464 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
467 return RPC_S_OK;
470 typedef struct _RpcServerProtseq_np
472 RpcServerProtseq common;
473 HANDLE mgr_event;
474 } RpcServerProtseq_np;
476 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
478 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
479 if (ps)
480 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
481 return &ps->common;
484 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
486 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
487 SetEvent(npps->mgr_event);
490 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
492 HANDLE *objs = prev_array;
493 RpcConnection_np *conn;
494 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
496 EnterCriticalSection(&protseq->cs);
498 /* open and count connections */
499 *count = 1;
500 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
501 while (conn) {
502 rpcrt4_conn_listen_pipe(conn);
503 if (conn->ovl.hEvent)
504 (*count)++;
505 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
508 /* make array of connections */
509 if (objs)
510 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
511 else
512 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
513 if (!objs)
515 ERR("couldn't allocate objs\n");
516 LeaveCriticalSection(&protseq->cs);
517 return NULL;
520 objs[0] = npps->mgr_event;
521 *count = 1;
522 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
523 while (conn) {
524 if ((objs[*count] = conn->ovl.hEvent))
525 (*count)++;
526 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
528 LeaveCriticalSection(&protseq->cs);
529 return objs;
532 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
534 HeapFree(GetProcessHeap(), 0, array);
537 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
539 HANDLE b_handle;
540 HANDLE *objs = wait_array;
541 DWORD res;
542 RpcConnection *cconn;
543 RpcConnection_np *conn;
545 if (!objs)
546 return -1;
548 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
549 if (res == WAIT_OBJECT_0)
550 return 0;
551 else if (res == WAIT_FAILED)
553 ERR("wait failed with error %d\n", GetLastError());
554 return -1;
556 else
558 b_handle = objs[res - WAIT_OBJECT_0];
559 /* find which connection got a RPC */
560 EnterCriticalSection(&protseq->cs);
561 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
562 while (conn) {
563 if (b_handle == conn->ovl.hEvent) break;
564 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
566 cconn = NULL;
567 if (conn)
568 RPCRT4_SpawnConnection(&cconn, &conn->common);
569 else
570 ERR("failed to locate connection for handle %p\n", b_handle);
571 LeaveCriticalSection(&protseq->cs);
572 if (cconn)
574 RPCRT4_new_client(cconn);
575 return 1;
577 else return -1;
581 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
582 const char *networkaddr,
583 const char *endpoint)
585 twr_empty_floor_t *pipe_floor;
586 size_t size;
587 size_t endpoint_size;
589 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
591 endpoint_size = strlen(networkaddr) + 1;
592 size = sizeof(*pipe_floor) + endpoint_size;
594 if (!tower_data)
595 return size;
597 pipe_floor = (twr_empty_floor_t *)tower_data;
599 tower_data += sizeof(*pipe_floor);
601 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
602 pipe_floor->protid = EPM_PROTOCOL_SMB;
603 pipe_floor->count_rhs = endpoint_size;
605 memcpy(tower_data, endpoint, endpoint_size);
606 tower_data += endpoint_size;
608 return size;
611 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
612 size_t tower_size,
613 char **networkaddr,
614 char **endpoint)
616 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
618 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
620 *networkaddr = NULL;
621 *endpoint = NULL;
623 if (tower_size < sizeof(*pipe_floor))
624 return EPT_S_NOT_REGISTERED;
626 tower_data += sizeof(*pipe_floor);
627 tower_size -= sizeof(*pipe_floor);
629 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
630 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
631 (pipe_floor->count_rhs > tower_size))
632 return EPT_S_NOT_REGISTERED;
634 if (endpoint)
636 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
637 if (!*endpoint)
638 return RPC_S_OUT_OF_RESOURCES;
639 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
642 return RPC_S_OK;
645 /**** ncacn_ip_tcp support ****/
647 typedef struct _RpcConnection_tcp
649 RpcConnection common;
650 int sock;
651 } RpcConnection_tcp;
653 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
655 RpcConnection_tcp *tcpc;
656 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
657 if (tcpc == NULL)
658 return NULL;
659 tcpc->sock = -1;
660 return &tcpc->common;
663 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
665 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
666 int sock;
667 int ret;
668 struct addrinfo *ai;
669 struct addrinfo *ai_cur;
670 struct addrinfo hints;
672 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
674 if (tcpc->sock != -1)
675 return RPC_S_OK;
677 hints.ai_flags = 0;
678 hints.ai_family = PF_UNSPEC;
679 hints.ai_socktype = SOCK_STREAM;
680 hints.ai_protocol = IPPROTO_TCP;
681 hints.ai_addrlen = 0;
682 hints.ai_addr = NULL;
683 hints.ai_canonname = NULL;
684 hints.ai_next = NULL;
686 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
687 if (ret)
689 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
690 Connection->Endpoint, gai_strerror(ret));
691 return RPC_S_SERVER_UNAVAILABLE;
694 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
696 if (TRACE_ON(rpc))
698 char host[256];
699 char service[256];
700 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
701 host, sizeof(host), service, sizeof(service),
702 NI_NUMERICHOST | NI_NUMERICSERV);
703 TRACE("trying %s:%s\n", host, service);
706 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
707 if (sock < 0)
709 WARN("socket() failed: %s\n", strerror(errno));
710 continue;
713 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
715 WARN("connect() failed: %s\n", strerror(errno));
716 close(sock);
717 continue;
719 tcpc->sock = sock;
721 freeaddrinfo(ai);
722 TRACE("connected\n");
723 return RPC_S_OK;
726 freeaddrinfo(ai);
727 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
728 return RPC_S_SERVER_UNAVAILABLE;
731 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
733 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
734 int sock;
735 int ret;
736 struct addrinfo *ai;
737 struct addrinfo *ai_cur;
738 struct addrinfo hints;
739 RpcConnection *first_connection = NULL;
741 TRACE("(%p, %s)\n", protseq, endpoint);
743 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
744 hints.ai_family = PF_UNSPEC;
745 hints.ai_socktype = SOCK_STREAM;
746 hints.ai_protocol = IPPROTO_TCP;
747 hints.ai_addrlen = 0;
748 hints.ai_addr = NULL;
749 hints.ai_canonname = NULL;
750 hints.ai_next = NULL;
752 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
753 if (ret)
755 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
756 gai_strerror(ret));
757 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
758 return RPC_S_INVALID_ENDPOINT_FORMAT;
759 return RPC_S_CANT_CREATE_ENDPOINT;
762 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
764 RpcConnection_tcp *tcpc;
765 RPC_STATUS create_status;
767 if (TRACE_ON(rpc))
769 char host[256];
770 char service[256];
771 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
772 host, sizeof(host), service, sizeof(service),
773 NI_NUMERICHOST | NI_NUMERICSERV);
774 TRACE("trying %s:%s\n", host, service);
777 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
778 if (sock < 0)
780 WARN("socket() failed: %s\n", strerror(errno));
781 status = RPC_S_CANT_CREATE_ENDPOINT;
782 continue;
785 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
786 if (ret < 0)
788 WARN("bind failed: %s\n", strerror(errno));
789 close(sock);
790 if (errno == EADDRINUSE)
791 status = RPC_S_DUPLICATE_ENDPOINT;
792 else
793 status = RPC_S_CANT_CREATE_ENDPOINT;
794 continue;
796 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
797 protseq->Protseq, NULL,
798 endpoint, NULL, NULL, NULL);
799 if (create_status != RPC_S_OK)
801 close(sock);
802 status = create_status;
803 continue;
806 tcpc->sock = sock;
807 ret = listen(sock, protseq->MaxCalls);
808 if (ret < 0)
810 WARN("listen failed: %s\n", strerror(errno));
811 RPCRT4_DestroyConnection(&tcpc->common);
812 status = RPC_S_OUT_OF_RESOURCES;
813 continue;
815 /* need a non-blocking socket, otherwise accept() has a potential
816 * race-condition (poll() says it is readable, connection drops,
817 * and accept() blocks until the next connection comes...)
819 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
820 if (ret < 0)
822 WARN("couldn't make socket non-blocking, error %d\n", ret);
823 RPCRT4_DestroyConnection(&tcpc->common);
824 status = RPC_S_OUT_OF_RESOURCES;
825 continue;
828 tcpc->common.Next = first_connection;
829 first_connection = &tcpc->common;
832 freeaddrinfo(ai);
834 /* if at least one connection was created for an endpoint then
835 * return success */
836 if (first_connection)
838 RpcConnection *conn;
840 /* find last element in list */
841 for (conn = first_connection; conn->Next; conn = conn->Next)
844 EnterCriticalSection(&protseq->cs);
845 conn->Next = protseq->conn;
846 protseq->conn = first_connection;
847 LeaveCriticalSection(&protseq->cs);
849 TRACE("listening on %s\n", endpoint);
850 return RPC_S_OK;
853 ERR("couldn't listen on port %s\n", endpoint);
854 return status;
857 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
859 int ret;
860 struct sockaddr_in address;
861 socklen_t addrsize;
862 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
863 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
865 addrsize = sizeof(address);
866 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
867 if (ret < 0)
869 ERR("Failed to accept a TCP connection: error %d\n", ret);
870 return RPC_S_OUT_OF_RESOURCES;
872 /* reset to blocking behaviour */
873 fcntl(ret, F_SETFL, 0);
874 client->sock = ret;
875 TRACE("Accepted a new TCP connection\n");
876 return RPC_S_OK;
879 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
880 void *buffer, unsigned int count)
882 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
883 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
884 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
885 return r;
888 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
889 const void *buffer, unsigned int count)
891 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
892 int r = write(tcpc->sock, buffer, count);
893 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
894 return r;
897 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
899 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
901 TRACE("%d\n", tcpc->sock);
903 if (tcpc->sock != -1)
904 close(tcpc->sock);
905 tcpc->sock = -1;
906 return 0;
909 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
910 const char *networkaddr,
911 const char *endpoint)
913 twr_tcp_floor_t *tcp_floor;
914 twr_ipv4_floor_t *ipv4_floor;
915 struct addrinfo *ai;
916 struct addrinfo hints;
917 int ret;
918 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
920 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
922 if (!tower_data)
923 return size;
925 tcp_floor = (twr_tcp_floor_t *)tower_data;
926 tower_data += sizeof(*tcp_floor);
928 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
930 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
931 tcp_floor->protid = EPM_PROTOCOL_TCP;
932 tcp_floor->count_rhs = sizeof(tcp_floor->port);
934 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
935 ipv4_floor->protid = EPM_PROTOCOL_IP;
936 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
938 hints.ai_flags = AI_NUMERICHOST;
939 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
940 hints.ai_family = PF_INET;
941 hints.ai_socktype = SOCK_STREAM;
942 hints.ai_protocol = IPPROTO_TCP;
943 hints.ai_addrlen = 0;
944 hints.ai_addr = NULL;
945 hints.ai_canonname = NULL;
946 hints.ai_next = NULL;
948 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
949 if (ret)
951 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
952 if (ret)
954 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
955 return 0;
959 if (ai->ai_family == PF_INET)
961 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
962 tcp_floor->port = sin->sin_port;
963 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
965 else
967 ERR("unexpected protocol family %d\n", ai->ai_family);
968 return 0;
971 freeaddrinfo(ai);
973 return size;
976 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
977 size_t tower_size,
978 char **networkaddr,
979 char **endpoint)
981 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
982 const twr_ipv4_floor_t *ipv4_floor;
983 struct in_addr in_addr;
985 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
987 if (tower_size < sizeof(*tcp_floor))
988 return EPT_S_NOT_REGISTERED;
990 tower_data += sizeof(*tcp_floor);
991 tower_size -= sizeof(*tcp_floor);
993 if (tower_size < sizeof(*ipv4_floor))
994 return EPT_S_NOT_REGISTERED;
996 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
998 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
999 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1000 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1001 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1002 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1003 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1004 return EPT_S_NOT_REGISTERED;
1006 if (endpoint)
1008 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1009 if (!*endpoint)
1010 return RPC_S_OUT_OF_RESOURCES;
1011 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1014 if (networkaddr)
1016 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1017 if (!*networkaddr)
1019 if (endpoint)
1021 I_RpcFree(*endpoint);
1022 *endpoint = NULL;
1024 return RPC_S_OUT_OF_RESOURCES;
1026 in_addr.s_addr = ipv4_floor->ipv4addr;
1027 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1029 ERR("inet_ntop: %s\n", strerror(errno));
1030 I_RpcFree(*networkaddr);
1031 *networkaddr = NULL;
1032 if (endpoint)
1034 I_RpcFree(*endpoint);
1035 *endpoint = NULL;
1037 return EPT_S_NOT_REGISTERED;
1041 return RPC_S_OK;
1044 typedef struct _RpcServerProtseq_sock
1046 RpcServerProtseq common;
1047 int mgr_event_rcv;
1048 int mgr_event_snd;
1049 } RpcServerProtseq_sock;
1051 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1053 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1054 if (ps)
1056 int fds[2];
1057 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1059 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1060 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1061 ps->mgr_event_rcv = fds[0];
1062 ps->mgr_event_snd = fds[1];
1064 else
1066 ERR("socketpair failed with error %s\n", strerror(errno));
1067 HeapFree(GetProcessHeap(), 0, ps);
1068 return NULL;
1071 return &ps->common;
1074 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1076 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1077 char dummy = 1;
1078 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1081 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1083 struct pollfd *poll_info = prev_array;
1084 RpcConnection_tcp *conn;
1085 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1087 EnterCriticalSection(&protseq->cs);
1089 /* open and count connections */
1090 *count = 1;
1091 conn = (RpcConnection_tcp *)protseq->conn;
1092 while (conn) {
1093 if (conn->sock != -1)
1094 (*count)++;
1095 conn = (RpcConnection_tcp *)conn->common.Next;
1098 /* make array of connections */
1099 if (poll_info)
1100 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1101 else
1102 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1103 if (!poll_info)
1105 ERR("couldn't allocate poll_info\n");
1106 LeaveCriticalSection(&protseq->cs);
1107 return NULL;
1110 poll_info[0].fd = sockps->mgr_event_rcv;
1111 poll_info[0].events = POLLIN;
1112 *count = 1;
1113 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1114 while (conn) {
1115 if (conn->sock != -1)
1117 poll_info[*count].fd = conn->sock;
1118 poll_info[*count].events = POLLIN;
1119 (*count)++;
1121 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1123 LeaveCriticalSection(&protseq->cs);
1124 return poll_info;
1127 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1129 HeapFree(GetProcessHeap(), 0, array);
1132 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1134 struct pollfd *poll_info = wait_array;
1135 int ret, i;
1136 RpcConnection *cconn;
1137 RpcConnection_tcp *conn;
1139 if (!poll_info)
1140 return -1;
1142 ret = poll(poll_info, count, -1);
1143 if (ret < 0)
1145 ERR("poll failed with error %d\n", ret);
1146 return -1;
1149 for (i = 0; i < count; i++)
1150 if (poll_info[i].revents & POLLIN)
1152 /* RPC server event */
1153 if (i == 0)
1155 char dummy;
1156 read(poll_info[0].fd, &dummy, sizeof(dummy));
1157 return 0;
1160 /* find which connection got a RPC */
1161 EnterCriticalSection(&protseq->cs);
1162 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1163 while (conn) {
1164 if (poll_info[i].fd == conn->sock) break;
1165 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1167 cconn = NULL;
1168 if (conn)
1169 RPCRT4_SpawnConnection(&cconn, &conn->common);
1170 else
1171 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1172 LeaveCriticalSection(&protseq->cs);
1173 if (cconn)
1174 RPCRT4_new_client(cconn);
1175 else
1176 return -1;
1179 return 1;
1182 static const struct connection_ops conn_protseq_list[] = {
1183 { "ncacn_np",
1184 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1185 rpcrt4_conn_np_alloc,
1186 rpcrt4_ncacn_np_open,
1187 rpcrt4_ncacn_np_handoff,
1188 rpcrt4_conn_np_read,
1189 rpcrt4_conn_np_write,
1190 rpcrt4_conn_np_close,
1191 rpcrt4_ncacn_np_get_top_of_tower,
1192 rpcrt4_ncacn_np_parse_top_of_tower,
1194 { "ncalrpc",
1195 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1196 rpcrt4_conn_np_alloc,
1197 rpcrt4_ncalrpc_open,
1198 rpcrt4_ncalrpc_handoff,
1199 rpcrt4_conn_np_read,
1200 rpcrt4_conn_np_write,
1201 rpcrt4_conn_np_close,
1202 rpcrt4_ncalrpc_get_top_of_tower,
1203 rpcrt4_ncalrpc_parse_top_of_tower,
1205 { "ncacn_ip_tcp",
1206 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1207 rpcrt4_conn_tcp_alloc,
1208 rpcrt4_ncacn_ip_tcp_open,
1209 rpcrt4_conn_tcp_handoff,
1210 rpcrt4_conn_tcp_read,
1211 rpcrt4_conn_tcp_write,
1212 rpcrt4_conn_tcp_close,
1213 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1214 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1219 static const struct protseq_ops protseq_list[] =
1222 "ncacn_np",
1223 rpcrt4_protseq_np_alloc,
1224 rpcrt4_protseq_np_signal_state_changed,
1225 rpcrt4_protseq_np_get_wait_array,
1226 rpcrt4_protseq_np_free_wait_array,
1227 rpcrt4_protseq_np_wait_for_new_connection,
1228 rpcrt4_protseq_ncacn_np_open_endpoint,
1231 "ncalrpc",
1232 rpcrt4_protseq_np_alloc,
1233 rpcrt4_protseq_np_signal_state_changed,
1234 rpcrt4_protseq_np_get_wait_array,
1235 rpcrt4_protseq_np_free_wait_array,
1236 rpcrt4_protseq_np_wait_for_new_connection,
1237 rpcrt4_protseq_ncalrpc_open_endpoint,
1240 "ncacn_ip_tcp",
1241 rpcrt4_protseq_sock_alloc,
1242 rpcrt4_protseq_sock_signal_state_changed,
1243 rpcrt4_protseq_sock_get_wait_array,
1244 rpcrt4_protseq_sock_free_wait_array,
1245 rpcrt4_protseq_sock_wait_for_new_connection,
1246 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1250 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1252 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1254 int i;
1255 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1256 if (!strcmp(protseq_list[i].name, protseq))
1257 return &protseq_list[i];
1258 return NULL;
1261 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1263 int i;
1264 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1265 if (!strcmp(conn_protseq_list[i].name, protseq))
1266 return &conn_protseq_list[i];
1267 return NULL;
1270 /**** interface to rest of code ****/
1272 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1274 TRACE("(Connection == ^%p)\n", Connection);
1276 assert(!Connection->server);
1277 return Connection->ops->open_connection_client(Connection);
1280 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1282 TRACE("(Connection == ^%p)\n", Connection);
1283 if (SecIsValidHandle(&Connection->ctx))
1285 DeleteSecurityContext(&Connection->ctx);
1286 SecInvalidateHandle(&Connection->ctx);
1288 rpcrt4_conn_close(Connection);
1289 return RPC_S_OK;
1292 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1293 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1294 LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1296 const struct connection_ops *ops;
1297 RpcConnection* NewConnection;
1299 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1300 if (!ops)
1302 FIXME("not supported for protseq %s\n", Protseq);
1303 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1306 NewConnection = ops->alloc();
1307 NewConnection->Next = NULL;
1308 NewConnection->server = server;
1309 NewConnection->ops = ops;
1310 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1311 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1312 NewConnection->Used = Binding;
1313 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1314 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1315 NewConnection->NextCallId = 1;
1317 SecInvalidateHandle(&NewConnection->ctx);
1318 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1319 NewConnection->AuthInfo = AuthInfo;
1320 list_init(&NewConnection->conn_pool_entry);
1322 TRACE("connection: %p\n", NewConnection);
1323 *Connection = NewConnection;
1325 return RPC_S_OK;
1328 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1329 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1330 LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1332 RpcConnection *Connection;
1333 /* try to find a compatible connection from the connection pool */
1334 EnterCriticalSection(&connection_pool_cs);
1335 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1336 if ((Connection->AuthInfo == AuthInfo) &&
1337 !memcmp(&Connection->ActiveInterface, InterfaceId,
1338 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1339 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1340 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1341 !strcmp(Connection->Endpoint, Endpoint))
1343 list_remove(&Connection->conn_pool_entry);
1344 LeaveCriticalSection(&connection_pool_cs);
1345 TRACE("got connection from pool %p\n", Connection);
1346 return Connection;
1349 LeaveCriticalSection(&connection_pool_cs);
1350 return NULL;
1353 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1355 assert(!Connection->server);
1356 EnterCriticalSection(&connection_pool_cs);
1357 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1358 LeaveCriticalSection(&connection_pool_cs);
1362 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1364 RPC_STATUS err;
1366 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1367 rpcrt4_conn_get_name(OldConnection),
1368 OldConnection->NetworkAddr,
1369 OldConnection->Endpoint, NULL,
1370 OldConnection->AuthInfo, NULL);
1371 if (err == RPC_S_OK)
1372 rpcrt4_conn_handoff(OldConnection, *Connection);
1373 return err;
1376 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1378 TRACE("connection: %p\n", Connection);
1380 RPCRT4_CloseConnection(Connection);
1381 RPCRT4_strfree(Connection->Endpoint);
1382 RPCRT4_strfree(Connection->NetworkAddr);
1383 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1384 HeapFree(GetProcessHeap(), 0, Connection);
1385 return RPC_S_OK;
1388 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1389 size_t *tower_size,
1390 const char *protseq,
1391 const char *networkaddr,
1392 const char *endpoint)
1394 twr_empty_floor_t *protocol_floor;
1395 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1397 *tower_size = 0;
1399 if (!protseq_ops)
1400 return RPC_S_INVALID_RPC_PROTSEQ;
1402 if (!tower_data)
1404 *tower_size = sizeof(*protocol_floor);
1405 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1406 return RPC_S_OK;
1409 protocol_floor = (twr_empty_floor_t *)tower_data;
1410 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1411 protocol_floor->protid = protseq_ops->epm_protocols[0];
1412 protocol_floor->count_rhs = 0;
1414 tower_data += sizeof(*protocol_floor);
1416 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1417 if (!*tower_size)
1418 return EPT_S_NOT_REGISTERED;
1420 *tower_size += sizeof(*protocol_floor);
1422 return RPC_S_OK;
1425 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1426 size_t tower_size,
1427 char **protseq,
1428 char **networkaddr,
1429 char **endpoint)
1431 const twr_empty_floor_t *protocol_floor;
1432 const twr_empty_floor_t *floor4;
1433 const struct connection_ops *protseq_ops = NULL;
1434 RPC_STATUS status;
1435 int i;
1437 if (tower_size < sizeof(*protocol_floor))
1438 return EPT_S_NOT_REGISTERED;
1440 protocol_floor = (const twr_empty_floor_t *)tower_data;
1441 tower_data += sizeof(*protocol_floor);
1442 tower_size -= sizeof(*protocol_floor);
1443 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1444 (protocol_floor->count_rhs > tower_size))
1445 return EPT_S_NOT_REGISTERED;
1446 tower_data += protocol_floor->count_rhs;
1447 tower_size -= protocol_floor->count_rhs;
1449 floor4 = (const twr_empty_floor_t *)tower_data;
1450 if ((tower_size < sizeof(*floor4)) ||
1451 (floor4->count_lhs != sizeof(floor4->protid)))
1452 return EPT_S_NOT_REGISTERED;
1454 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1455 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1456 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1458 protseq_ops = &conn_protseq_list[i];
1459 break;
1462 if (!protseq_ops)
1463 return EPT_S_NOT_REGISTERED;
1465 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1467 if ((status == RPC_S_OK) && protseq)
1469 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1470 strcpy(*protseq, protseq_ops->name);
1473 return status;
1476 /***********************************************************************
1477 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1479 * Checks if the given protocol sequence is known by the RPC system.
1480 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1483 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1485 char ps[0x10];
1487 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1488 ps, sizeof ps, NULL, NULL);
1489 if (rpcrt4_get_conn_protseq_ops(ps))
1490 return RPC_S_OK;
1492 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1494 return RPC_S_INVALID_RPC_PROTSEQ;
1497 /***********************************************************************
1498 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1500 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1502 UNICODE_STRING protseqW;
1504 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1506 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1507 RtlFreeUnicodeString(&protseqW);
1508 return ret;
1510 return RPC_S_OUT_OF_MEMORY;