winmm: Prevent NULL dereference in MCI_Close and add testcase for it.
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blob4249d2a072f68cb4ca9fa91ec384826fab845a28
1 /*
2 * RPC transport layer
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
7 * Copyright 2006 Mike McCormack
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <errno.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45 #ifdef HAVE_ARPA_INET_H
46 # include <arpa/inet.h>
47 #endif
48 #ifdef HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winnls.h"
55 #include "winerror.h"
56 #include "winreg.h"
57 #include "winternl.h"
58 #include "wine/unicode.h"
60 #include "rpc.h"
61 #include "rpcndr.h"
63 #include "wine/debug.h"
65 #include "rpc_binding.h"
66 #include "rpc_message.h"
67 #include "epm_towers.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
71 static CRITICAL_SECTION connection_pool_cs;
72 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
74 0, 0, &connection_pool_cs,
75 { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
76 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
78 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
80 static struct list connection_pool = LIST_INIT(connection_pool);
82 /**** ncacn_np support ****/
84 typedef struct _RpcConnection_np
86 RpcConnection common;
87 HANDLE pipe, thread;
88 OVERLAPPED ovl;
89 } RpcConnection_np;
91 static RpcConnection *rpcrt4_conn_np_alloc(void)
93 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
96 static RPC_STATUS rpcrt4_connect_pipe(RpcConnection *Connection, LPCSTR pname)
98 RpcConnection_np *npc = (RpcConnection_np *) Connection;
99 TRACE("listening on %s\n", pname);
101 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
102 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
103 PIPE_UNLIMITED_INSTANCES,
104 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
105 if (npc->pipe == INVALID_HANDLE_VALUE) {
106 WARN("CreateNamedPipe failed with error %ld\n", GetLastError());
107 return RPC_S_SERVER_UNAVAILABLE;
110 memset(&npc->ovl, 0, sizeof(npc->ovl));
111 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
112 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
113 return RPC_S_OK;
115 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
116 if (GetLastError() == ERROR_PIPE_CONNECTED) {
117 SetEvent(npc->ovl.hEvent);
118 return RPC_S_OK;
120 if (GetLastError() == ERROR_IO_PENDING) {
121 /* FIXME: looks like we need to GetOverlappedResult here? */
122 return RPC_S_OK;
124 return RPC_S_SERVER_UNAVAILABLE;
127 static RPC_STATUS rpcrt4_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
129 RpcConnection_np *npc = (RpcConnection_np *) Connection;
130 HANDLE pipe;
131 DWORD err, dwMode;
133 TRACE("connecting to %s\n", pname);
135 while (TRUE) {
136 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
137 OPEN_EXISTING, 0, 0);
138 if (pipe != INVALID_HANDLE_VALUE) break;
139 err = GetLastError();
140 if (err == ERROR_PIPE_BUSY) {
141 TRACE("connection failed, error=%lx\n", err);
142 return RPC_S_SERVER_TOO_BUSY;
144 if (!wait)
145 return RPC_S_SERVER_UNAVAILABLE;
146 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
147 err = GetLastError();
148 WARN("connection failed, error=%lx\n", err);
149 return RPC_S_SERVER_UNAVAILABLE;
153 /* success */
154 memset(&npc->ovl, 0, sizeof(npc->ovl));
155 /* pipe is connected; change to message-read mode. */
156 dwMode = PIPE_READMODE_MESSAGE;
157 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
158 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
159 npc->pipe = pipe;
161 return RPC_S_OK;
164 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
166 RpcConnection_np *npc = (RpcConnection_np *) Connection;
167 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
168 RPC_STATUS r;
169 LPSTR pname;
171 /* already connected? */
172 if (npc->pipe)
173 return RPC_S_OK;
175 /* protseq=ncalrpc: supposed to use NT LPC ports,
176 * but we'll implement it with named pipes for now */
177 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
178 strcat(strcpy(pname, prefix), Connection->Endpoint);
180 if (Connection->server)
181 r = rpcrt4_connect_pipe(Connection, pname);
182 else
183 r = rpcrt4_open_pipe(Connection, pname, TRUE);
184 HeapFree(GetProcessHeap(), 0, pname);
186 return r;
189 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
191 RpcConnection_np *npc = (RpcConnection_np *) Connection;
192 static LPCSTR prefix = "\\\\.";
193 RPC_STATUS r;
194 LPSTR pname;
196 /* already connected? */
197 if (npc->pipe)
198 return RPC_S_OK;
200 /* protseq=ncacn_np: named pipes */
201 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
202 strcat(strcpy(pname, prefix), Connection->Endpoint);
203 if (Connection->server)
204 r = rpcrt4_connect_pipe(Connection, pname);
205 else
206 r = rpcrt4_open_pipe(Connection, pname, FALSE);
207 HeapFree(GetProcessHeap(), 0, pname);
209 return r;
212 static HANDLE rpcrt4_conn_np_get_connect_event(RpcConnection *Connection)
214 RpcConnection_np *npc = (RpcConnection_np *) Connection;
215 return npc->ovl.hEvent;
218 static RPC_STATUS rpcrt4_conn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
220 RpcConnection_np *old_npc = (RpcConnection_np *) old_conn;
221 RpcConnection_np *new_npc = (RpcConnection_np *) new_conn;
222 /* because of the way named pipes work, we'll transfer the connected pipe
223 * to the child, then reopen the server binding to continue listening */
225 new_npc->pipe = old_npc->pipe;
226 new_npc->ovl = old_npc->ovl;
227 old_npc->pipe = 0;
228 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
229 return RPCRT4_OpenConnection(old_conn);
232 static int rpcrt4_conn_np_read(RpcConnection *Connection,
233 void *buffer, unsigned int count)
235 RpcConnection_np *npc = (RpcConnection_np *) Connection;
236 DWORD dwRead = 0;
237 if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
238 (GetLastError() != ERROR_MORE_DATA))
239 return -1;
240 return dwRead;
243 static int rpcrt4_conn_np_write(RpcConnection *Connection,
244 const void *buffer, unsigned int count)
246 RpcConnection_np *npc = (RpcConnection_np *) Connection;
247 DWORD dwWritten = 0;
248 if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
249 return -1;
250 return dwWritten;
253 static int rpcrt4_conn_np_close(RpcConnection *Connection)
255 RpcConnection_np *npc = (RpcConnection_np *) Connection;
256 if (npc->pipe) {
257 FlushFileBuffers(npc->pipe);
258 CloseHandle(npc->pipe);
259 npc->pipe = 0;
261 if (npc->ovl.hEvent) {
262 CloseHandle(npc->ovl.hEvent);
263 npc->ovl.hEvent = 0;
265 return 0;
268 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
269 const char *networkaddr,
270 const char *endpoint)
272 twr_empty_floor_t *smb_floor;
273 twr_empty_floor_t *nb_floor;
274 size_t size;
275 size_t networkaddr_size;
276 size_t endpoint_size;
278 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
280 networkaddr_size = strlen(networkaddr) + 1;
281 endpoint_size = strlen(endpoint) + 1;
282 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
284 if (!tower_data)
285 return size;
287 smb_floor = (twr_empty_floor_t *)tower_data;
289 tower_data += sizeof(*smb_floor);
291 smb_floor->count_lhs = sizeof(smb_floor->protid);
292 smb_floor->protid = EPM_PROTOCOL_SMB;
293 smb_floor->count_rhs = endpoint_size;
295 memcpy(tower_data, endpoint, endpoint_size);
296 tower_data += endpoint_size;
298 nb_floor = (twr_empty_floor_t *)tower_data;
300 tower_data += sizeof(*nb_floor);
302 nb_floor->count_lhs = sizeof(nb_floor->protid);
303 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
304 nb_floor->count_rhs = networkaddr_size;
306 memcpy(tower_data, networkaddr, networkaddr_size);
307 tower_data += networkaddr_size;
309 return size;
312 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
313 size_t tower_size,
314 char **networkaddr,
315 char **endpoint)
317 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
318 const twr_empty_floor_t *nb_floor;
320 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
322 if (tower_size < sizeof(*smb_floor))
323 return EPT_S_NOT_REGISTERED;
325 tower_data += sizeof(*smb_floor);
326 tower_size -= sizeof(*smb_floor);
328 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
329 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
330 (smb_floor->count_rhs > tower_size))
331 return EPT_S_NOT_REGISTERED;
333 if (endpoint)
335 *endpoint = HeapAlloc(GetProcessHeap(), 0, smb_floor->count_rhs);
336 if (!*endpoint)
337 return RPC_S_OUT_OF_RESOURCES;
338 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
340 tower_data += smb_floor->count_rhs;
341 tower_size -= smb_floor->count_rhs;
343 if (tower_size < sizeof(*nb_floor))
344 return EPT_S_NOT_REGISTERED;
346 nb_floor = (const twr_empty_floor_t *)tower_data;
348 tower_data += sizeof(*nb_floor);
349 tower_size -= sizeof(*nb_floor);
351 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
352 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
353 (nb_floor->count_rhs > tower_size))
354 return EPT_S_NOT_REGISTERED;
356 if (networkaddr)
358 *networkaddr = HeapAlloc(GetProcessHeap(), 0, nb_floor->count_rhs);
359 if (!*networkaddr)
361 if (endpoint)
363 HeapFree(GetProcessHeap(), 0, *endpoint);
364 *endpoint = NULL;
366 return RPC_S_OUT_OF_RESOURCES;
368 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
371 return RPC_S_OK;
374 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
375 const char *networkaddr,
376 const char *endpoint)
378 twr_empty_floor_t *pipe_floor;
379 size_t size;
380 size_t endpoint_size;
382 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
384 endpoint_size = strlen(networkaddr) + 1;
385 size = sizeof(*pipe_floor) + endpoint_size;
387 if (!tower_data)
388 return size;
390 pipe_floor = (twr_empty_floor_t *)tower_data;
392 tower_data += sizeof(*pipe_floor);
394 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
395 pipe_floor->protid = EPM_PROTOCOL_SMB;
396 pipe_floor->count_rhs = endpoint_size;
398 memcpy(tower_data, endpoint, endpoint_size);
399 tower_data += endpoint_size;
401 return size;
404 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
405 size_t tower_size,
406 char **networkaddr,
407 char **endpoint)
409 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
411 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
413 *networkaddr = NULL;
414 *endpoint = NULL;
416 if (tower_size < sizeof(*pipe_floor))
417 return EPT_S_NOT_REGISTERED;
419 tower_data += sizeof(*pipe_floor);
420 tower_size -= sizeof(*pipe_floor);
422 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
423 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
424 (pipe_floor->count_rhs > tower_size))
425 return EPT_S_NOT_REGISTERED;
427 if (endpoint)
429 *endpoint = HeapAlloc(GetProcessHeap(), 0, pipe_floor->count_rhs);
430 if (!*endpoint)
431 return RPC_S_OUT_OF_RESOURCES;
432 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
435 return RPC_S_OK;
438 /**** ncacn_ip_tcp support ****/
440 typedef struct _RpcConnection_tcp
442 RpcConnection common;
443 int sock;
444 } RpcConnection_tcp;
446 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
448 RpcConnection_tcp *tcpc;
449 tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
450 tcpc->sock = -1;
451 return &tcpc->common;
454 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
456 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
457 int sock;
458 int ret;
459 struct addrinfo *ai;
460 struct addrinfo *ai_cur;
461 struct addrinfo hints;
463 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
465 if (Connection->server)
467 ERR("ncacn_ip_tcp servers not supported yet\n");
468 return RPC_S_SERVER_UNAVAILABLE;
471 if (tcpc->sock != -1)
472 return RPC_S_OK;
474 hints.ai_flags = 0;
475 hints.ai_family = PF_UNSPEC;
476 hints.ai_socktype = SOCK_STREAM;
477 hints.ai_protocol = IPPROTO_TCP;
478 hints.ai_addrlen = 0;
479 hints.ai_addr = NULL;
480 hints.ai_canonname = NULL;
481 hints.ai_next = NULL;
483 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
484 if (ret)
486 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
487 return RPC_S_SERVER_UNAVAILABLE;
490 for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
492 if (TRACE_ON(rpc))
494 char host[256];
495 char service[256];
496 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
497 host, sizeof(host), service, sizeof(service),
498 NI_NUMERICHOST | NI_NUMERICSERV);
499 TRACE("trying %s:%s\n", host, service);
502 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
503 if (sock < 0)
505 WARN("socket() failed\n");
506 continue;
509 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
511 WARN("connect() failed\n");
512 close(sock);
513 continue;
516 tcpc->sock = sock;
518 freeaddrinfo(ai);
519 TRACE("connected\n");
520 return RPC_S_OK;
523 freeaddrinfo(ai);
524 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
525 return RPC_S_SERVER_UNAVAILABLE;
528 static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
530 assert(0);
531 return 0;
534 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
536 assert(0);
537 return RPC_S_SERVER_UNAVAILABLE;
540 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
541 void *buffer, unsigned int count)
543 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
544 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
545 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
546 return r;
549 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
550 const void *buffer, unsigned int count)
552 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
553 int r = write(tcpc->sock, buffer, count);
554 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
555 return r;
558 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
560 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
562 TRACE("%d\n", tcpc->sock);
563 if (tcpc->sock != -1)
564 close(tcpc->sock);
565 tcpc->sock = -1;
566 return 0;
569 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
570 const char *networkaddr,
571 const char *endpoint)
573 twr_tcp_floor_t *tcp_floor;
574 twr_ipv4_floor_t *ipv4_floor;
575 struct addrinfo *ai;
576 struct addrinfo hints;
577 int ret;
578 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
580 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
582 if (!tower_data)
583 return size;
585 tcp_floor = (twr_tcp_floor_t *)tower_data;
586 tower_data += sizeof(*tcp_floor);
588 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
590 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
591 tcp_floor->protid = EPM_PROTOCOL_TCP;
592 tcp_floor->count_rhs = sizeof(tcp_floor->port);
594 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
595 ipv4_floor->protid = EPM_PROTOCOL_IP;
596 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
598 hints.ai_flags = AI_NUMERICHOST;
599 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
600 hints.ai_family = PF_INET;
601 hints.ai_socktype = SOCK_STREAM;
602 hints.ai_protocol = IPPROTO_TCP;
603 hints.ai_addrlen = 0;
604 hints.ai_addr = NULL;
605 hints.ai_canonname = NULL;
606 hints.ai_next = NULL;
608 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
609 if (ret)
611 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
612 if (ret)
614 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
615 return 0;
619 if (ai->ai_family == PF_INET)
621 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
622 tcp_floor->port = sin->sin_port;
623 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
625 else
627 ERR("unexpected protocol family %d\n", ai->ai_family);
628 return 0;
631 freeaddrinfo(ai);
633 return size;
636 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
637 size_t tower_size,
638 char **networkaddr,
639 char **endpoint)
641 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
642 const twr_ipv4_floor_t *ipv4_floor;
643 struct in_addr in_addr;
645 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
647 if (tower_size < sizeof(*tcp_floor))
648 return EPT_S_NOT_REGISTERED;
650 tower_data += sizeof(*tcp_floor);
651 tower_size -= sizeof(*tcp_floor);
653 if (tower_size < sizeof(*ipv4_floor))
654 return EPT_S_NOT_REGISTERED;
656 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
658 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
659 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
660 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
661 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
662 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
663 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
664 return EPT_S_NOT_REGISTERED;
666 if (endpoint)
668 *endpoint = HeapAlloc(GetProcessHeap(), 0, 6);
669 if (!*endpoint)
670 return RPC_S_OUT_OF_RESOURCES;
671 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
674 if (networkaddr)
676 *networkaddr = HeapAlloc(GetProcessHeap(), 0, INET_ADDRSTRLEN);
677 if (!*networkaddr)
679 if (endpoint)
681 HeapFree(GetProcessHeap(), 0, *endpoint);
682 *endpoint = NULL;
684 return RPC_S_OUT_OF_RESOURCES;
686 in_addr.s_addr = ipv4_floor->ipv4addr;
687 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
689 ERR("inet_ntop: %s\n", strerror(errno));
690 HeapFree(GetProcessHeap(), 0, *networkaddr);
691 *networkaddr = NULL;
692 if (endpoint)
694 HeapFree(GetProcessHeap(), 0, *endpoint);
695 *endpoint = NULL;
697 return EPT_S_NOT_REGISTERED;
701 return RPC_S_OK;
704 static const struct protseq_ops protseq_list[] = {
705 { "ncacn_np",
706 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
707 rpcrt4_conn_np_alloc,
708 rpcrt4_ncacn_np_open,
709 rpcrt4_conn_np_get_connect_event,
710 rpcrt4_conn_np_handoff,
711 rpcrt4_conn_np_read,
712 rpcrt4_conn_np_write,
713 rpcrt4_conn_np_close,
714 rpcrt4_ncacn_np_get_top_of_tower,
715 rpcrt4_ncacn_np_parse_top_of_tower,
717 { "ncalrpc",
718 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
719 rpcrt4_conn_np_alloc,
720 rpcrt4_ncalrpc_open,
721 rpcrt4_conn_np_get_connect_event,
722 rpcrt4_conn_np_handoff,
723 rpcrt4_conn_np_read,
724 rpcrt4_conn_np_write,
725 rpcrt4_conn_np_close,
726 rpcrt4_ncalrpc_get_top_of_tower,
727 rpcrt4_ncalrpc_parse_top_of_tower,
729 { "ncacn_ip_tcp",
730 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
731 rpcrt4_conn_tcp_alloc,
732 rpcrt4_ncacn_ip_tcp_open,
733 rpcrt4_conn_tcp_get_wait_handle,
734 rpcrt4_conn_tcp_handoff,
735 rpcrt4_conn_tcp_read,
736 rpcrt4_conn_tcp_write,
737 rpcrt4_conn_tcp_close,
738 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
739 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
743 #define MAX_PROTSEQ (sizeof protseq_list / sizeof protseq_list[0])
745 static const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
747 int i;
748 for(i=0; i<MAX_PROTSEQ; i++)
749 if (!strcmp(protseq_list[i].name, protseq))
750 return &protseq_list[i];
751 return NULL;
754 /**** interface to rest of code ****/
756 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
758 TRACE("(Connection == ^%p)\n", Connection);
760 return Connection->ops->open_connection(Connection);
763 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
765 TRACE("(Connection == ^%p)\n", Connection);
766 rpcrt4_conn_close(Connection);
767 return RPC_S_OK;
770 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
771 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
772 LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
774 const struct protseq_ops *ops;
775 RpcConnection* NewConnection;
777 ops = rpcrt4_get_protseq_ops(Protseq);
778 if (!ops)
779 return RPC_S_PROTSEQ_NOT_SUPPORTED;
781 NewConnection = ops->alloc();
782 NewConnection->server = server;
783 NewConnection->ops = ops;
784 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
785 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
786 NewConnection->Used = Binding;
787 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
788 NewConnection->NextCallId = 1;
789 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
790 NewConnection->AuthInfo = AuthInfo;
791 list_init(&NewConnection->conn_pool_entry);
793 TRACE("connection: %p\n", NewConnection);
794 *Connection = NewConnection;
796 return RPC_S_OK;
799 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
800 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
801 LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
803 RpcConnection *Connection;
804 /* try to find a compatible connection from the connection pool */
805 EnterCriticalSection(&connection_pool_cs);
806 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
807 if ((Connection->AuthInfo == AuthInfo) &&
808 !memcmp(&Connection->ActiveInterface, InterfaceId,
809 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
810 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
811 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
812 !strcmp(Connection->Endpoint, Endpoint))
814 list_remove(&Connection->conn_pool_entry);
815 LeaveCriticalSection(&connection_pool_cs);
816 TRACE("got connection from pool %p\n", Connection);
817 return Connection;
820 LeaveCriticalSection(&connection_pool_cs);
821 return NULL;
824 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
826 assert(!Connection->server);
827 EnterCriticalSection(&connection_pool_cs);
828 list_add_head(&connection_pool, &Connection->conn_pool_entry);
829 LeaveCriticalSection(&connection_pool_cs);
833 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
835 RPC_STATUS err;
837 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
838 rpcrt4_conn_get_name(OldConnection),
839 OldConnection->NetworkAddr,
840 OldConnection->Endpoint, NULL,
841 OldConnection->AuthInfo, NULL);
842 if (err == RPC_S_OK)
843 rpcrt4_conn_handoff(OldConnection, *Connection);
844 return err;
847 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
849 TRACE("connection: %p\n", Connection);
851 RPCRT4_CloseConnection(Connection);
852 RPCRT4_strfree(Connection->Endpoint);
853 RPCRT4_strfree(Connection->NetworkAddr);
854 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
855 HeapFree(GetProcessHeap(), 0, Connection);
856 return RPC_S_OK;
859 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
860 size_t *tower_size,
861 const char *protseq,
862 const char *networkaddr,
863 const char *endpoint)
865 twr_empty_floor_t *protocol_floor;
866 const struct protseq_ops *protseq_ops = rpcrt4_get_protseq_ops(protseq);
868 *tower_size = 0;
870 if (!protseq_ops)
871 return RPC_S_INVALID_RPC_PROTSEQ;
873 if (!tower_data)
875 *tower_size = sizeof(*protocol_floor);
876 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
877 return RPC_S_OK;
880 protocol_floor = (twr_empty_floor_t *)tower_data;
881 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
882 protocol_floor->protid = protseq_ops->epm_protocols[0];
883 protocol_floor->count_rhs = 0;
885 tower_data += sizeof(*protocol_floor);
887 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
888 if (!*tower_size)
889 return EPT_S_NOT_REGISTERED;
891 *tower_size += sizeof(*protocol_floor);
893 return RPC_S_OK;
896 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
897 size_t tower_size,
898 char **protseq,
899 char **networkaddr,
900 char **endpoint)
902 twr_empty_floor_t *protocol_floor;
903 twr_empty_floor_t *floor4;
904 const struct protseq_ops *protseq_ops = NULL;
905 RPC_STATUS status;
906 int i;
908 if (tower_size < sizeof(*protocol_floor))
909 return EPT_S_NOT_REGISTERED;
911 protocol_floor = (twr_empty_floor_t *)tower_data;
912 tower_data += sizeof(*protocol_floor);
913 tower_size -= sizeof(*protocol_floor);
914 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
915 (protocol_floor->count_rhs > tower_size))
916 return EPT_S_NOT_REGISTERED;
917 tower_data += protocol_floor->count_rhs;
918 tower_size -= protocol_floor->count_rhs;
920 floor4 = (twr_empty_floor_t *)tower_data;
921 if ((tower_size < sizeof(*floor4)) ||
922 (floor4->count_lhs != sizeof(floor4->protid)))
923 return EPT_S_NOT_REGISTERED;
925 for(i = 0; i < MAX_PROTSEQ; i++)
926 if ((protocol_floor->protid == protseq_list[i].epm_protocols[0]) &&
927 (floor4->protid == protseq_list[i].epm_protocols[1]))
929 protseq_ops = &protseq_list[i];
930 break;
933 if (!protseq_ops)
934 return EPT_S_NOT_REGISTERED;
936 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
938 if ((status == RPC_S_OK) && protseq)
940 *protseq = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_ops->name) + 1);
941 strcpy(*protseq, protseq_ops->name);
944 return status;
947 /***********************************************************************
948 * RpcNetworkIsProtseqValidW (RPCRT4.@)
950 * Checks if the given protocol sequence is known by the RPC system.
951 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
954 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq)
956 char ps[0x10];
958 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
959 ps, sizeof ps, NULL, NULL);
960 if (rpcrt4_get_protseq_ops(ps))
961 return RPC_S_OK;
963 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
965 return RPC_S_INVALID_RPC_PROTSEQ;
968 /***********************************************************************
969 * RpcNetworkIsProtseqValidA (RPCRT4.@)
971 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq)
973 UNICODE_STRING protseqW;
975 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
977 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
978 RtlFreeUnicodeString(&protseqW);
979 return ret;
981 return RPC_S_OUT_OF_MEMORY;