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 RpcConnection_np
*npc
= HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np
));
98 memset(&npc
->ovl
, 0, sizeof(npc
->ovl
));
103 static RPC_STATUS
rpcrt4_connect_pipe(RpcConnection
*Connection
, LPCSTR pname
)
105 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
106 TRACE("listening on %s\n", pname
);
108 npc
->pipe
= CreateNamedPipeA(pname
, PIPE_ACCESS_DUPLEX
,
109 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
,
110 PIPE_UNLIMITED_INSTANCES
,
111 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
, 5000, NULL
);
112 if (npc
->pipe
== INVALID_HANDLE_VALUE
) {
113 WARN("CreateNamedPipe failed with error %ld\n", GetLastError());
114 return RPC_S_SERVER_UNAVAILABLE
;
117 memset(&npc
->ovl
, 0, sizeof(npc
->ovl
));
118 npc
->ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
119 if (ConnectNamedPipe(npc
->pipe
, &npc
->ovl
))
122 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
123 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
124 SetEvent(npc
->ovl
.hEvent
);
127 if (GetLastError() == ERROR_IO_PENDING
) {
128 /* FIXME: looks like we need to GetOverlappedResult here? */
131 return RPC_S_SERVER_UNAVAILABLE
;
134 static RPC_STATUS
rpcrt4_open_pipe(RpcConnection
*Connection
, LPCSTR pname
, BOOL wait
)
136 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
140 TRACE("connecting to %s\n", pname
);
143 pipe
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
144 OPEN_EXISTING
, 0, 0);
145 if (pipe
!= INVALID_HANDLE_VALUE
) break;
146 err
= GetLastError();
147 if (err
== ERROR_PIPE_BUSY
) {
148 TRACE("connection failed, error=%lx\n", err
);
149 return RPC_S_SERVER_TOO_BUSY
;
152 return RPC_S_SERVER_UNAVAILABLE
;
153 if (!WaitNamedPipeA(pname
, NMPWAIT_WAIT_FOREVER
)) {
154 err
= GetLastError();
155 WARN("connection failed, error=%lx\n", err
);
156 return RPC_S_SERVER_UNAVAILABLE
;
161 memset(&npc
->ovl
, 0, sizeof(npc
->ovl
));
162 /* pipe is connected; change to message-read mode. */
163 dwMode
= PIPE_READMODE_MESSAGE
;
164 SetNamedPipeHandleState(pipe
, &dwMode
, NULL
, NULL
);
165 npc
->ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
171 static RPC_STATUS
rpcrt4_ncalrpc_open(RpcConnection
* Connection
)
173 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
174 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
178 /* already connected? */
182 /* protseq=ncalrpc: supposed to use NT LPC ports,
183 * but we'll implement it with named pipes for now */
184 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
185 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
187 if (Connection
->server
)
188 r
= rpcrt4_connect_pipe(Connection
, pname
);
190 r
= rpcrt4_open_pipe(Connection
, pname
, TRUE
);
191 HeapFree(GetProcessHeap(), 0, pname
);
196 static RPC_STATUS
rpcrt4_ncacn_np_open(RpcConnection
* Connection
)
198 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
199 static LPCSTR prefix
= "\\\\.";
203 /* already connected? */
207 /* protseq=ncacn_np: named pipes */
208 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
209 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
210 if (Connection
->server
)
211 r
= rpcrt4_connect_pipe(Connection
, pname
);
213 r
= rpcrt4_open_pipe(Connection
, pname
, FALSE
);
214 HeapFree(GetProcessHeap(), 0, pname
);
219 static HANDLE
rpcrt4_conn_np_get_connect_event(RpcConnection
*Connection
)
221 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
222 return npc
->ovl
.hEvent
;
225 static RPC_STATUS
rpcrt4_conn_np_handoff(RpcConnection
*old_conn
, RpcConnection
*new_conn
)
227 RpcConnection_np
*old_npc
= (RpcConnection_np
*) old_conn
;
228 RpcConnection_np
*new_npc
= (RpcConnection_np
*) new_conn
;
229 /* because of the way named pipes work, we'll transfer the connected pipe
230 * to the child, then reopen the server binding to continue listening */
232 new_npc
->pipe
= old_npc
->pipe
;
233 new_npc
->ovl
= old_npc
->ovl
;
235 memset(&old_npc
->ovl
, 0, sizeof(old_npc
->ovl
));
236 return RPCRT4_OpenConnection(old_conn
);
239 static int rpcrt4_conn_np_read(RpcConnection
*Connection
,
240 void *buffer
, unsigned int count
)
242 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
244 if (!ReadFile(npc
->pipe
, buffer
, count
, &dwRead
, NULL
) &&
245 (GetLastError() != ERROR_MORE_DATA
))
250 static int rpcrt4_conn_np_write(RpcConnection
*Connection
,
251 const void *buffer
, unsigned int count
)
253 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
255 if (!WriteFile(npc
->pipe
, buffer
, count
, &dwWritten
, NULL
))
260 static int rpcrt4_conn_np_close(RpcConnection
*Connection
)
262 RpcConnection_np
*npc
= (RpcConnection_np
*) Connection
;
264 FlushFileBuffers(npc
->pipe
);
265 CloseHandle(npc
->pipe
);
268 if (npc
->ovl
.hEvent
) {
269 CloseHandle(npc
->ovl
.hEvent
);
275 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data
,
276 const char *networkaddr
,
277 const char *endpoint
)
279 twr_empty_floor_t
*smb_floor
;
280 twr_empty_floor_t
*nb_floor
;
282 size_t networkaddr_size
;
283 size_t endpoint_size
;
285 TRACE("(%p, %s, %s)\n", tower_data
, networkaddr
, endpoint
);
287 networkaddr_size
= strlen(networkaddr
) + 1;
288 endpoint_size
= strlen(endpoint
) + 1;
289 size
= sizeof(*smb_floor
) + endpoint_size
+ sizeof(*nb_floor
) + networkaddr_size
;
294 smb_floor
= (twr_empty_floor_t
*)tower_data
;
296 tower_data
+= sizeof(*smb_floor
);
298 smb_floor
->count_lhs
= sizeof(smb_floor
->protid
);
299 smb_floor
->protid
= EPM_PROTOCOL_SMB
;
300 smb_floor
->count_rhs
= endpoint_size
;
302 memcpy(tower_data
, endpoint
, endpoint_size
);
303 tower_data
+= endpoint_size
;
305 nb_floor
= (twr_empty_floor_t
*)tower_data
;
307 tower_data
+= sizeof(*nb_floor
);
309 nb_floor
->count_lhs
= sizeof(nb_floor
->protid
);
310 nb_floor
->protid
= EPM_PROTOCOL_NETBIOS
;
311 nb_floor
->count_rhs
= networkaddr_size
;
313 memcpy(tower_data
, networkaddr
, networkaddr_size
);
314 tower_data
+= networkaddr_size
;
319 static RPC_STATUS
rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data
,
324 const twr_empty_floor_t
*smb_floor
= (const twr_empty_floor_t
*)tower_data
;
325 const twr_empty_floor_t
*nb_floor
;
327 TRACE("(%p, %d, %p, %p)\n", tower_data
, (int)tower_size
, networkaddr
, endpoint
);
329 if (tower_size
< sizeof(*smb_floor
))
330 return EPT_S_NOT_REGISTERED
;
332 tower_data
+= sizeof(*smb_floor
);
333 tower_size
-= sizeof(*smb_floor
);
335 if ((smb_floor
->count_lhs
!= sizeof(smb_floor
->protid
)) ||
336 (smb_floor
->protid
!= EPM_PROTOCOL_SMB
) ||
337 (smb_floor
->count_rhs
> tower_size
))
338 return EPT_S_NOT_REGISTERED
;
342 *endpoint
= HeapAlloc(GetProcessHeap(), 0, smb_floor
->count_rhs
);
344 return RPC_S_OUT_OF_RESOURCES
;
345 memcpy(*endpoint
, tower_data
, smb_floor
->count_rhs
);
347 tower_data
+= smb_floor
->count_rhs
;
348 tower_size
-= smb_floor
->count_rhs
;
350 if (tower_size
< sizeof(*nb_floor
))
351 return EPT_S_NOT_REGISTERED
;
353 nb_floor
= (const twr_empty_floor_t
*)tower_data
;
355 tower_data
+= sizeof(*nb_floor
);
356 tower_size
-= sizeof(*nb_floor
);
358 if ((nb_floor
->count_lhs
!= sizeof(nb_floor
->protid
)) ||
359 (nb_floor
->protid
!= EPM_PROTOCOL_NETBIOS
) ||
360 (nb_floor
->count_rhs
> tower_size
))
361 return EPT_S_NOT_REGISTERED
;
365 *networkaddr
= HeapAlloc(GetProcessHeap(), 0, nb_floor
->count_rhs
);
370 HeapFree(GetProcessHeap(), 0, *endpoint
);
373 return RPC_S_OUT_OF_RESOURCES
;
375 memcpy(*networkaddr
, tower_data
, nb_floor
->count_rhs
);
381 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data
,
382 const char *networkaddr
,
383 const char *endpoint
)
385 twr_empty_floor_t
*pipe_floor
;
387 size_t endpoint_size
;
389 TRACE("(%p, %s, %s)\n", tower_data
, networkaddr
, endpoint
);
391 endpoint_size
= strlen(networkaddr
) + 1;
392 size
= sizeof(*pipe_floor
) + endpoint_size
;
397 pipe_floor
= (twr_empty_floor_t
*)tower_data
;
399 tower_data
+= sizeof(*pipe_floor
);
401 pipe_floor
->count_lhs
= sizeof(pipe_floor
->protid
);
402 pipe_floor
->protid
= EPM_PROTOCOL_SMB
;
403 pipe_floor
->count_rhs
= endpoint_size
;
405 memcpy(tower_data
, endpoint
, endpoint_size
);
406 tower_data
+= endpoint_size
;
411 static RPC_STATUS
rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data
,
416 const twr_empty_floor_t
*pipe_floor
= (const twr_empty_floor_t
*)tower_data
;
418 TRACE("(%p, %d, %p, %p)\n", tower_data
, (int)tower_size
, networkaddr
, endpoint
);
423 if (tower_size
< sizeof(*pipe_floor
))
424 return EPT_S_NOT_REGISTERED
;
426 tower_data
+= sizeof(*pipe_floor
);
427 tower_size
-= sizeof(*pipe_floor
);
429 if ((pipe_floor
->count_lhs
!= sizeof(pipe_floor
->protid
)) ||
430 (pipe_floor
->protid
!= EPM_PROTOCOL_SMB
) ||
431 (pipe_floor
->count_rhs
> tower_size
))
432 return EPT_S_NOT_REGISTERED
;
436 *endpoint
= HeapAlloc(GetProcessHeap(), 0, pipe_floor
->count_rhs
);
438 return RPC_S_OUT_OF_RESOURCES
;
439 memcpy(*endpoint
, tower_data
, pipe_floor
->count_rhs
);
445 /**** ncacn_ip_tcp support ****/
447 typedef struct _RpcConnection_tcp
449 RpcConnection common
;
453 static RpcConnection
*rpcrt4_conn_tcp_alloc(void)
455 RpcConnection_tcp
*tcpc
;
456 tcpc
= HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp
));
459 return &tcpc
->common
;
462 static RPC_STATUS
rpcrt4_ncacn_ip_tcp_open(RpcConnection
* Connection
)
464 RpcConnection_tcp
*tcpc
= (RpcConnection_tcp
*) Connection
;
468 struct addrinfo
*ai_cur
;
469 struct addrinfo hints
;
471 TRACE("(%s, %s)\n", Connection
->NetworkAddr
, Connection
->Endpoint
);
473 if (Connection
->server
)
475 ERR("ncacn_ip_tcp servers not supported yet\n");
476 return RPC_S_SERVER_UNAVAILABLE
;
479 if (tcpc
->sock
!= -1)
483 hints
.ai_family
= PF_UNSPEC
;
484 hints
.ai_socktype
= SOCK_STREAM
;
485 hints
.ai_protocol
= IPPROTO_TCP
;
486 hints
.ai_addrlen
= 0;
487 hints
.ai_addr
= NULL
;
488 hints
.ai_canonname
= NULL
;
489 hints
.ai_next
= NULL
;
491 ret
= getaddrinfo(Connection
->NetworkAddr
, Connection
->Endpoint
, &hints
, &ai
);
494 ERR("getaddrinfo failed: %s\n", gai_strerror(ret
));
495 return RPC_S_SERVER_UNAVAILABLE
;
498 for (ai_cur
= ai
; ai_cur
; ai_cur
= ai
->ai_next
)
504 getnameinfo(ai_cur
->ai_addr
, ai_cur
->ai_addrlen
,
505 host
, sizeof(host
), service
, sizeof(service
),
506 NI_NUMERICHOST
| NI_NUMERICSERV
);
507 TRACE("trying %s:%s\n", host
, service
);
510 sock
= socket(ai_cur
->ai_family
, ai_cur
->ai_socktype
, ai_cur
->ai_protocol
);
513 WARN("socket() failed\n");
517 if (0>connect(sock
, ai_cur
->ai_addr
, ai_cur
->ai_addrlen
))
519 WARN("connect() failed\n");
527 TRACE("connected\n");
532 ERR("couldn't connect to %s:%s\n", Connection
->NetworkAddr
, Connection
->Endpoint
);
533 return RPC_S_SERVER_UNAVAILABLE
;
536 static HANDLE
rpcrt4_conn_tcp_get_wait_handle(RpcConnection
*Connection
)
542 static RPC_STATUS
rpcrt4_conn_tcp_handoff(RpcConnection
*old_conn
, RpcConnection
*new_conn
)
545 return RPC_S_SERVER_UNAVAILABLE
;
548 static int rpcrt4_conn_tcp_read(RpcConnection
*Connection
,
549 void *buffer
, unsigned int count
)
551 RpcConnection_tcp
*tcpc
= (RpcConnection_tcp
*) Connection
;
552 int r
= recv(tcpc
->sock
, buffer
, count
, MSG_WAITALL
);
553 TRACE("%d %p %u -> %d\n", tcpc
->sock
, buffer
, count
, r
);
557 static int rpcrt4_conn_tcp_write(RpcConnection
*Connection
,
558 const void *buffer
, unsigned int count
)
560 RpcConnection_tcp
*tcpc
= (RpcConnection_tcp
*) Connection
;
561 int r
= write(tcpc
->sock
, buffer
, count
);
562 TRACE("%d %p %u -> %d\n", tcpc
->sock
, buffer
, count
, r
);
566 static int rpcrt4_conn_tcp_close(RpcConnection
*Connection
)
568 RpcConnection_tcp
*tcpc
= (RpcConnection_tcp
*) Connection
;
570 TRACE("%d\n", tcpc
->sock
);
571 if (tcpc
->sock
!= -1)
577 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data
,
578 const char *networkaddr
,
579 const char *endpoint
)
581 twr_tcp_floor_t
*tcp_floor
;
582 twr_ipv4_floor_t
*ipv4_floor
;
584 struct addrinfo hints
;
586 size_t size
= sizeof(*tcp_floor
) + sizeof(*ipv4_floor
);
588 TRACE("(%p, %s, %s)\n", tower_data
, networkaddr
, endpoint
);
593 tcp_floor
= (twr_tcp_floor_t
*)tower_data
;
594 tower_data
+= sizeof(*tcp_floor
);
596 ipv4_floor
= (twr_ipv4_floor_t
*)tower_data
;
598 tcp_floor
->count_lhs
= sizeof(tcp_floor
->protid
);
599 tcp_floor
->protid
= EPM_PROTOCOL_TCP
;
600 tcp_floor
->count_rhs
= sizeof(tcp_floor
->port
);
602 ipv4_floor
->count_lhs
= sizeof(ipv4_floor
->protid
);
603 ipv4_floor
->protid
= EPM_PROTOCOL_IP
;
604 ipv4_floor
->count_rhs
= sizeof(ipv4_floor
->ipv4addr
);
606 hints
.ai_flags
= AI_NUMERICHOST
;
607 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
608 hints
.ai_family
= PF_INET
;
609 hints
.ai_socktype
= SOCK_STREAM
;
610 hints
.ai_protocol
= IPPROTO_TCP
;
611 hints
.ai_addrlen
= 0;
612 hints
.ai_addr
= NULL
;
613 hints
.ai_canonname
= NULL
;
614 hints
.ai_next
= NULL
;
616 ret
= getaddrinfo(networkaddr
, endpoint
, &hints
, &ai
);
619 ret
= getaddrinfo("0.0.0.0", endpoint
, &hints
, &ai
);
622 ERR("getaddrinfo failed: %s\n", gai_strerror(ret
));
627 if (ai
->ai_family
== PF_INET
)
629 const struct sockaddr_in
*sin
= (const struct sockaddr_in
*)ai
->ai_addr
;
630 tcp_floor
->port
= sin
->sin_port
;
631 ipv4_floor
->ipv4addr
= sin
->sin_addr
.s_addr
;
635 ERR("unexpected protocol family %d\n", ai
->ai_family
);
644 static RPC_STATUS
rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data
,
649 const twr_tcp_floor_t
*tcp_floor
= (const twr_tcp_floor_t
*)tower_data
;
650 const twr_ipv4_floor_t
*ipv4_floor
;
651 struct in_addr in_addr
;
653 TRACE("(%p, %d, %p, %p)\n", tower_data
, (int)tower_size
, networkaddr
, endpoint
);
655 if (tower_size
< sizeof(*tcp_floor
))
656 return EPT_S_NOT_REGISTERED
;
658 tower_data
+= sizeof(*tcp_floor
);
659 tower_size
-= sizeof(*tcp_floor
);
661 if (tower_size
< sizeof(*ipv4_floor
))
662 return EPT_S_NOT_REGISTERED
;
664 ipv4_floor
= (const twr_ipv4_floor_t
*)tower_data
;
666 if ((tcp_floor
->count_lhs
!= sizeof(tcp_floor
->protid
)) ||
667 (tcp_floor
->protid
!= EPM_PROTOCOL_TCP
) ||
668 (tcp_floor
->count_rhs
!= sizeof(tcp_floor
->port
)) ||
669 (ipv4_floor
->count_lhs
!= sizeof(ipv4_floor
->protid
)) ||
670 (ipv4_floor
->protid
!= EPM_PROTOCOL_IP
) ||
671 (ipv4_floor
->count_rhs
!= sizeof(ipv4_floor
->ipv4addr
)))
672 return EPT_S_NOT_REGISTERED
;
676 *endpoint
= HeapAlloc(GetProcessHeap(), 0, 6);
678 return RPC_S_OUT_OF_RESOURCES
;
679 sprintf(*endpoint
, "%u", ntohs(tcp_floor
->port
));
684 *networkaddr
= HeapAlloc(GetProcessHeap(), 0, INET_ADDRSTRLEN
);
689 HeapFree(GetProcessHeap(), 0, *endpoint
);
692 return RPC_S_OUT_OF_RESOURCES
;
694 in_addr
.s_addr
= ipv4_floor
->ipv4addr
;
695 if (!inet_ntop(AF_INET
, &in_addr
, *networkaddr
, INET_ADDRSTRLEN
))
697 ERR("inet_ntop: %s\n", strerror(errno
));
698 HeapFree(GetProcessHeap(), 0, *networkaddr
);
702 HeapFree(GetProcessHeap(), 0, *endpoint
);
705 return EPT_S_NOT_REGISTERED
;
712 static const struct protseq_ops protseq_list
[] = {
714 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_SMB
},
715 rpcrt4_conn_np_alloc
,
716 rpcrt4_ncacn_np_open
,
717 rpcrt4_conn_np_get_connect_event
,
718 rpcrt4_conn_np_handoff
,
720 rpcrt4_conn_np_write
,
721 rpcrt4_conn_np_close
,
722 rpcrt4_ncacn_np_get_top_of_tower
,
723 rpcrt4_ncacn_np_parse_top_of_tower
,
726 { EPM_PROTOCOL_NCALRPC
, EPM_PROTOCOL_PIPE
},
727 rpcrt4_conn_np_alloc
,
729 rpcrt4_conn_np_get_connect_event
,
730 rpcrt4_conn_np_handoff
,
732 rpcrt4_conn_np_write
,
733 rpcrt4_conn_np_close
,
734 rpcrt4_ncalrpc_get_top_of_tower
,
735 rpcrt4_ncalrpc_parse_top_of_tower
,
738 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_TCP
},
739 rpcrt4_conn_tcp_alloc
,
740 rpcrt4_ncacn_ip_tcp_open
,
741 rpcrt4_conn_tcp_get_wait_handle
,
742 rpcrt4_conn_tcp_handoff
,
743 rpcrt4_conn_tcp_read
,
744 rpcrt4_conn_tcp_write
,
745 rpcrt4_conn_tcp_close
,
746 rpcrt4_ncacn_ip_tcp_get_top_of_tower
,
747 rpcrt4_ncacn_ip_tcp_parse_top_of_tower
,
751 #define MAX_PROTSEQ (sizeof protseq_list / sizeof protseq_list[0])
753 static const struct protseq_ops
*rpcrt4_get_protseq_ops(const char *protseq
)
756 for(i
=0; i
<MAX_PROTSEQ
; i
++)
757 if (!strcmp(protseq_list
[i
].name
, protseq
))
758 return &protseq_list
[i
];
762 /**** interface to rest of code ****/
764 RPC_STATUS
RPCRT4_OpenConnection(RpcConnection
* Connection
)
766 TRACE("(Connection == ^%p)\n", Connection
);
768 return Connection
->ops
->open_connection(Connection
);
771 RPC_STATUS
RPCRT4_CloseConnection(RpcConnection
* Connection
)
773 TRACE("(Connection == ^%p)\n", Connection
);
774 rpcrt4_conn_close(Connection
);
778 RPC_STATUS
RPCRT4_CreateConnection(RpcConnection
** Connection
, BOOL server
,
779 LPCSTR Protseq
, LPCSTR NetworkAddr
, LPCSTR Endpoint
,
780 LPCSTR NetworkOptions
, RpcAuthInfo
* AuthInfo
, RpcBinding
* Binding
)
782 const struct protseq_ops
*ops
;
783 RpcConnection
* NewConnection
;
785 ops
= rpcrt4_get_protseq_ops(Protseq
);
787 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
789 NewConnection
= ops
->alloc();
790 NewConnection
->Next
= NULL
;
791 NewConnection
->server
= server
;
792 NewConnection
->ops
= ops
;
793 NewConnection
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
794 NewConnection
->Endpoint
= RPCRT4_strdupA(Endpoint
);
795 NewConnection
->Used
= Binding
;
796 NewConnection
->MaxTransmissionSize
= RPC_MAX_PACKET_SIZE
;
797 memset(&NewConnection
->ActiveInterface
, 0, sizeof(NewConnection
->ActiveInterface
));
798 NewConnection
->NextCallId
= 1;
800 memset(&NewConnection
->ctx
, 0, sizeof(NewConnection
->ctx
));
801 if (AuthInfo
) RpcAuthInfo_AddRef(AuthInfo
);
802 NewConnection
->AuthInfo
= AuthInfo
;
803 list_init(&NewConnection
->conn_pool_entry
);
805 TRACE("connection: %p\n", NewConnection
);
806 *Connection
= NewConnection
;
811 RpcConnection
*RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER
*InterfaceId
,
812 const RPC_SYNTAX_IDENTIFIER
*TransferSyntax
, LPCSTR Protseq
, LPCSTR NetworkAddr
,
813 LPCSTR Endpoint
, RpcAuthInfo
* AuthInfo
)
815 RpcConnection
*Connection
;
816 /* try to find a compatible connection from the connection pool */
817 EnterCriticalSection(&connection_pool_cs
);
818 LIST_FOR_EACH_ENTRY(Connection
, &connection_pool
, RpcConnection
, conn_pool_entry
)
819 if ((Connection
->AuthInfo
== AuthInfo
) &&
820 !memcmp(&Connection
->ActiveInterface
, InterfaceId
,
821 sizeof(RPC_SYNTAX_IDENTIFIER
)) &&
822 !strcmp(rpcrt4_conn_get_name(Connection
), Protseq
) &&
823 !strcmp(Connection
->NetworkAddr
, NetworkAddr
) &&
824 !strcmp(Connection
->Endpoint
, Endpoint
))
826 list_remove(&Connection
->conn_pool_entry
);
827 LeaveCriticalSection(&connection_pool_cs
);
828 TRACE("got connection from pool %p\n", Connection
);
832 LeaveCriticalSection(&connection_pool_cs
);
836 void RPCRT4_ReleaseIdleConnection(RpcConnection
*Connection
)
838 assert(!Connection
->server
);
839 EnterCriticalSection(&connection_pool_cs
);
840 list_add_head(&connection_pool
, &Connection
->conn_pool_entry
);
841 LeaveCriticalSection(&connection_pool_cs
);
845 RPC_STATUS
RPCRT4_SpawnConnection(RpcConnection
** Connection
, RpcConnection
* OldConnection
)
849 err
= RPCRT4_CreateConnection(Connection
, OldConnection
->server
,
850 rpcrt4_conn_get_name(OldConnection
),
851 OldConnection
->NetworkAddr
,
852 OldConnection
->Endpoint
, NULL
,
853 OldConnection
->AuthInfo
, NULL
);
855 rpcrt4_conn_handoff(OldConnection
, *Connection
);
859 RPC_STATUS
RPCRT4_DestroyConnection(RpcConnection
* Connection
)
861 TRACE("connection: %p\n", Connection
);
863 RPCRT4_CloseConnection(Connection
);
864 RPCRT4_strfree(Connection
->Endpoint
);
865 RPCRT4_strfree(Connection
->NetworkAddr
);
866 if (Connection
->AuthInfo
) RpcAuthInfo_Release(Connection
->AuthInfo
);
867 HeapFree(GetProcessHeap(), 0, Connection
);
871 RPC_STATUS
RpcTransport_GetTopOfTower(unsigned char *tower_data
,
874 const char *networkaddr
,
875 const char *endpoint
)
877 twr_empty_floor_t
*protocol_floor
;
878 const struct protseq_ops
*protseq_ops
= rpcrt4_get_protseq_ops(protseq
);
883 return RPC_S_INVALID_RPC_PROTSEQ
;
887 *tower_size
= sizeof(*protocol_floor
);
888 *tower_size
+= protseq_ops
->get_top_of_tower(NULL
, networkaddr
, endpoint
);
892 protocol_floor
= (twr_empty_floor_t
*)tower_data
;
893 protocol_floor
->count_lhs
= sizeof(protocol_floor
->protid
);
894 protocol_floor
->protid
= protseq_ops
->epm_protocols
[0];
895 protocol_floor
->count_rhs
= 0;
897 tower_data
+= sizeof(*protocol_floor
);
899 *tower_size
= protseq_ops
->get_top_of_tower(tower_data
, networkaddr
, endpoint
);
901 return EPT_S_NOT_REGISTERED
;
903 *tower_size
+= sizeof(*protocol_floor
);
908 RPC_STATUS
RpcTransport_ParseTopOfTower(const unsigned char *tower_data
,
914 const twr_empty_floor_t
*protocol_floor
;
915 const twr_empty_floor_t
*floor4
;
916 const struct protseq_ops
*protseq_ops
= NULL
;
920 if (tower_size
< sizeof(*protocol_floor
))
921 return EPT_S_NOT_REGISTERED
;
923 protocol_floor
= (const twr_empty_floor_t
*)tower_data
;
924 tower_data
+= sizeof(*protocol_floor
);
925 tower_size
-= sizeof(*protocol_floor
);
926 if ((protocol_floor
->count_lhs
!= sizeof(protocol_floor
->protid
)) ||
927 (protocol_floor
->count_rhs
> tower_size
))
928 return EPT_S_NOT_REGISTERED
;
929 tower_data
+= protocol_floor
->count_rhs
;
930 tower_size
-= protocol_floor
->count_rhs
;
932 floor4
= (const twr_empty_floor_t
*)tower_data
;
933 if ((tower_size
< sizeof(*floor4
)) ||
934 (floor4
->count_lhs
!= sizeof(floor4
->protid
)))
935 return EPT_S_NOT_REGISTERED
;
937 for(i
= 0; i
< MAX_PROTSEQ
; i
++)
938 if ((protocol_floor
->protid
== protseq_list
[i
].epm_protocols
[0]) &&
939 (floor4
->protid
== protseq_list
[i
].epm_protocols
[1]))
941 protseq_ops
= &protseq_list
[i
];
946 return EPT_S_NOT_REGISTERED
;
948 status
= protseq_ops
->parse_top_of_tower(tower_data
, tower_size
, networkaddr
, endpoint
);
950 if ((status
== RPC_S_OK
) && protseq
)
952 *protseq
= HeapAlloc(GetProcessHeap(), 0, strlen(protseq_ops
->name
) + 1);
953 strcpy(*protseq
, protseq_ops
->name
);
959 /***********************************************************************
960 * RpcNetworkIsProtseqValidW (RPCRT4.@)
962 * Checks if the given protocol sequence is known by the RPC system.
963 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
966 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidW(LPWSTR protseq
)
970 WideCharToMultiByte(CP_ACP
, 0, protseq
, -1,
971 ps
, sizeof ps
, NULL
, NULL
);
972 if (rpcrt4_get_protseq_ops(ps
))
975 FIXME("Unknown protseq %s\n", debugstr_w(protseq
));
977 return RPC_S_INVALID_RPC_PROTSEQ
;
980 /***********************************************************************
981 * RpcNetworkIsProtseqValidA (RPCRT4.@)
983 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidA(unsigned char *protseq
)
985 UNICODE_STRING protseqW
;
987 if (RtlCreateUnicodeStringFromAsciiz(&protseqW
, (char*)protseq
))
989 RPC_STATUS ret
= RpcNetworkIsProtseqValidW(protseqW
.Buffer
);
990 RtlFreeUnicodeString(&protseqW
);
993 return RPC_S_OUT_OF_MEMORY
;