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
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 # include <arpa/inet.h>
52 #ifdef HAVE_SYS_POLL_H
62 #include "wine/unicode.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
96 static RpcConnection *rpcrt4_conn_np_alloc(void)
98 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
103 memset(&npc->ovl, 0, sizeof(npc->ovl));
108 static RPC_STATUS rpcrt4_connect_pipe(RpcConnection *Connection, LPCSTR pname)
110 RpcConnection_np *npc = (RpcConnection_np *) Connection;
111 TRACE("listening on %s\n", pname);
113 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
114 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
115 PIPE_UNLIMITED_INSTANCES,
116 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
117 if (npc->pipe == INVALID_HANDLE_VALUE) {
118 WARN("CreateNamedPipe failed with error %ld\n", GetLastError());
119 return RPC_S_SERVER_UNAVAILABLE;
122 memset(&npc->ovl, 0, sizeof(npc->ovl));
123 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
124 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
127 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
128 if (GetLastError() == ERROR_PIPE_CONNECTED) {
129 SetEvent(npc->ovl.hEvent);
132 if (GetLastError() == ERROR_IO_PENDING) {
133 /* FIXME: looks like we need to GetOverlappedResult here? */
136 return RPC_S_SERVER_UNAVAILABLE;
139 static RPC_STATUS rpcrt4_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
141 RpcConnection_np *npc = (RpcConnection_np *) Connection;
145 TRACE("connecting to %s\n", pname);
148 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
149 OPEN_EXISTING, 0, 0);
150 if (pipe != INVALID_HANDLE_VALUE) break;
151 err = GetLastError();
152 if (err == ERROR_PIPE_BUSY) {
153 TRACE("connection failed, error=%lx\n", err);
154 return RPC_S_SERVER_TOO_BUSY;
157 return RPC_S_SERVER_UNAVAILABLE;
158 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
159 err = GetLastError();
160 WARN("connection failed, error=%lx\n", err);
161 return RPC_S_SERVER_UNAVAILABLE;
166 memset(&npc->ovl, 0, sizeof(npc->ovl));
167 /* pipe is connected; change to message-read mode. */
168 dwMode = PIPE_READMODE_MESSAGE;
169 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
170 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
176 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
178 RpcConnection_np *npc = (RpcConnection_np *) Connection;
179 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
183 /* already connected? */
187 /* protseq=ncalrpc: supposed to use NT LPC ports,
188 * but we'll implement it with named pipes for now */
189 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
190 strcat(strcpy(pname, prefix), Connection->Endpoint);
192 if (Connection->server)
193 r = rpcrt4_connect_pipe(Connection, pname);
195 r = rpcrt4_open_pipe(Connection, pname, TRUE);
201 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
203 RpcConnection_np *npc = (RpcConnection_np *) Connection;
204 static LPCSTR prefix = "\\\\.";
208 /* already connected? */
212 /* protseq=ncacn_np: named pipes */
213 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
214 strcat(strcpy(pname, prefix), Connection->Endpoint);
215 if (Connection->server)
216 r = rpcrt4_connect_pipe(Connection, pname);
218 r = rpcrt4_open_pipe(Connection, pname, FALSE);
224 static HANDLE rpcrt4_conn_np_get_connect_event(RpcConnection *Connection)
226 RpcConnection_np *npc = (RpcConnection_np *) Connection;
227 return npc->ovl.hEvent;
230 static RPC_STATUS rpcrt4_conn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
232 RpcConnection_np *old_npc = (RpcConnection_np *) old_conn;
233 RpcConnection_np *new_npc = (RpcConnection_np *) new_conn;
234 /* because of the way named pipes work, we'll transfer the connected pipe
235 * to the child, then reopen the server binding to continue listening */
237 new_npc->pipe = old_npc->pipe;
238 new_npc->ovl = old_npc->ovl;
240 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
241 return RPCRT4_OpenConnection(old_conn);
244 static int rpcrt4_conn_np_read(RpcConnection *Connection,
245 void *buffer, unsigned int count)
247 RpcConnection_np *npc = (RpcConnection_np *) Connection;
249 if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
250 (GetLastError() != ERROR_MORE_DATA))
255 static int rpcrt4_conn_np_write(RpcConnection *Connection,
256 const void *buffer, unsigned int count)
258 RpcConnection_np *npc = (RpcConnection_np *) Connection;
260 if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
265 static int rpcrt4_conn_np_close(RpcConnection *Connection)
267 RpcConnection_np *npc = (RpcConnection_np *) Connection;
269 FlushFileBuffers(npc->pipe);
270 CloseHandle(npc->pipe);
273 if (npc->ovl.hEvent) {
274 CloseHandle(npc->ovl.hEvent);
280 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
281 const char *networkaddr,
282 const char *endpoint)
284 twr_empty_floor_t *smb_floor;
285 twr_empty_floor_t *nb_floor;
287 size_t networkaddr_size;
288 size_t endpoint_size;
290 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
292 networkaddr_size = strlen(networkaddr) + 1;
293 endpoint_size = strlen(endpoint) + 1;
294 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
299 smb_floor = (twr_empty_floor_t *)tower_data;
301 tower_data += sizeof(*smb_floor);
303 smb_floor->count_lhs = sizeof(smb_floor->protid);
304 smb_floor->protid = EPM_PROTOCOL_SMB;
305 smb_floor->count_rhs = endpoint_size;
307 memcpy(tower_data, endpoint, endpoint_size);
308 tower_data += endpoint_size;
310 nb_floor = (twr_empty_floor_t *)tower_data;
312 tower_data += sizeof(*nb_floor);
314 nb_floor->count_lhs = sizeof(nb_floor->protid);
315 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
316 nb_floor->count_rhs = networkaddr_size;
318 memcpy(tower_data, networkaddr, networkaddr_size);
319 tower_data += networkaddr_size;
324 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
329 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
330 const twr_empty_floor_t *nb_floor;
332 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
334 if (tower_size < sizeof(*smb_floor))
335 return EPT_S_NOT_REGISTERED;
337 tower_data += sizeof(*smb_floor);
338 tower_size -= sizeof(*smb_floor);
340 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
341 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
342 (smb_floor->count_rhs > tower_size))
343 return EPT_S_NOT_REGISTERED;
347 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
349 return RPC_S_OUT_OF_RESOURCES;
350 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
352 tower_data += smb_floor->count_rhs;
353 tower_size -= smb_floor->count_rhs;
355 if (tower_size < sizeof(*nb_floor))
356 return EPT_S_NOT_REGISTERED;
358 nb_floor = (const twr_empty_floor_t *)tower_data;
360 tower_data += sizeof(*nb_floor);
361 tower_size -= sizeof(*nb_floor);
363 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
364 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
365 (nb_floor->count_rhs > tower_size))
366 return EPT_S_NOT_REGISTERED;
370 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
375 I_RpcFree(*endpoint);
378 return RPC_S_OUT_OF_RESOURCES;
380 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
386 typedef struct _RpcServerProtseq_np
388 RpcServerProtseq common;
390 } RpcServerProtseq_np;
392 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
394 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
396 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
400 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
402 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
403 SetEvent(npps->mgr_event);
406 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
408 HANDLE *objs = prev_array;
410 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
412 EnterCriticalSection(&protseq->cs);
414 /* open and count connections */
416 conn = protseq->conn;
418 RPCRT4_OpenConnection(conn);
419 if (rpcrt4_conn_get_wait_object(conn))
424 /* make array of connections */
426 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
428 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
431 ERR("couldn't allocate objs\n");
432 LeaveCriticalSection(&protseq->cs);
436 objs[0] = npps->mgr_event;
438 conn = protseq->conn;
440 if ((objs[*count] = rpcrt4_conn_get_wait_object(conn)))
444 LeaveCriticalSection(&protseq->cs);
448 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
450 HeapFree(GetProcessHeap(), 0, array);
453 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
456 HANDLE *objs = wait_array;
458 RpcConnection* cconn;
464 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
465 if (res == WAIT_OBJECT_0)
467 else if (res == WAIT_FAILED)
469 ERR("wait failed with error %ld\n", GetLastError());
474 b_handle = objs[res - WAIT_OBJECT_0];
475 /* find which connection got a RPC */
476 EnterCriticalSection(&protseq->cs);
477 conn = protseq->conn;
479 if (b_handle == rpcrt4_conn_get_wait_object(conn)) break;
484 RPCRT4_SpawnConnection(&cconn, conn);
486 ERR("failed to locate connection for handle %p\n", b_handle);
487 LeaveCriticalSection(&protseq->cs);
490 RPCRT4_new_client(cconn);
497 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
498 const char *networkaddr,
499 const char *endpoint)
501 twr_empty_floor_t *pipe_floor;
503 size_t endpoint_size;
505 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
507 endpoint_size = strlen(networkaddr) + 1;
508 size = sizeof(*pipe_floor) + endpoint_size;
513 pipe_floor = (twr_empty_floor_t *)tower_data;
515 tower_data += sizeof(*pipe_floor);
517 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
518 pipe_floor->protid = EPM_PROTOCOL_SMB;
519 pipe_floor->count_rhs = endpoint_size;
521 memcpy(tower_data, endpoint, endpoint_size);
522 tower_data += endpoint_size;
527 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
532 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
534 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
539 if (tower_size < sizeof(*pipe_floor))
540 return EPT_S_NOT_REGISTERED;
542 tower_data += sizeof(*pipe_floor);
543 tower_size -= sizeof(*pipe_floor);
545 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
546 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
547 (pipe_floor->count_rhs > tower_size))
548 return EPT_S_NOT_REGISTERED;
552 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
554 return RPC_S_OUT_OF_RESOURCES;
555 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
561 /**** ncacn_ip_tcp support ****/
563 typedef struct _RpcConnection_tcp
565 RpcConnection common;
567 HANDLE onEventAvailable;
568 HANDLE onEventHandled;
572 static DWORD WINAPI rpcrt4_tcp_poll_thread(LPVOID arg)
574 RpcConnection_tcp *tcpc;
576 struct pollfd pollInfo;
578 tcpc = (RpcConnection_tcp*) arg;
579 pollInfo.fd = tcpc->sock;
580 pollInfo.events = POLLIN;
584 ret = poll(&pollInfo, 1, 1000);
586 ERR("poll failed with error %d\n", ret);
589 if (pollInfo.revents & POLLIN)
591 SignalObjectAndWait(tcpc->onEventAvailable,
592 tcpc->onEventHandled, INFINITE, FALSE);
597 /* This avoids the tcpc being destroyed before we are done with it */
598 SetEvent(tcpc->onEventAvailable);
603 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
605 RpcConnection_tcp *tcpc;
606 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
610 tcpc->onEventAvailable = NULL;
611 tcpc->onEventHandled = NULL;
613 return &tcpc->common;
616 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
618 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
622 struct addrinfo *ai_cur;
623 struct addrinfo hints;
625 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
627 if (tcpc->sock != -1)
631 hints.ai_family = PF_UNSPEC;
632 hints.ai_socktype = SOCK_STREAM;
633 hints.ai_protocol = IPPROTO_TCP;
634 hints.ai_addrlen = 0;
635 hints.ai_addr = NULL;
636 hints.ai_canonname = NULL;
637 hints.ai_next = NULL;
639 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
642 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
643 return RPC_S_SERVER_UNAVAILABLE;
646 for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
652 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
653 host, sizeof(host), service, sizeof(service),
654 NI_NUMERICHOST | NI_NUMERICSERV);
655 TRACE("trying %s:%s\n", host, service);
658 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
661 WARN("socket() failed\n");
665 if (Connection->server)
667 HANDLE thread = NULL;
668 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
671 WARN("bind failed, error %d\n", ret);
674 ret = listen(sock, 10);
677 WARN("listen failed, error %d\n", ret);
680 /* need a non-blocking socket, otherwise accept() has a potential
681 * race-condition (poll() says it is readable, connection drops,
682 * and accept() blocks until the next connection comes...)
684 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
687 WARN("couldn't make socket non-blocking, error %d\n", ret);
690 tcpc->onEventAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
691 if (tcpc->onEventAvailable == NULL)
693 WARN("creating available event failed, error %lu\n", GetLastError());
696 tcpc->onEventHandled = CreateEventW(NULL, FALSE, FALSE, NULL);
697 if (tcpc->onEventHandled == NULL)
699 WARN("creating handled event failed, error %lu\n", GetLastError());
703 thread = CreateThread(NULL, 0, rpcrt4_tcp_poll_thread, tcpc, 0, NULL);
706 WARN("creating server polling thread failed, error %lu\n",
714 if (thread == NULL) /* ie. we failed somewhere */
717 if (tcpc->onEventAvailable != NULL)
719 CloseHandle(tcpc->onEventAvailable);
720 tcpc->onEventAvailable = NULL;
722 if (tcpc->onEventHandled != NULL)
724 CloseHandle(tcpc->onEventHandled);
725 tcpc->onEventHandled = NULL;
730 else /* it's a client */
732 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
734 WARN("connect() failed\n");
742 TRACE("connected\n");
747 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
748 return RPC_S_SERVER_UNAVAILABLE;
751 static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
753 RpcConnection_tcp *tcpc = (RpcConnection_tcp*) Connection;
754 return tcpc->onEventAvailable;
757 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
760 struct sockaddr_in address;
762 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
763 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
765 addrsize = sizeof(address);
766 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
767 SetEvent(server->onEventHandled);
770 ERR("Failed to accept a TCP connection: error %d\n", ret);
771 return RPC_S_SERVER_UNAVAILABLE;
774 TRACE("Accepted a new TCP connection\n");
778 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
779 void *buffer, unsigned int count)
781 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
782 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
783 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
787 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
788 const void *buffer, unsigned int count)
790 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
791 int r = write(tcpc->sock, buffer, count);
792 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
796 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
798 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
800 TRACE("%d\n", tcpc->sock);
802 if (tcpc->onEventAvailable != NULL)
804 /* it's a server connection */
806 WaitForSingleObject(tcpc->onEventAvailable, INFINITE);
807 CloseHandle(tcpc->onEventAvailable);
808 CloseHandle(tcpc->onEventHandled);
811 if (tcpc->sock != -1)
817 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
818 const char *networkaddr,
819 const char *endpoint)
821 twr_tcp_floor_t *tcp_floor;
822 twr_ipv4_floor_t *ipv4_floor;
824 struct addrinfo hints;
826 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
828 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
833 tcp_floor = (twr_tcp_floor_t *)tower_data;
834 tower_data += sizeof(*tcp_floor);
836 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
838 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
839 tcp_floor->protid = EPM_PROTOCOL_TCP;
840 tcp_floor->count_rhs = sizeof(tcp_floor->port);
842 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
843 ipv4_floor->protid = EPM_PROTOCOL_IP;
844 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
846 hints.ai_flags = AI_NUMERICHOST;
847 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
848 hints.ai_family = PF_INET;
849 hints.ai_socktype = SOCK_STREAM;
850 hints.ai_protocol = IPPROTO_TCP;
851 hints.ai_addrlen = 0;
852 hints.ai_addr = NULL;
853 hints.ai_canonname = NULL;
854 hints.ai_next = NULL;
856 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
859 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
862 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
867 if (ai->ai_family == PF_INET)
869 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
870 tcp_floor->port = sin->sin_port;
871 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
875 ERR("unexpected protocol family %d\n", ai->ai_family);
884 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
889 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
890 const twr_ipv4_floor_t *ipv4_floor;
891 struct in_addr in_addr;
893 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
895 if (tower_size < sizeof(*tcp_floor))
896 return EPT_S_NOT_REGISTERED;
898 tower_data += sizeof(*tcp_floor);
899 tower_size -= sizeof(*tcp_floor);
901 if (tower_size < sizeof(*ipv4_floor))
902 return EPT_S_NOT_REGISTERED;
904 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
906 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
907 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
908 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
909 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
910 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
911 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
912 return EPT_S_NOT_REGISTERED;
916 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
918 return RPC_S_OUT_OF_RESOURCES;
919 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
924 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
929 I_RpcFree(*endpoint);
932 return RPC_S_OUT_OF_RESOURCES;
934 in_addr.s_addr = ipv4_floor->ipv4addr;
935 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
937 ERR("inet_ntop: %s\n", strerror(errno));
938 I_RpcFree(*networkaddr);
942 I_RpcFree(*endpoint);
945 return EPT_S_NOT_REGISTERED;
952 static const struct connection_ops conn_protseq_list[] = {
954 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
955 rpcrt4_conn_np_alloc,
956 rpcrt4_ncacn_np_open,
957 rpcrt4_conn_np_get_connect_event,
958 rpcrt4_conn_np_handoff,
960 rpcrt4_conn_np_write,
961 rpcrt4_conn_np_close,
962 rpcrt4_ncacn_np_get_top_of_tower,
963 rpcrt4_ncacn_np_parse_top_of_tower,
966 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
967 rpcrt4_conn_np_alloc,
969 rpcrt4_conn_np_get_connect_event,
970 rpcrt4_conn_np_handoff,
972 rpcrt4_conn_np_write,
973 rpcrt4_conn_np_close,
974 rpcrt4_ncalrpc_get_top_of_tower,
975 rpcrt4_ncalrpc_parse_top_of_tower,
978 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
979 rpcrt4_conn_tcp_alloc,
980 rpcrt4_ncacn_ip_tcp_open,
981 rpcrt4_conn_tcp_get_wait_handle,
982 rpcrt4_conn_tcp_handoff,
983 rpcrt4_conn_tcp_read,
984 rpcrt4_conn_tcp_write,
985 rpcrt4_conn_tcp_close,
986 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
987 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
992 static const struct protseq_ops protseq_list[] =
996 rpcrt4_protseq_np_alloc,
997 rpcrt4_protseq_np_signal_state_changed,
998 rpcrt4_protseq_np_get_wait_array,
999 rpcrt4_protseq_np_free_wait_array,
1000 rpcrt4_protseq_np_wait_for_new_connection,
1004 rpcrt4_protseq_np_alloc,
1005 rpcrt4_protseq_np_signal_state_changed,
1006 rpcrt4_protseq_np_get_wait_array,
1007 rpcrt4_protseq_np_free_wait_array,
1008 rpcrt4_protseq_np_wait_for_new_connection,
1012 rpcrt4_protseq_np_alloc,
1013 rpcrt4_protseq_np_signal_state_changed,
1014 rpcrt4_protseq_np_get_wait_array,
1015 rpcrt4_protseq_np_free_wait_array,
1016 rpcrt4_protseq_np_wait_for_new_connection,
1020 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1022 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1025 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1026 if (!strcmp(protseq_list[i].name, protseq))
1027 return &protseq_list[i];
1031 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1034 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1035 if (!strcmp(conn_protseq_list[i].name, protseq))
1036 return &conn_protseq_list[i];
1040 /**** interface to rest of code ****/
1042 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
1044 TRACE("(Connection == ^%p)\n", Connection);
1046 return Connection->ops->open_connection(Connection);
1049 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1051 TRACE("(Connection == ^%p)\n", Connection);
1052 rpcrt4_conn_close(Connection);
1056 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1057 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1058 LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1060 const struct connection_ops *ops;
1061 RpcConnection* NewConnection;
1063 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1065 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1067 NewConnection = ops->alloc();
1068 NewConnection->Next = NULL;
1069 NewConnection->server = server;
1070 NewConnection->ops = ops;
1071 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1072 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1073 NewConnection->Used = Binding;
1074 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1075 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1076 NewConnection->NextCallId = 1;
1078 memset(&NewConnection->ctx, 0, sizeof(NewConnection->ctx));
1079 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1080 NewConnection->AuthInfo = AuthInfo;
1081 list_init(&NewConnection->conn_pool_entry);
1083 TRACE("connection: %p\n", NewConnection);
1084 *Connection = NewConnection;
1089 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1090 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1091 LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1093 RpcConnection *Connection;
1094 /* try to find a compatible connection from the connection pool */
1095 EnterCriticalSection(&connection_pool_cs);
1096 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1097 if ((Connection->AuthInfo == AuthInfo) &&
1098 !memcmp(&Connection->ActiveInterface, InterfaceId,
1099 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1100 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1101 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1102 !strcmp(Connection->Endpoint, Endpoint))
1104 list_remove(&Connection->conn_pool_entry);
1105 LeaveCriticalSection(&connection_pool_cs);
1106 TRACE("got connection from pool %p\n", Connection);
1110 LeaveCriticalSection(&connection_pool_cs);
1114 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1116 assert(!Connection->server);
1117 EnterCriticalSection(&connection_pool_cs);
1118 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1119 LeaveCriticalSection(&connection_pool_cs);
1123 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1127 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1128 rpcrt4_conn_get_name(OldConnection),
1129 OldConnection->NetworkAddr,
1130 OldConnection->Endpoint, NULL,
1131 OldConnection->AuthInfo, NULL);
1132 if (err == RPC_S_OK)
1133 rpcrt4_conn_handoff(OldConnection, *Connection);
1137 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1139 TRACE("connection: %p\n", Connection);
1141 RPCRT4_CloseConnection(Connection);
1142 RPCRT4_strfree(Connection->Endpoint);
1143 RPCRT4_strfree(Connection->NetworkAddr);
1144 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1145 HeapFree(GetProcessHeap(), 0, Connection);
1149 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1151 const char *protseq,
1152 const char *networkaddr,
1153 const char *endpoint)
1155 twr_empty_floor_t *protocol_floor;
1156 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1161 return RPC_S_INVALID_RPC_PROTSEQ;
1165 *tower_size = sizeof(*protocol_floor);
1166 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1170 protocol_floor = (twr_empty_floor_t *)tower_data;
1171 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1172 protocol_floor->protid = protseq_ops->epm_protocols[0];
1173 protocol_floor->count_rhs = 0;
1175 tower_data += sizeof(*protocol_floor);
1177 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1179 return EPT_S_NOT_REGISTERED;
1181 *tower_size += sizeof(*protocol_floor);
1186 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1192 const twr_empty_floor_t *protocol_floor;
1193 const twr_empty_floor_t *floor4;
1194 const struct connection_ops *protseq_ops = NULL;
1198 if (tower_size < sizeof(*protocol_floor))
1199 return EPT_S_NOT_REGISTERED;
1201 protocol_floor = (const twr_empty_floor_t *)tower_data;
1202 tower_data += sizeof(*protocol_floor);
1203 tower_size -= sizeof(*protocol_floor);
1204 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1205 (protocol_floor->count_rhs > tower_size))
1206 return EPT_S_NOT_REGISTERED;
1207 tower_data += protocol_floor->count_rhs;
1208 tower_size -= protocol_floor->count_rhs;
1210 floor4 = (const twr_empty_floor_t *)tower_data;
1211 if ((tower_size < sizeof(*floor4)) ||
1212 (floor4->count_lhs != sizeof(floor4->protid)))
1213 return EPT_S_NOT_REGISTERED;
1215 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1216 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1217 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1219 protseq_ops = &conn_protseq_list[i];
1224 return EPT_S_NOT_REGISTERED;
1226 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1228 if ((status == RPC_S_OK) && protseq)
1230 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1231 strcpy(*protseq, protseq_ops->name);
1237 /***********************************************************************
1238 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1240 * Checks if the given protocol sequence is known by the RPC system.
1241 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1244 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1248 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1249 ps, sizeof ps, NULL, NULL);
1250 if (rpcrt4_get_conn_protseq_ops(ps))
1253 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1255 return RPC_S_INVALID_RPC_PROTSEQ;
1258 /***********************************************************************
1259 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1261 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1263 UNICODE_STRING protseqW;
1265 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1267 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1268 RtlFreeUnicodeString(&protseqW);
1271 return RPC_S_OUT_OF_MEMORY;