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
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
45 #ifdef HAVE_ARPA_INET_H
46 # include <arpa/inet.h>
58 #include "wine/unicode.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
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
))
115 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
116 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
117 SetEvent(npc
->ovl
.hEvent
);
120 if (GetLastError() == ERROR_IO_PENDING
) {
121 /* FIXME: looks like we need to GetOverlappedResult here? */
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
;
133 TRACE("connecting to %s\n", pname
);
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
;
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
;
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
);
164 static RPC_STATUS
rpcrt4_ncalrpc_open(RpcConnection
* Connection
)
166 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
167 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
171 /* already connected? */
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
);
183 r
= rpcrt4_open_pipe(Connection
, pname
, TRUE
);
184 HeapFree(GetProcessHeap(), 0, pname
);
189 static RPC_STATUS
rpcrt4_ncacn_np_open(RpcConnection
* Connection
)
191 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
192 static LPCSTR prefix
= "\\\\.";
196 /* already connected? */
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
);
206 r
= rpcrt4_open_pipe(Connection
, pname
, FALSE
);
207 HeapFree(GetProcessHeap(), 0, pname
);
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
;
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
;
237 if (!ReadFile(npc
->pipe
, buffer
, count
, &dwRead
, NULL
) &&
238 (GetLastError() != ERROR_MORE_DATA
))
243 static int rpcrt4_conn_np_write(RpcConnection
*Connection
,
244 const void *buffer
, unsigned int count
)
246 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
248 if (!WriteFile(npc
->pipe
, buffer
, count
, &dwWritten
, NULL
))
253 static int rpcrt4_conn_np_close(RpcConnection
*Connection
)
255 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
257 FlushFileBuffers(npc
->pipe
);
258 CloseHandle(npc
->pipe
);
261 if (npc
->ovl
.hEvent
) {
262 CloseHandle(npc
->ovl
.hEvent
);
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
;
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
;
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
;
312 static RPC_STATUS
rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data
,
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
;
335 *endpoint
= HeapAlloc(GetProcessHeap(), 0, smb_floor
->count_rhs
);
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
;
358 *networkaddr
= HeapAlloc(GetProcessHeap(), 0, nb_floor
->count_rhs
);
363 HeapFree(GetProcessHeap(), 0, *endpoint
);
366 return RPC_S_OUT_OF_RESOURCES
;
368 memcpy(*networkaddr
, tower_data
, nb_floor
->count_rhs
);
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
;
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
;
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
;
404 static RPC_STATUS
rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data
,
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
);
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
;
429 *endpoint
= HeapAlloc(GetProcessHeap(), 0, pipe_floor
->count_rhs
);
431 return RPC_S_OUT_OF_RESOURCES
;
432 memcpy(*endpoint
, tower_data
, pipe_floor
->count_rhs
);
438 /**** ncacn_ip_tcp support ****/
440 typedef struct _RpcConnection_tcp
442 RpcConnection common
;
446 static RpcConnection
*rpcrt4_conn_tcp_alloc(void)
448 RpcConnection_tcp
*tcpc
;
449 tcpc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcConnection_tcp
));
451 return &tcpc
->common
;
454 static RPC_STATUS
rpcrt4_ncacn_ip_tcp_open(RpcConnection
* Connection
)
456 RpcConnection_tcp
*tcpc
= (RpcConnection_tcp
*) Connection
;
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)
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
);
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
)
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
);
505 WARN("socket() failed\n");
509 if (0>connect(sock
, ai_cur
->ai_addr
, ai_cur
->ai_addrlen
))
511 WARN("connect() failed\n");
519 TRACE("connected\n");
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
)
534 static RPC_STATUS
rpcrt4_conn_tcp_handoff(RpcConnection
*old_conn
, RpcConnection
*new_conn
)
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
);
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
);
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)
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
;
576 struct addrinfo hints
;
578 size_t size
= sizeof(*tcp_floor
) + sizeof(*ipv4_floor
);
580 TRACE("(%p, %s, %s)\n", tower_data
, networkaddr
, endpoint
);
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
);
611 ret
= getaddrinfo("0.0.0.0", endpoint
, &hints
, &ai
);
614 ERR("getaddrinfo failed: %s\n", gai_strerror(ret
));
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
;
627 ERR("unexpected protocol family %d\n", ai
->ai_family
);
636 static RPC_STATUS
rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data
,
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
;
668 *endpoint
= HeapAlloc(GetProcessHeap(), 0, 6);
670 return RPC_S_OUT_OF_RESOURCES
;
671 sprintf(*endpoint
, "%u", ntohs(tcp_floor
->port
));
676 *networkaddr
= HeapAlloc(GetProcessHeap(), 0, INET_ADDRSTRLEN
);
681 HeapFree(GetProcessHeap(), 0, *endpoint
);
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
);
694 HeapFree(GetProcessHeap(), 0, *endpoint
);
697 return EPT_S_NOT_REGISTERED
;
704 static const struct protseq_ops protseq_list
[] = {
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
,
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
,
718 { EPM_PROTOCOL_NCALRPC
, EPM_PROTOCOL_PIPE
},
719 rpcrt4_conn_np_alloc
,
721 rpcrt4_conn_np_get_connect_event
,
722 rpcrt4_conn_np_handoff
,
724 rpcrt4_conn_np_write
,
725 rpcrt4_conn_np_close
,
726 rpcrt4_ncalrpc_get_top_of_tower
,
727 rpcrt4_ncalrpc_parse_top_of_tower
,
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
)
748 for(i
=0; i
<MAX_PROTSEQ
; i
++)
749 if (!strcmp(protseq_list
[i
].name
, protseq
))
750 return &protseq_list
[i
];
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
);
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
);
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
;
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
);
820 LeaveCriticalSection(&connection_pool_cs
);
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
)
837 err
= RPCRT4_CreateConnection(Connection
, OldConnection
->server
,
838 rpcrt4_conn_get_name(OldConnection
),
839 OldConnection
->NetworkAddr
,
840 OldConnection
->Endpoint
, NULL
,
841 OldConnection
->AuthInfo
, NULL
);
843 rpcrt4_conn_handoff(OldConnection
, *Connection
);
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
);
859 RPC_STATUS
RpcTransport_GetTopOfTower(unsigned char *tower_data
,
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
);
871 return RPC_S_INVALID_RPC_PROTSEQ
;
875 *tower_size
= sizeof(*protocol_floor
);
876 *tower_size
+= protseq_ops
->get_top_of_tower(NULL
, networkaddr
, endpoint
);
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
);
889 return EPT_S_NOT_REGISTERED
;
891 *tower_size
+= sizeof(*protocol_floor
);
896 RPC_STATUS
RpcTransport_ParseTopOfTower(const unsigned char *tower_data
,
902 twr_empty_floor_t
*protocol_floor
;
903 twr_empty_floor_t
*floor4
;
904 const struct protseq_ops
*protseq_ops
= NULL
;
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
];
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
);
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
)
958 WideCharToMultiByte(CP_ACP
, 0, protseq
, -1,
959 ps
, sizeof ps
, NULL
, NULL
);
960 if (rpcrt4_get_protseq_ops(ps
))
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
);
981 return RPC_S_OUT_OF_MEMORY
;