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 RPC_STATUS rpcrt4_conn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
226 RpcConnection_np *old_npc = (RpcConnection_np *) old_conn;
227 RpcConnection_np *new_npc = (RpcConnection_np *) new_conn;
228 /* because of the way named pipes work, we'll transfer the connected pipe
229 * to the child, then reopen the server binding to continue listening */
231 new_npc->pipe = old_npc->pipe;
232 new_npc->ovl = old_npc->ovl;
234 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
235 return RPCRT4_OpenConnection(old_conn);
238 static int rpcrt4_conn_np_read(RpcConnection *Connection,
239 void *buffer, unsigned int count)
241 RpcConnection_np *npc = (RpcConnection_np *) Connection;
243 if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
244 (GetLastError() != ERROR_MORE_DATA))
249 static int rpcrt4_conn_np_write(RpcConnection *Connection,
250 const void *buffer, unsigned int count)
252 RpcConnection_np *npc = (RpcConnection_np *) Connection;
254 if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
259 static int rpcrt4_conn_np_close(RpcConnection *Connection)
261 RpcConnection_np *npc = (RpcConnection_np *) Connection;
263 FlushFileBuffers(npc->pipe);
264 CloseHandle(npc->pipe);
267 if (npc->ovl.hEvent) {
268 CloseHandle(npc->ovl.hEvent);
274 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
275 const char *networkaddr,
276 const char *endpoint)
278 twr_empty_floor_t *smb_floor;
279 twr_empty_floor_t *nb_floor;
281 size_t networkaddr_size;
282 size_t endpoint_size;
284 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
286 networkaddr_size = strlen(networkaddr) + 1;
287 endpoint_size = strlen(endpoint) + 1;
288 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
293 smb_floor = (twr_empty_floor_t *)tower_data;
295 tower_data += sizeof(*smb_floor);
297 smb_floor->count_lhs = sizeof(smb_floor->protid);
298 smb_floor->protid = EPM_PROTOCOL_SMB;
299 smb_floor->count_rhs = endpoint_size;
301 memcpy(tower_data, endpoint, endpoint_size);
302 tower_data += endpoint_size;
304 nb_floor = (twr_empty_floor_t *)tower_data;
306 tower_data += sizeof(*nb_floor);
308 nb_floor->count_lhs = sizeof(nb_floor->protid);
309 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
310 nb_floor->count_rhs = networkaddr_size;
312 memcpy(tower_data, networkaddr, networkaddr_size);
313 tower_data += networkaddr_size;
318 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
323 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
324 const twr_empty_floor_t *nb_floor;
326 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
328 if (tower_size < sizeof(*smb_floor))
329 return EPT_S_NOT_REGISTERED;
331 tower_data += sizeof(*smb_floor);
332 tower_size -= sizeof(*smb_floor);
334 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
335 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
336 (smb_floor->count_rhs > tower_size))
337 return EPT_S_NOT_REGISTERED;
341 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
343 return RPC_S_OUT_OF_RESOURCES;
344 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
346 tower_data += smb_floor->count_rhs;
347 tower_size -= smb_floor->count_rhs;
349 if (tower_size < sizeof(*nb_floor))
350 return EPT_S_NOT_REGISTERED;
352 nb_floor = (const twr_empty_floor_t *)tower_data;
354 tower_data += sizeof(*nb_floor);
355 tower_size -= sizeof(*nb_floor);
357 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
358 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
359 (nb_floor->count_rhs > tower_size))
360 return EPT_S_NOT_REGISTERED;
364 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
369 I_RpcFree(*endpoint);
372 return RPC_S_OUT_OF_RESOURCES;
374 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
380 typedef struct _RpcServerProtseq_np
382 RpcServerProtseq common;
384 } RpcServerProtseq_np;
386 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
388 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
390 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
394 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
396 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
397 SetEvent(npps->mgr_event);
400 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
402 HANDLE *objs = prev_array;
403 RpcConnection_np *conn;
404 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
406 EnterCriticalSection(&protseq->cs);
408 /* open and count connections */
410 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
412 RPCRT4_OpenConnection(&conn->common);
413 if (conn->ovl.hEvent)
415 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
418 /* make array of connections */
420 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
422 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
425 ERR("couldn't allocate objs\n");
426 LeaveCriticalSection(&protseq->cs);
430 objs[0] = npps->mgr_event;
432 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
434 if ((objs[*count] = conn->ovl.hEvent))
436 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
438 LeaveCriticalSection(&protseq->cs);
442 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
444 HeapFree(GetProcessHeap(), 0, array);
447 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
450 HANDLE *objs = wait_array;
452 RpcConnection *cconn;
453 RpcConnection_np *conn;
458 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
459 if (res == WAIT_OBJECT_0)
461 else if (res == WAIT_FAILED)
463 ERR("wait failed with error %ld\n", GetLastError());
468 b_handle = objs[res - WAIT_OBJECT_0];
469 /* find which connection got a RPC */
470 EnterCriticalSection(&protseq->cs);
471 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
473 if (b_handle == conn->ovl.hEvent) break;
474 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
478 RPCRT4_SpawnConnection(&cconn, &conn->common);
480 ERR("failed to locate connection for handle %p\n", b_handle);
481 LeaveCriticalSection(&protseq->cs);
484 RPCRT4_new_client(cconn);
491 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
492 const char *networkaddr,
493 const char *endpoint)
495 twr_empty_floor_t *pipe_floor;
497 size_t endpoint_size;
499 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
501 endpoint_size = strlen(networkaddr) + 1;
502 size = sizeof(*pipe_floor) + endpoint_size;
507 pipe_floor = (twr_empty_floor_t *)tower_data;
509 tower_data += sizeof(*pipe_floor);
511 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
512 pipe_floor->protid = EPM_PROTOCOL_SMB;
513 pipe_floor->count_rhs = endpoint_size;
515 memcpy(tower_data, endpoint, endpoint_size);
516 tower_data += endpoint_size;
521 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
526 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
528 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
533 if (tower_size < sizeof(*pipe_floor))
534 return EPT_S_NOT_REGISTERED;
536 tower_data += sizeof(*pipe_floor);
537 tower_size -= sizeof(*pipe_floor);
539 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
540 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
541 (pipe_floor->count_rhs > tower_size))
542 return EPT_S_NOT_REGISTERED;
546 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
548 return RPC_S_OUT_OF_RESOURCES;
549 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
555 /**** ncacn_ip_tcp support ****/
557 typedef struct _RpcConnection_tcp
559 RpcConnection common;
563 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
565 RpcConnection_tcp *tcpc;
566 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
570 return &tcpc->common;
573 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
575 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
579 struct addrinfo *ai_cur;
580 struct addrinfo hints;
582 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
584 if (tcpc->sock != -1)
588 hints.ai_family = PF_UNSPEC;
589 hints.ai_socktype = SOCK_STREAM;
590 hints.ai_protocol = IPPROTO_TCP;
591 hints.ai_addrlen = 0;
592 hints.ai_addr = NULL;
593 hints.ai_canonname = NULL;
594 hints.ai_next = NULL;
596 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
599 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
600 return RPC_S_SERVER_UNAVAILABLE;
603 for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
609 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
610 host, sizeof(host), service, sizeof(service),
611 NI_NUMERICHOST | NI_NUMERICSERV);
612 TRACE("trying %s:%s\n", host, service);
615 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
618 WARN("socket() failed\n");
622 if (Connection->server)
624 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
627 WARN("bind failed, error %d\n", ret);
631 ret = listen(sock, 10);
634 WARN("listen failed, error %d\n", ret);
638 /* need a non-blocking socket, otherwise accept() has a potential
639 * race-condition (poll() says it is readable, connection drops,
640 * and accept() blocks until the next connection comes...)
642 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
645 WARN("couldn't make socket non-blocking, error %d\n", ret);
651 else /* it's a client */
653 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
655 WARN("connect() failed\n");
663 TRACE("connected\n");
668 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
669 return RPC_S_SERVER_UNAVAILABLE;
672 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
675 struct sockaddr_in address;
677 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
678 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
680 addrsize = sizeof(address);
681 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
684 ERR("Failed to accept a TCP connection: error %d\n", ret);
685 return RPC_S_SERVER_UNAVAILABLE;
688 TRACE("Accepted a new TCP connection\n");
692 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
693 void *buffer, unsigned int count)
695 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
696 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
697 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
701 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
702 const void *buffer, unsigned int count)
704 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
705 int r = write(tcpc->sock, buffer, count);
706 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
710 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
712 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
714 TRACE("%d\n", tcpc->sock);
716 if (tcpc->sock != -1)
722 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
723 const char *networkaddr,
724 const char *endpoint)
726 twr_tcp_floor_t *tcp_floor;
727 twr_ipv4_floor_t *ipv4_floor;
729 struct addrinfo hints;
731 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
733 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
738 tcp_floor = (twr_tcp_floor_t *)tower_data;
739 tower_data += sizeof(*tcp_floor);
741 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
743 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
744 tcp_floor->protid = EPM_PROTOCOL_TCP;
745 tcp_floor->count_rhs = sizeof(tcp_floor->port);
747 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
748 ipv4_floor->protid = EPM_PROTOCOL_IP;
749 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
751 hints.ai_flags = AI_NUMERICHOST;
752 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
753 hints.ai_family = PF_INET;
754 hints.ai_socktype = SOCK_STREAM;
755 hints.ai_protocol = IPPROTO_TCP;
756 hints.ai_addrlen = 0;
757 hints.ai_addr = NULL;
758 hints.ai_canonname = NULL;
759 hints.ai_next = NULL;
761 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
764 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
767 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
772 if (ai->ai_family == PF_INET)
774 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
775 tcp_floor->port = sin->sin_port;
776 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
780 ERR("unexpected protocol family %d\n", ai->ai_family);
789 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
794 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
795 const twr_ipv4_floor_t *ipv4_floor;
796 struct in_addr in_addr;
798 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
800 if (tower_size < sizeof(*tcp_floor))
801 return EPT_S_NOT_REGISTERED;
803 tower_data += sizeof(*tcp_floor);
804 tower_size -= sizeof(*tcp_floor);
806 if (tower_size < sizeof(*ipv4_floor))
807 return EPT_S_NOT_REGISTERED;
809 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
811 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
812 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
813 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
814 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
815 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
816 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
817 return EPT_S_NOT_REGISTERED;
821 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
823 return RPC_S_OUT_OF_RESOURCES;
824 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
829 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
834 I_RpcFree(*endpoint);
837 return RPC_S_OUT_OF_RESOURCES;
839 in_addr.s_addr = ipv4_floor->ipv4addr;
840 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
842 ERR("inet_ntop: %s\n", strerror(errno));
843 I_RpcFree(*networkaddr);
847 I_RpcFree(*endpoint);
850 return EPT_S_NOT_REGISTERED;
857 typedef struct _RpcServerProtseq_sock
859 RpcServerProtseq common;
862 } RpcServerProtseq_sock;
864 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
866 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
870 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
872 fcntl(fds[0], F_SETFL, O_NONBLOCK);
873 fcntl(fds[1], F_SETFL, O_NONBLOCK);
874 ps->mgr_event_rcv = fds[0];
875 ps->mgr_event_snd = fds[1];
879 ERR("socketpair failed with error %s\n", strerror(errno));
880 HeapFree(GetProcessHeap(), 0, ps);
887 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
889 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
891 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
894 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
896 struct pollfd *poll_info = prev_array;
897 RpcConnection_tcp *conn;
898 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
900 EnterCriticalSection(&protseq->cs);
902 /* open and count connections */
904 conn = (RpcConnection_tcp *)protseq->conn;
906 RPCRT4_OpenConnection(&conn->common);
907 if (conn->sock != -1)
909 conn = (RpcConnection_tcp *)conn->common.Next;
912 /* make array of connections */
914 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
916 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
919 ERR("couldn't allocate poll_info\n");
920 LeaveCriticalSection(&protseq->cs);
924 poll_info[0].fd = sockps->mgr_event_rcv;
925 poll_info[0].events = POLLIN;
927 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
929 if (conn->sock != -1)
931 poll_info[*count].fd = conn->sock;
932 poll_info[*count].events = POLLIN;
935 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
937 LeaveCriticalSection(&protseq->cs);
941 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
943 HeapFree(GetProcessHeap(), 0, array);
946 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
948 struct pollfd *poll_info = wait_array;
950 RpcConnection *cconn;
951 RpcConnection_tcp *conn;
956 ret = poll(poll_info, count, -1);
959 ERR("poll failed with error %d\n", ret);
963 for (i = 0; i < count; i++)
964 if (poll_info[i].revents & POLLIN)
966 /* RPC server event */
970 read(poll_info[0].fd, &dummy, sizeof(dummy));
974 /* find which connection got a RPC */
975 EnterCriticalSection(&protseq->cs);
976 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
978 if (poll_info[i].fd == conn->sock) break;
979 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
983 RPCRT4_SpawnConnection(&cconn, &conn->common);
985 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
986 LeaveCriticalSection(&protseq->cs);
988 RPCRT4_new_client(cconn);
996 static const struct connection_ops conn_protseq_list[] = {
998 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
999 rpcrt4_conn_np_alloc,
1000 rpcrt4_ncacn_np_open,
1001 rpcrt4_conn_np_handoff,
1002 rpcrt4_conn_np_read,
1003 rpcrt4_conn_np_write,
1004 rpcrt4_conn_np_close,
1005 rpcrt4_ncacn_np_get_top_of_tower,
1006 rpcrt4_ncacn_np_parse_top_of_tower,
1009 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1010 rpcrt4_conn_np_alloc,
1011 rpcrt4_ncalrpc_open,
1012 rpcrt4_conn_np_handoff,
1013 rpcrt4_conn_np_read,
1014 rpcrt4_conn_np_write,
1015 rpcrt4_conn_np_close,
1016 rpcrt4_ncalrpc_get_top_of_tower,
1017 rpcrt4_ncalrpc_parse_top_of_tower,
1020 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1021 rpcrt4_conn_tcp_alloc,
1022 rpcrt4_ncacn_ip_tcp_open,
1023 rpcrt4_conn_tcp_handoff,
1024 rpcrt4_conn_tcp_read,
1025 rpcrt4_conn_tcp_write,
1026 rpcrt4_conn_tcp_close,
1027 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1028 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1033 static const struct protseq_ops protseq_list[] =
1037 rpcrt4_protseq_np_alloc,
1038 rpcrt4_protseq_np_signal_state_changed,
1039 rpcrt4_protseq_np_get_wait_array,
1040 rpcrt4_protseq_np_free_wait_array,
1041 rpcrt4_protseq_np_wait_for_new_connection,
1045 rpcrt4_protseq_np_alloc,
1046 rpcrt4_protseq_np_signal_state_changed,
1047 rpcrt4_protseq_np_get_wait_array,
1048 rpcrt4_protseq_np_free_wait_array,
1049 rpcrt4_protseq_np_wait_for_new_connection,
1053 rpcrt4_protseq_sock_alloc,
1054 rpcrt4_protseq_sock_signal_state_changed,
1055 rpcrt4_protseq_sock_get_wait_array,
1056 rpcrt4_protseq_sock_free_wait_array,
1057 rpcrt4_protseq_sock_wait_for_new_connection,
1061 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1063 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1066 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1067 if (!strcmp(protseq_list[i].name, protseq))
1068 return &protseq_list[i];
1072 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1075 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1076 if (!strcmp(conn_protseq_list[i].name, protseq))
1077 return &conn_protseq_list[i];
1081 /**** interface to rest of code ****/
1083 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
1085 TRACE("(Connection == ^%p)\n", Connection);
1087 return Connection->ops->open_connection(Connection);
1090 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1092 TRACE("(Connection == ^%p)\n", Connection);
1093 rpcrt4_conn_close(Connection);
1097 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1098 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1099 LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1101 const struct connection_ops *ops;
1102 RpcConnection* NewConnection;
1104 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1106 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1108 NewConnection = ops->alloc();
1109 NewConnection->Next = NULL;
1110 NewConnection->server = server;
1111 NewConnection->ops = ops;
1112 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1113 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1114 NewConnection->Used = Binding;
1115 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1116 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1117 NewConnection->NextCallId = 1;
1119 memset(&NewConnection->ctx, 0, sizeof(NewConnection->ctx));
1120 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1121 NewConnection->AuthInfo = AuthInfo;
1122 list_init(&NewConnection->conn_pool_entry);
1124 TRACE("connection: %p\n", NewConnection);
1125 *Connection = NewConnection;
1130 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1131 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1132 LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1134 RpcConnection *Connection;
1135 /* try to find a compatible connection from the connection pool */
1136 EnterCriticalSection(&connection_pool_cs);
1137 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1138 if ((Connection->AuthInfo == AuthInfo) &&
1139 !memcmp(&Connection->ActiveInterface, InterfaceId,
1140 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1141 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1142 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1143 !strcmp(Connection->Endpoint, Endpoint))
1145 list_remove(&Connection->conn_pool_entry);
1146 LeaveCriticalSection(&connection_pool_cs);
1147 TRACE("got connection from pool %p\n", Connection);
1151 LeaveCriticalSection(&connection_pool_cs);
1155 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1157 assert(!Connection->server);
1158 EnterCriticalSection(&connection_pool_cs);
1159 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1160 LeaveCriticalSection(&connection_pool_cs);
1164 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1168 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1169 rpcrt4_conn_get_name(OldConnection),
1170 OldConnection->NetworkAddr,
1171 OldConnection->Endpoint, NULL,
1172 OldConnection->AuthInfo, NULL);
1173 if (err == RPC_S_OK)
1174 rpcrt4_conn_handoff(OldConnection, *Connection);
1178 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1180 TRACE("connection: %p\n", Connection);
1182 RPCRT4_CloseConnection(Connection);
1183 RPCRT4_strfree(Connection->Endpoint);
1184 RPCRT4_strfree(Connection->NetworkAddr);
1185 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1186 HeapFree(GetProcessHeap(), 0, Connection);
1190 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1192 const char *protseq,
1193 const char *networkaddr,
1194 const char *endpoint)
1196 twr_empty_floor_t *protocol_floor;
1197 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1202 return RPC_S_INVALID_RPC_PROTSEQ;
1206 *tower_size = sizeof(*protocol_floor);
1207 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1211 protocol_floor = (twr_empty_floor_t *)tower_data;
1212 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1213 protocol_floor->protid = protseq_ops->epm_protocols[0];
1214 protocol_floor->count_rhs = 0;
1216 tower_data += sizeof(*protocol_floor);
1218 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1220 return EPT_S_NOT_REGISTERED;
1222 *tower_size += sizeof(*protocol_floor);
1227 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1233 const twr_empty_floor_t *protocol_floor;
1234 const twr_empty_floor_t *floor4;
1235 const struct connection_ops *protseq_ops = NULL;
1239 if (tower_size < sizeof(*protocol_floor))
1240 return EPT_S_NOT_REGISTERED;
1242 protocol_floor = (const twr_empty_floor_t *)tower_data;
1243 tower_data += sizeof(*protocol_floor);
1244 tower_size -= sizeof(*protocol_floor);
1245 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1246 (protocol_floor->count_rhs > tower_size))
1247 return EPT_S_NOT_REGISTERED;
1248 tower_data += protocol_floor->count_rhs;
1249 tower_size -= protocol_floor->count_rhs;
1251 floor4 = (const twr_empty_floor_t *)tower_data;
1252 if ((tower_size < sizeof(*floor4)) ||
1253 (floor4->count_lhs != sizeof(floor4->protid)))
1254 return EPT_S_NOT_REGISTERED;
1256 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1257 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1258 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1260 protseq_ops = &conn_protseq_list[i];
1265 return EPT_S_NOT_REGISTERED;
1267 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1269 if ((status == RPC_S_OK) && protseq)
1271 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1272 strcpy(*protseq, protseq_ops->name);
1278 /***********************************************************************
1279 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1281 * Checks if the given protocol sequence is known by the RPC system.
1282 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1285 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1289 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1290 ps, sizeof ps, NULL, NULL);
1291 if (rpcrt4_get_conn_protseq_ops(ps))
1294 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1296 return RPC_S_INVALID_RPC_PROTSEQ;
1299 /***********************************************************************
1300 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1302 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1304 UNICODE_STRING protseqW;
1306 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1308 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1309 RtlFreeUnicodeString(&protseqW);
1312 return RPC_S_OUT_OF_MEMORY;