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
97 static RpcConnection *rpcrt4_conn_np_alloc(void)
99 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
103 memset(&npc->ovl, 0, sizeof(npc->ovl));
104 npc->listening = FALSE;
109 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
114 npc->listening = TRUE;
115 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
118 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
119 if (GetLastError() == ERROR_PIPE_CONNECTED) {
120 SetEvent(npc->ovl.hEvent);
123 if (GetLastError() == ERROR_IO_PENDING) {
124 /* FIXME: looks like we need to GetOverlappedResult here? */
127 npc->listening = FALSE;
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 %ld\n", GetLastError());
142 if (GetLastError() == ERROR_FILE_EXISTS)
143 return RPC_S_DUPLICATE_ENDPOINT;
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 */
156 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
158 RpcConnection_np *npc = (RpcConnection_np *) Connection;
162 TRACE("connecting to %s\n", pname);
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=%lx\n", err);
171 return RPC_S_SERVER_TOO_BUSY;
174 return RPC_S_SERVER_UNAVAILABLE;
175 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
176 err = GetLastError();
177 WARN("connection failed, error=%lx\n", err);
178 return RPC_S_SERVER_UNAVAILABLE;
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);
193 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
195 RpcConnection_np *npc = (RpcConnection_np *) Connection;
196 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
200 /* already connected? */
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);
214 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
216 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
219 RpcConnection *Connection;
221 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
222 endpoint, NULL, NULL, NULL);
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);
233 EnterCriticalSection(&protseq->cs);
234 Connection->Next = protseq->conn;
235 protseq->conn = Connection;
236 LeaveCriticalSection(&protseq->cs);
241 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
243 RpcConnection_np *npc = (RpcConnection_np *) Connection;
244 static LPCSTR prefix = "\\\\.";
248 /* already connected? */
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);
261 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
263 static LPCSTR prefix = "\\\\.";
266 RpcConnection *Connection;
268 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
269 endpoint, NULL, NULL, NULL);
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);
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;
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)
298 static LPCSTR 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);
310 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
314 static LPCSTR 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);
328 static int rpcrt4_conn_np_read(RpcConnection *Connection,
329 void *buffer, unsigned int count)
331 RpcConnection_np *npc = (RpcConnection_np *) Connection;
333 if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
334 (GetLastError() != ERROR_MORE_DATA))
339 static int rpcrt4_conn_np_write(RpcConnection *Connection,
340 const void *buffer, unsigned int count)
342 RpcConnection_np *npc = (RpcConnection_np *) Connection;
344 if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
349 static int rpcrt4_conn_np_close(RpcConnection *Connection)
351 RpcConnection_np *npc = (RpcConnection_np *) Connection;
353 FlushFileBuffers(npc->pipe);
354 CloseHandle(npc->pipe);
357 if (npc->ovl.hEvent) {
358 CloseHandle(npc->ovl.hEvent);
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;
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;
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;
408 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
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;
431 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
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;
454 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
459 I_RpcFree(*endpoint);
462 return RPC_S_OUT_OF_RESOURCES;
464 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
470 typedef struct _RpcServerProtseq_np
472 RpcServerProtseq common;
474 } RpcServerProtseq_np;
476 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
478 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
480 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
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 */
500 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
502 rpcrt4_conn_listen_pipe(conn);
503 if (conn->ovl.hEvent)
505 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
508 /* make array of connections */
510 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
512 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
515 ERR("couldn't allocate objs\n");
516 LeaveCriticalSection(&protseq->cs);
520 objs[0] = npps->mgr_event;
522 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
524 if ((objs[*count] = conn->ovl.hEvent))
526 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
528 LeaveCriticalSection(&protseq->cs);
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)
540 HANDLE *objs = wait_array;
542 RpcConnection *cconn;
543 RpcConnection_np *conn;
548 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
549 if (res == WAIT_OBJECT_0)
551 else if (res == WAIT_FAILED)
553 ERR("wait failed with error %ld\n", GetLastError());
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);
563 if (b_handle == conn->ovl.hEvent) break;
564 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
568 RPCRT4_SpawnConnection(&cconn, &conn->common);
570 ERR("failed to locate connection for handle %p\n", b_handle);
571 LeaveCriticalSection(&protseq->cs);
574 RPCRT4_new_client(cconn);
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;
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;
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;
611 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
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);
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;
636 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
638 return RPC_S_OUT_OF_RESOURCES;
639 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
645 /**** ncacn_ip_tcp support ****/
647 typedef struct _RpcConnection_tcp
649 RpcConnection common;
653 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
655 RpcConnection_tcp *tcpc;
656 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
660 return &tcpc->common;
663 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
665 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
669 struct addrinfo *ai_cur;
670 struct addrinfo hints;
672 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
674 if (tcpc->sock != -1)
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);
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)
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);
709 WARN("socket() failed: %s\n", strerror(errno));
713 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
715 WARN("connect() failed: %s\n", strerror(errno));
722 TRACE("connected\n");
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;
737 struct addrinfo *ai_cur;
738 struct addrinfo hints;
740 TRACE("(%p, %s)\n", protseq, endpoint);
742 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
743 hints.ai_family = PF_UNSPEC;
744 hints.ai_socktype = SOCK_STREAM;
745 hints.ai_protocol = IPPROTO_TCP;
746 hints.ai_addrlen = 0;
747 hints.ai_addr = NULL;
748 hints.ai_canonname = NULL;
749 hints.ai_next = NULL;
751 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
754 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
756 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
757 return RPC_S_INVALID_ENDPOINT_FORMAT;
758 return RPC_S_CANT_CREATE_ENDPOINT;
761 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
763 RpcConnection_tcp *tcpc;
768 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
769 host, sizeof(host), service, sizeof(service),
770 NI_NUMERICHOST | NI_NUMERICSERV);
771 TRACE("trying %s:%s\n", host, service);
774 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
777 WARN("socket() failed: %s\n", strerror(errno));
778 status = RPC_S_CANT_CREATE_ENDPOINT;
782 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
785 WARN("bind failed: %s\n", strerror(errno));
787 if (errno == EADDRINUSE)
788 status = RPC_S_DUPLICATE_ENDPOINT;
790 status = RPC_S_CANT_CREATE_ENDPOINT;
793 status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
794 protseq->Protseq, NULL, endpoint, NULL,
796 if (status != RPC_S_OK)
802 ret = listen(sock, protseq->MaxCalls);
805 WARN("listen failed: %s\n", strerror(errno));
807 status = RPC_S_OUT_OF_RESOURCES;
810 /* need a non-blocking socket, otherwise accept() has a potential
811 * race-condition (poll() says it is readable, connection drops,
812 * and accept() blocks until the next connection comes...)
814 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
817 WARN("couldn't make socket non-blocking, error %d\n", ret);
819 status = RPC_S_OUT_OF_RESOURCES;
826 EnterCriticalSection(&protseq->cs);
827 tcpc->common.Next = protseq->conn;
828 protseq->conn = &tcpc->common;
829 LeaveCriticalSection(&protseq->cs);
831 TRACE("listening on %s\n", endpoint);
836 ERR("couldn't listen on port %s\n", endpoint);
840 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
843 struct sockaddr_in address;
845 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
846 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
848 addrsize = sizeof(address);
849 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
852 ERR("Failed to accept a TCP connection: error %d\n", ret);
853 return RPC_S_OUT_OF_RESOURCES;
855 /* reset to blocking behaviour */
856 fcntl(ret, F_SETFL, 0);
858 TRACE("Accepted a new TCP connection\n");
862 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
863 void *buffer, unsigned int count)
865 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
866 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
867 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
871 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
872 const void *buffer, unsigned int count)
874 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
875 int r = write(tcpc->sock, buffer, count);
876 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
880 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
882 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
884 TRACE("%d\n", tcpc->sock);
886 if (tcpc->sock != -1)
892 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
893 const char *networkaddr,
894 const char *endpoint)
896 twr_tcp_floor_t *tcp_floor;
897 twr_ipv4_floor_t *ipv4_floor;
899 struct addrinfo hints;
901 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
903 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
908 tcp_floor = (twr_tcp_floor_t *)tower_data;
909 tower_data += sizeof(*tcp_floor);
911 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
913 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
914 tcp_floor->protid = EPM_PROTOCOL_TCP;
915 tcp_floor->count_rhs = sizeof(tcp_floor->port);
917 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
918 ipv4_floor->protid = EPM_PROTOCOL_IP;
919 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
921 hints.ai_flags = AI_NUMERICHOST;
922 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
923 hints.ai_family = PF_INET;
924 hints.ai_socktype = SOCK_STREAM;
925 hints.ai_protocol = IPPROTO_TCP;
926 hints.ai_addrlen = 0;
927 hints.ai_addr = NULL;
928 hints.ai_canonname = NULL;
929 hints.ai_next = NULL;
931 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
934 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
937 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
942 if (ai->ai_family == PF_INET)
944 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
945 tcp_floor->port = sin->sin_port;
946 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
950 ERR("unexpected protocol family %d\n", ai->ai_family);
959 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
964 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
965 const twr_ipv4_floor_t *ipv4_floor;
966 struct in_addr in_addr;
968 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
970 if (tower_size < sizeof(*tcp_floor))
971 return EPT_S_NOT_REGISTERED;
973 tower_data += sizeof(*tcp_floor);
974 tower_size -= sizeof(*tcp_floor);
976 if (tower_size < sizeof(*ipv4_floor))
977 return EPT_S_NOT_REGISTERED;
979 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
981 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
982 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
983 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
984 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
985 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
986 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
987 return EPT_S_NOT_REGISTERED;
991 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
993 return RPC_S_OUT_OF_RESOURCES;
994 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
999 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1004 I_RpcFree(*endpoint);
1007 return RPC_S_OUT_OF_RESOURCES;
1009 in_addr.s_addr = ipv4_floor->ipv4addr;
1010 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1012 ERR("inet_ntop: %s\n", strerror(errno));
1013 I_RpcFree(*networkaddr);
1014 *networkaddr = NULL;
1017 I_RpcFree(*endpoint);
1020 return EPT_S_NOT_REGISTERED;
1027 typedef struct _RpcServerProtseq_sock
1029 RpcServerProtseq common;
1032 } RpcServerProtseq_sock;
1034 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1036 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1040 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1042 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1043 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1044 ps->mgr_event_rcv = fds[0];
1045 ps->mgr_event_snd = fds[1];
1049 ERR("socketpair failed with error %s\n", strerror(errno));
1050 HeapFree(GetProcessHeap(), 0, ps);
1057 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1059 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1061 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1064 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1066 struct pollfd *poll_info = prev_array;
1067 RpcConnection_tcp *conn;
1068 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1070 EnterCriticalSection(&protseq->cs);
1072 /* open and count connections */
1074 conn = (RpcConnection_tcp *)protseq->conn;
1076 if (conn->sock != -1)
1078 conn = (RpcConnection_tcp *)conn->common.Next;
1081 /* make array of connections */
1083 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1085 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1088 ERR("couldn't allocate poll_info\n");
1089 LeaveCriticalSection(&protseq->cs);
1093 poll_info[0].fd = sockps->mgr_event_rcv;
1094 poll_info[0].events = POLLIN;
1096 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1098 if (conn->sock != -1)
1100 poll_info[*count].fd = conn->sock;
1101 poll_info[*count].events = POLLIN;
1104 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1106 LeaveCriticalSection(&protseq->cs);
1110 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1112 HeapFree(GetProcessHeap(), 0, array);
1115 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1117 struct pollfd *poll_info = wait_array;
1119 RpcConnection *cconn;
1120 RpcConnection_tcp *conn;
1125 ret = poll(poll_info, count, -1);
1128 ERR("poll failed with error %d\n", ret);
1132 for (i = 0; i < count; i++)
1133 if (poll_info[i].revents & POLLIN)
1135 /* RPC server event */
1139 read(poll_info[0].fd, &dummy, sizeof(dummy));
1143 /* find which connection got a RPC */
1144 EnterCriticalSection(&protseq->cs);
1145 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1147 if (poll_info[i].fd == conn->sock) break;
1148 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1152 RPCRT4_SpawnConnection(&cconn, &conn->common);
1154 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1155 LeaveCriticalSection(&protseq->cs);
1157 RPCRT4_new_client(cconn);
1165 static const struct connection_ops conn_protseq_list[] = {
1167 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1168 rpcrt4_conn_np_alloc,
1169 rpcrt4_ncacn_np_open,
1170 rpcrt4_ncacn_np_handoff,
1171 rpcrt4_conn_np_read,
1172 rpcrt4_conn_np_write,
1173 rpcrt4_conn_np_close,
1174 rpcrt4_ncacn_np_get_top_of_tower,
1175 rpcrt4_ncacn_np_parse_top_of_tower,
1178 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1179 rpcrt4_conn_np_alloc,
1180 rpcrt4_ncalrpc_open,
1181 rpcrt4_ncalrpc_handoff,
1182 rpcrt4_conn_np_read,
1183 rpcrt4_conn_np_write,
1184 rpcrt4_conn_np_close,
1185 rpcrt4_ncalrpc_get_top_of_tower,
1186 rpcrt4_ncalrpc_parse_top_of_tower,
1189 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1190 rpcrt4_conn_tcp_alloc,
1191 rpcrt4_ncacn_ip_tcp_open,
1192 rpcrt4_conn_tcp_handoff,
1193 rpcrt4_conn_tcp_read,
1194 rpcrt4_conn_tcp_write,
1195 rpcrt4_conn_tcp_close,
1196 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1197 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1202 static const struct protseq_ops protseq_list[] =
1206 rpcrt4_protseq_np_alloc,
1207 rpcrt4_protseq_np_signal_state_changed,
1208 rpcrt4_protseq_np_get_wait_array,
1209 rpcrt4_protseq_np_free_wait_array,
1210 rpcrt4_protseq_np_wait_for_new_connection,
1211 rpcrt4_protseq_ncacn_np_open_endpoint,
1215 rpcrt4_protseq_np_alloc,
1216 rpcrt4_protseq_np_signal_state_changed,
1217 rpcrt4_protseq_np_get_wait_array,
1218 rpcrt4_protseq_np_free_wait_array,
1219 rpcrt4_protseq_np_wait_for_new_connection,
1220 rpcrt4_protseq_ncalrpc_open_endpoint,
1224 rpcrt4_protseq_sock_alloc,
1225 rpcrt4_protseq_sock_signal_state_changed,
1226 rpcrt4_protseq_sock_get_wait_array,
1227 rpcrt4_protseq_sock_free_wait_array,
1228 rpcrt4_protseq_sock_wait_for_new_connection,
1229 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1233 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1235 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1238 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1239 if (!strcmp(protseq_list[i].name, protseq))
1240 return &protseq_list[i];
1244 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1247 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1248 if (!strcmp(conn_protseq_list[i].name, protseq))
1249 return &conn_protseq_list[i];
1253 /**** interface to rest of code ****/
1255 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1257 TRACE("(Connection == ^%p)\n", Connection);
1259 assert(!Connection->server);
1260 return Connection->ops->open_connection_client(Connection);
1263 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1265 TRACE("(Connection == ^%p)\n", Connection);
1266 rpcrt4_conn_close(Connection);
1270 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1271 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1272 LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1274 const struct connection_ops *ops;
1275 RpcConnection* NewConnection;
1277 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1279 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1281 NewConnection = ops->alloc();
1282 NewConnection->Next = NULL;
1283 NewConnection->server = server;
1284 NewConnection->ops = ops;
1285 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1286 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1287 NewConnection->Used = Binding;
1288 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1289 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1290 NewConnection->NextCallId = 1;
1292 memset(&NewConnection->ctx, 0, sizeof(NewConnection->ctx));
1293 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1294 NewConnection->AuthInfo = AuthInfo;
1295 list_init(&NewConnection->conn_pool_entry);
1297 TRACE("connection: %p\n", NewConnection);
1298 *Connection = NewConnection;
1303 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1304 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1305 LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1307 RpcConnection *Connection;
1308 /* try to find a compatible connection from the connection pool */
1309 EnterCriticalSection(&connection_pool_cs);
1310 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1311 if ((Connection->AuthInfo == AuthInfo) &&
1312 !memcmp(&Connection->ActiveInterface, InterfaceId,
1313 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1314 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1315 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1316 !strcmp(Connection->Endpoint, Endpoint))
1318 list_remove(&Connection->conn_pool_entry);
1319 LeaveCriticalSection(&connection_pool_cs);
1320 TRACE("got connection from pool %p\n", Connection);
1324 LeaveCriticalSection(&connection_pool_cs);
1328 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1330 assert(!Connection->server);
1331 EnterCriticalSection(&connection_pool_cs);
1332 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1333 LeaveCriticalSection(&connection_pool_cs);
1337 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1341 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1342 rpcrt4_conn_get_name(OldConnection),
1343 OldConnection->NetworkAddr,
1344 OldConnection->Endpoint, NULL,
1345 OldConnection->AuthInfo, NULL);
1346 if (err == RPC_S_OK)
1347 rpcrt4_conn_handoff(OldConnection, *Connection);
1351 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1353 TRACE("connection: %p\n", Connection);
1355 RPCRT4_CloseConnection(Connection);
1356 RPCRT4_strfree(Connection->Endpoint);
1357 RPCRT4_strfree(Connection->NetworkAddr);
1358 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1359 HeapFree(GetProcessHeap(), 0, Connection);
1363 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1365 const char *protseq,
1366 const char *networkaddr,
1367 const char *endpoint)
1369 twr_empty_floor_t *protocol_floor;
1370 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1375 return RPC_S_INVALID_RPC_PROTSEQ;
1379 *tower_size = sizeof(*protocol_floor);
1380 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1384 protocol_floor = (twr_empty_floor_t *)tower_data;
1385 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1386 protocol_floor->protid = protseq_ops->epm_protocols[0];
1387 protocol_floor->count_rhs = 0;
1389 tower_data += sizeof(*protocol_floor);
1391 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1393 return EPT_S_NOT_REGISTERED;
1395 *tower_size += sizeof(*protocol_floor);
1400 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1406 const twr_empty_floor_t *protocol_floor;
1407 const twr_empty_floor_t *floor4;
1408 const struct connection_ops *protseq_ops = NULL;
1412 if (tower_size < sizeof(*protocol_floor))
1413 return EPT_S_NOT_REGISTERED;
1415 protocol_floor = (const twr_empty_floor_t *)tower_data;
1416 tower_data += sizeof(*protocol_floor);
1417 tower_size -= sizeof(*protocol_floor);
1418 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1419 (protocol_floor->count_rhs > tower_size))
1420 return EPT_S_NOT_REGISTERED;
1421 tower_data += protocol_floor->count_rhs;
1422 tower_size -= protocol_floor->count_rhs;
1424 floor4 = (const twr_empty_floor_t *)tower_data;
1425 if ((tower_size < sizeof(*floor4)) ||
1426 (floor4->count_lhs != sizeof(floor4->protid)))
1427 return EPT_S_NOT_REGISTERED;
1429 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1430 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1431 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1433 protseq_ops = &conn_protseq_list[i];
1438 return EPT_S_NOT_REGISTERED;
1440 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1442 if ((status == RPC_S_OK) && protseq)
1444 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1445 strcpy(*protseq, protseq_ops->name);
1451 /***********************************************************************
1452 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1454 * Checks if the given protocol sequence is known by the RPC system.
1455 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1458 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1462 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1463 ps, sizeof ps, NULL, NULL);
1464 if (rpcrt4_get_conn_protseq_ops(ps))
1467 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1469 return RPC_S_INVALID_RPC_PROTSEQ;
1472 /***********************************************************************
1473 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1475 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1477 UNICODE_STRING protseqW;
1479 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1481 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1482 RtlFreeUnicodeString(&protseqW);
1485 return RPC_S_OUT_OF_MEMORY;