msvfw32: Replace const pointer parameter with correct pointer to const.
[wine/wine-kai.git] / dlls / rpcrt4 / rpc_transport.c
blob5f3966fc53650acb7b753fefb181d24f75744d81
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
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
26 #include "config.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_TCP_H
47 # include <netinet/tcp.h>
48 #endif
49 #ifdef HAVE_ARPA_INET_H
50 # include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NETDB_H
53 #include <netdb.h>
54 #endif
55 #ifdef HAVE_SYS_POLL_H
56 #include <sys/poll.h>
57 #endif
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winnls.h"
62 #include "winerror.h"
63 #include "winreg.h"
64 #include "winternl.h"
65 #include "wine/unicode.h"
67 #include "rpc.h"
68 #include "rpcndr.h"
70 #include "wine/debug.h"
72 #include "rpc_binding.h"
73 #include "rpc_message.h"
74 #include "rpc_server.h"
75 #include "epm_towers.h"
77 #ifndef SOL_TCP
78 # define SOL_TCP IPPROTO_TCP
79 #endif
81 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
83 static CRITICAL_SECTION connection_pool_cs;
84 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
86 0, 0, &connection_pool_cs,
87 { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
90 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
92 static struct list connection_pool = LIST_INIT(connection_pool);
94 /**** ncacn_np support ****/
96 typedef struct _RpcConnection_np
98 RpcConnection common;
99 HANDLE pipe;
100 OVERLAPPED ovl;
101 BOOL listening;
102 } RpcConnection_np;
104 static RpcConnection *rpcrt4_conn_np_alloc(void)
106 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
107 if (npc)
109 npc->pipe = NULL;
110 memset(&npc->ovl, 0, sizeof(npc->ovl));
111 npc->listening = FALSE;
113 return &npc->common;
116 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
118 if (npc->listening)
119 return RPC_S_OK;
121 npc->listening = TRUE;
122 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
123 return RPC_S_OK;
125 if (GetLastError() == ERROR_PIPE_CONNECTED) {
126 SetEvent(npc->ovl.hEvent);
127 return RPC_S_OK;
129 if (GetLastError() == ERROR_IO_PENDING) {
130 /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
131 return RPC_S_OK;
133 npc->listening = FALSE;
134 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
135 return RPC_S_OUT_OF_RESOURCES;
138 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
140 RpcConnection_np *npc = (RpcConnection_np *) Connection;
141 TRACE("listening on %s\n", pname);
143 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
144 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
145 PIPE_UNLIMITED_INSTANCES,
146 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
147 if (npc->pipe == INVALID_HANDLE_VALUE) {
148 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
149 if (GetLastError() == ERROR_FILE_EXISTS)
150 return RPC_S_DUPLICATE_ENDPOINT;
151 else
152 return RPC_S_CANT_CREATE_ENDPOINT;
155 memset(&npc->ovl, 0, sizeof(npc->ovl));
156 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
158 /* Note: we don't call ConnectNamedPipe here because it must be done in the
159 * server thread as the thread must be alertable */
160 return RPC_S_OK;
163 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
165 RpcConnection_np *npc = (RpcConnection_np *) Connection;
166 HANDLE pipe;
167 DWORD err, dwMode;
169 TRACE("connecting to %s\n", pname);
171 while (TRUE) {
172 DWORD dwFlags = 0;
173 if (Connection->QOS)
175 dwFlags = SECURITY_SQOS_PRESENT;
176 switch (Connection->QOS->qos->ImpersonationType)
178 case RPC_C_IMP_LEVEL_DEFAULT:
179 /* FIXME: what to do here? */
180 break;
181 case RPC_C_IMP_LEVEL_ANONYMOUS:
182 dwFlags |= SECURITY_ANONYMOUS;
183 break;
184 case RPC_C_IMP_LEVEL_IDENTIFY:
185 dwFlags |= SECURITY_IDENTIFICATION;
186 break;
187 case RPC_C_IMP_LEVEL_IMPERSONATE:
188 dwFlags |= SECURITY_IMPERSONATION;
189 break;
190 case RPC_C_IMP_LEVEL_DELEGATE:
191 dwFlags |= SECURITY_DELEGATION;
192 break;
194 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
195 dwFlags |= SECURITY_CONTEXT_TRACKING;
197 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
198 OPEN_EXISTING, dwFlags, 0);
199 if (pipe != INVALID_HANDLE_VALUE) break;
200 err = GetLastError();
201 if (err == ERROR_PIPE_BUSY) {
202 TRACE("connection failed, error=%x\n", err);
203 return RPC_S_SERVER_TOO_BUSY;
205 if (!wait)
206 return RPC_S_SERVER_UNAVAILABLE;
207 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
208 err = GetLastError();
209 WARN("connection failed, error=%x\n", err);
210 return RPC_S_SERVER_UNAVAILABLE;
214 /* success */
215 memset(&npc->ovl, 0, sizeof(npc->ovl));
216 /* pipe is connected; change to message-read mode. */
217 dwMode = PIPE_READMODE_MESSAGE;
218 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
219 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
220 npc->pipe = pipe;
222 return RPC_S_OK;
225 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
227 RpcConnection_np *npc = (RpcConnection_np *) Connection;
228 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
229 RPC_STATUS r;
230 LPSTR pname;
232 /* already connected? */
233 if (npc->pipe)
234 return RPC_S_OK;
236 /* protseq=ncalrpc: supposed to use NT LPC ports,
237 * but we'll implement it with named pipes for now */
238 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
239 strcat(strcpy(pname, prefix), Connection->Endpoint);
240 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
241 I_RpcFree(pname);
243 return r;
246 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
248 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
249 RPC_STATUS r;
250 LPSTR pname;
251 RpcConnection *Connection;
253 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
254 endpoint, NULL, NULL, NULL, NULL);
255 if (r != RPC_S_OK)
256 return r;
258 /* protseq=ncalrpc: supposed to use NT LPC ports,
259 * but we'll implement it with named pipes for now */
260 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
261 strcat(strcpy(pname, prefix), Connection->Endpoint);
262 r = rpcrt4_conn_create_pipe(Connection, pname);
263 I_RpcFree(pname);
265 EnterCriticalSection(&protseq->cs);
266 Connection->Next = protseq->conn;
267 protseq->conn = Connection;
268 LeaveCriticalSection(&protseq->cs);
270 return r;
273 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
275 RpcConnection_np *npc = (RpcConnection_np *) Connection;
276 static const char prefix[] = "\\\\.";
277 RPC_STATUS r;
278 LPSTR pname;
280 /* already connected? */
281 if (npc->pipe)
282 return RPC_S_OK;
284 /* protseq=ncacn_np: named pipes */
285 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
286 strcat(strcpy(pname, prefix), Connection->Endpoint);
287 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
288 I_RpcFree(pname);
290 return r;
293 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
295 static const char prefix[] = "\\\\.";
296 RPC_STATUS r;
297 LPSTR pname;
298 RpcConnection *Connection;
300 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
301 endpoint, NULL, NULL, NULL, NULL);
302 if (r != RPC_S_OK)
303 return r;
305 /* protseq=ncacn_np: named pipes */
306 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
307 strcat(strcpy(pname, prefix), Connection->Endpoint);
308 r = rpcrt4_conn_create_pipe(Connection, pname);
309 I_RpcFree(pname);
311 EnterCriticalSection(&protseq->cs);
312 Connection->Next = protseq->conn;
313 protseq->conn = Connection;
314 LeaveCriticalSection(&protseq->cs);
316 return r;
319 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
321 /* because of the way named pipes work, we'll transfer the connected pipe
322 * to the child, then reopen the server binding to continue listening */
324 new_npc->pipe = old_npc->pipe;
325 new_npc->ovl = old_npc->ovl;
326 old_npc->pipe = 0;
327 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
328 old_npc->listening = FALSE;
331 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
333 RPC_STATUS status;
334 LPSTR pname;
335 static const char prefix[] = "\\\\.";
337 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
339 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
340 strcat(strcpy(pname, prefix), old_conn->Endpoint);
341 status = rpcrt4_conn_create_pipe(old_conn, pname);
342 I_RpcFree(pname);
344 return status;
347 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
349 RPC_STATUS status;
350 LPSTR pname;
351 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
353 TRACE("%s\n", old_conn->Endpoint);
355 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
357 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
358 strcat(strcpy(pname, prefix), old_conn->Endpoint);
359 status = rpcrt4_conn_create_pipe(old_conn, pname);
360 I_RpcFree(pname);
362 return status;
365 static int rpcrt4_conn_np_read(RpcConnection *Connection,
366 void *buffer, unsigned int count)
368 RpcConnection_np *npc = (RpcConnection_np *) Connection;
369 char *buf = buffer;
370 BOOL ret = TRUE;
371 unsigned int bytes_left = count;
373 while (bytes_left)
375 DWORD bytes_read;
376 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
377 if (!ret || !bytes_read)
378 break;
379 bytes_left -= bytes_read;
380 buf += bytes_read;
382 return ret ? count : -1;
385 static int rpcrt4_conn_np_write(RpcConnection *Connection,
386 const void *buffer, unsigned int count)
388 RpcConnection_np *npc = (RpcConnection_np *) Connection;
389 const char *buf = buffer;
390 BOOL ret = TRUE;
391 unsigned int bytes_left = count;
393 while (bytes_left)
395 DWORD bytes_written;
396 ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
397 if (!ret || !bytes_written)
398 break;
399 bytes_left -= bytes_written;
400 buf += bytes_written;
402 return ret ? count : -1;
405 static int rpcrt4_conn_np_close(RpcConnection *Connection)
407 RpcConnection_np *npc = (RpcConnection_np *) Connection;
408 if (npc->pipe) {
409 FlushFileBuffers(npc->pipe);
410 CloseHandle(npc->pipe);
411 npc->pipe = 0;
413 if (npc->ovl.hEvent) {
414 CloseHandle(npc->ovl.hEvent);
415 npc->ovl.hEvent = 0;
417 return 0;
420 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
421 const char *networkaddr,
422 const char *endpoint)
424 twr_empty_floor_t *smb_floor;
425 twr_empty_floor_t *nb_floor;
426 size_t size;
427 size_t networkaddr_size;
428 size_t endpoint_size;
430 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
432 networkaddr_size = strlen(networkaddr) + 1;
433 endpoint_size = strlen(endpoint) + 1;
434 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
436 if (!tower_data)
437 return size;
439 smb_floor = (twr_empty_floor_t *)tower_data;
441 tower_data += sizeof(*smb_floor);
443 smb_floor->count_lhs = sizeof(smb_floor->protid);
444 smb_floor->protid = EPM_PROTOCOL_SMB;
445 smb_floor->count_rhs = endpoint_size;
447 memcpy(tower_data, endpoint, endpoint_size);
448 tower_data += endpoint_size;
450 nb_floor = (twr_empty_floor_t *)tower_data;
452 tower_data += sizeof(*nb_floor);
454 nb_floor->count_lhs = sizeof(nb_floor->protid);
455 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
456 nb_floor->count_rhs = networkaddr_size;
458 memcpy(tower_data, networkaddr, networkaddr_size);
459 tower_data += networkaddr_size;
461 return size;
464 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
465 size_t tower_size,
466 char **networkaddr,
467 char **endpoint)
469 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
470 const twr_empty_floor_t *nb_floor;
472 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
474 if (tower_size < sizeof(*smb_floor))
475 return EPT_S_NOT_REGISTERED;
477 tower_data += sizeof(*smb_floor);
478 tower_size -= sizeof(*smb_floor);
480 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
481 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
482 (smb_floor->count_rhs > tower_size))
483 return EPT_S_NOT_REGISTERED;
485 if (endpoint)
487 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
488 if (!*endpoint)
489 return RPC_S_OUT_OF_RESOURCES;
490 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
492 tower_data += smb_floor->count_rhs;
493 tower_size -= smb_floor->count_rhs;
495 if (tower_size < sizeof(*nb_floor))
496 return EPT_S_NOT_REGISTERED;
498 nb_floor = (const twr_empty_floor_t *)tower_data;
500 tower_data += sizeof(*nb_floor);
501 tower_size -= sizeof(*nb_floor);
503 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
504 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
505 (nb_floor->count_rhs > tower_size))
506 return EPT_S_NOT_REGISTERED;
508 if (networkaddr)
510 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
511 if (!*networkaddr)
513 if (endpoint)
515 I_RpcFree(*endpoint);
516 *endpoint = NULL;
518 return RPC_S_OUT_OF_RESOURCES;
520 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
523 return RPC_S_OK;
526 typedef struct _RpcServerProtseq_np
528 RpcServerProtseq common;
529 HANDLE mgr_event;
530 } RpcServerProtseq_np;
532 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
534 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
535 if (ps)
536 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
537 return &ps->common;
540 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
542 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
543 SetEvent(npps->mgr_event);
546 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
548 HANDLE *objs = prev_array;
549 RpcConnection_np *conn;
550 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
552 EnterCriticalSection(&protseq->cs);
554 /* open and count connections */
555 *count = 1;
556 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
557 while (conn) {
558 rpcrt4_conn_listen_pipe(conn);
559 if (conn->ovl.hEvent)
560 (*count)++;
561 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
564 /* make array of connections */
565 if (objs)
566 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
567 else
568 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
569 if (!objs)
571 ERR("couldn't allocate objs\n");
572 LeaveCriticalSection(&protseq->cs);
573 return NULL;
576 objs[0] = npps->mgr_event;
577 *count = 1;
578 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
579 while (conn) {
580 if ((objs[*count] = conn->ovl.hEvent))
581 (*count)++;
582 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
584 LeaveCriticalSection(&protseq->cs);
585 return objs;
588 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
590 HeapFree(GetProcessHeap(), 0, array);
593 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
595 HANDLE b_handle;
596 HANDLE *objs = wait_array;
597 DWORD res;
598 RpcConnection *cconn;
599 RpcConnection_np *conn;
601 if (!objs)
602 return -1;
604 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
605 if (res == WAIT_OBJECT_0)
606 return 0;
607 else if (res == WAIT_FAILED)
609 ERR("wait failed with error %d\n", GetLastError());
610 return -1;
612 else
614 b_handle = objs[res - WAIT_OBJECT_0];
615 /* find which connection got a RPC */
616 EnterCriticalSection(&protseq->cs);
617 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
618 while (conn) {
619 if (b_handle == conn->ovl.hEvent) break;
620 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
622 cconn = NULL;
623 if (conn)
624 RPCRT4_SpawnConnection(&cconn, &conn->common);
625 else
626 ERR("failed to locate connection for handle %p\n", b_handle);
627 LeaveCriticalSection(&protseq->cs);
628 if (cconn)
630 RPCRT4_new_client(cconn);
631 return 1;
633 else return -1;
637 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
638 const char *networkaddr,
639 const char *endpoint)
641 twr_empty_floor_t *pipe_floor;
642 size_t size;
643 size_t endpoint_size;
645 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
647 endpoint_size = strlen(networkaddr) + 1;
648 size = sizeof(*pipe_floor) + endpoint_size;
650 if (!tower_data)
651 return size;
653 pipe_floor = (twr_empty_floor_t *)tower_data;
655 tower_data += sizeof(*pipe_floor);
657 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
658 pipe_floor->protid = EPM_PROTOCOL_SMB;
659 pipe_floor->count_rhs = endpoint_size;
661 memcpy(tower_data, endpoint, endpoint_size);
662 tower_data += endpoint_size;
664 return size;
667 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
668 size_t tower_size,
669 char **networkaddr,
670 char **endpoint)
672 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
674 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
676 *networkaddr = NULL;
677 *endpoint = NULL;
679 if (tower_size < sizeof(*pipe_floor))
680 return EPT_S_NOT_REGISTERED;
682 tower_data += sizeof(*pipe_floor);
683 tower_size -= sizeof(*pipe_floor);
685 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
686 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
687 (pipe_floor->count_rhs > tower_size))
688 return EPT_S_NOT_REGISTERED;
690 if (endpoint)
692 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
693 if (!*endpoint)
694 return RPC_S_OUT_OF_RESOURCES;
695 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
698 return RPC_S_OK;
701 /**** ncacn_ip_tcp support ****/
703 typedef struct _RpcConnection_tcp
705 RpcConnection common;
706 int sock;
707 } RpcConnection_tcp;
709 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
711 RpcConnection_tcp *tcpc;
712 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
713 if (tcpc == NULL)
714 return NULL;
715 tcpc->sock = -1;
716 return &tcpc->common;
719 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
721 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
722 int sock;
723 int ret;
724 struct addrinfo *ai;
725 struct addrinfo *ai_cur;
726 struct addrinfo hints;
728 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
730 if (tcpc->sock != -1)
731 return RPC_S_OK;
733 hints.ai_flags = 0;
734 hints.ai_family = PF_UNSPEC;
735 hints.ai_socktype = SOCK_STREAM;
736 hints.ai_protocol = IPPROTO_TCP;
737 hints.ai_addrlen = 0;
738 hints.ai_addr = NULL;
739 hints.ai_canonname = NULL;
740 hints.ai_next = NULL;
742 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
743 if (ret)
745 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
746 Connection->Endpoint, gai_strerror(ret));
747 return RPC_S_SERVER_UNAVAILABLE;
750 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
752 int val;
754 if (TRACE_ON(rpc))
756 char host[256];
757 char service[256];
758 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
759 host, sizeof(host), service, sizeof(service),
760 NI_NUMERICHOST | NI_NUMERICSERV);
761 TRACE("trying %s:%s\n", host, service);
764 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
765 if (sock < 0)
767 WARN("socket() failed: %s\n", strerror(errno));
768 continue;
771 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
773 WARN("connect() failed: %s\n", strerror(errno));
774 close(sock);
775 continue;
778 /* RPC depends on having minimal latency so disable the Nagle algorithm */
779 val = 1;
780 setsockopt(sock, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
782 tcpc->sock = sock;
784 freeaddrinfo(ai);
785 TRACE("connected\n");
786 return RPC_S_OK;
789 freeaddrinfo(ai);
790 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
791 return RPC_S_SERVER_UNAVAILABLE;
794 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
796 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
797 int sock;
798 int ret;
799 struct addrinfo *ai;
800 struct addrinfo *ai_cur;
801 struct addrinfo hints;
802 RpcConnection *first_connection = NULL;
804 TRACE("(%p, %s)\n", protseq, endpoint);
806 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
807 hints.ai_family = PF_UNSPEC;
808 hints.ai_socktype = SOCK_STREAM;
809 hints.ai_protocol = IPPROTO_TCP;
810 hints.ai_addrlen = 0;
811 hints.ai_addr = NULL;
812 hints.ai_canonname = NULL;
813 hints.ai_next = NULL;
815 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
816 if (ret)
818 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
819 gai_strerror(ret));
820 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
821 return RPC_S_INVALID_ENDPOINT_FORMAT;
822 return RPC_S_CANT_CREATE_ENDPOINT;
825 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
827 RpcConnection_tcp *tcpc;
828 RPC_STATUS create_status;
830 if (TRACE_ON(rpc))
832 char host[256];
833 char service[256];
834 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
835 host, sizeof(host), service, sizeof(service),
836 NI_NUMERICHOST | NI_NUMERICSERV);
837 TRACE("trying %s:%s\n", host, service);
840 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
841 if (sock < 0)
843 WARN("socket() failed: %s\n", strerror(errno));
844 status = RPC_S_CANT_CREATE_ENDPOINT;
845 continue;
848 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
849 if (ret < 0)
851 WARN("bind failed: %s\n", strerror(errno));
852 close(sock);
853 if (errno == EADDRINUSE)
854 status = RPC_S_DUPLICATE_ENDPOINT;
855 else
856 status = RPC_S_CANT_CREATE_ENDPOINT;
857 continue;
859 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
860 protseq->Protseq, NULL,
861 endpoint, NULL, NULL, NULL,
862 NULL);
863 if (create_status != RPC_S_OK)
865 close(sock);
866 status = create_status;
867 continue;
870 tcpc->sock = sock;
871 ret = listen(sock, protseq->MaxCalls);
872 if (ret < 0)
874 WARN("listen failed: %s\n", strerror(errno));
875 RPCRT4_DestroyConnection(&tcpc->common);
876 status = RPC_S_OUT_OF_RESOURCES;
877 continue;
879 /* need a non-blocking socket, otherwise accept() has a potential
880 * race-condition (poll() says it is readable, connection drops,
881 * and accept() blocks until the next connection comes...)
883 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
884 if (ret < 0)
886 WARN("couldn't make socket non-blocking, error %d\n", ret);
887 RPCRT4_DestroyConnection(&tcpc->common);
888 status = RPC_S_OUT_OF_RESOURCES;
889 continue;
892 tcpc->common.Next = first_connection;
893 first_connection = &tcpc->common;
896 freeaddrinfo(ai);
898 /* if at least one connection was created for an endpoint then
899 * return success */
900 if (first_connection)
902 RpcConnection *conn;
904 /* find last element in list */
905 for (conn = first_connection; conn->Next; conn = conn->Next)
908 EnterCriticalSection(&protseq->cs);
909 conn->Next = protseq->conn;
910 protseq->conn = first_connection;
911 LeaveCriticalSection(&protseq->cs);
913 TRACE("listening on %s\n", endpoint);
914 return RPC_S_OK;
917 ERR("couldn't listen on port %s\n", endpoint);
918 return status;
921 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
923 int ret;
924 struct sockaddr_in address;
925 socklen_t addrsize;
926 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
927 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
929 addrsize = sizeof(address);
930 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
931 if (ret < 0)
933 ERR("Failed to accept a TCP connection: error %d\n", ret);
934 return RPC_S_OUT_OF_RESOURCES;
936 /* reset to blocking behaviour */
937 fcntl(ret, F_SETFL, 0);
938 client->sock = ret;
939 TRACE("Accepted a new TCP connection\n");
940 return RPC_S_OK;
943 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
944 void *buffer, unsigned int count)
946 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
947 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
948 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
949 return r;
952 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
953 const void *buffer, unsigned int count)
955 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
956 int r = write(tcpc->sock, buffer, count);
957 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
958 return r;
961 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
963 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
965 TRACE("%d\n", tcpc->sock);
967 if (tcpc->sock != -1)
968 close(tcpc->sock);
969 tcpc->sock = -1;
970 return 0;
973 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
974 const char *networkaddr,
975 const char *endpoint)
977 twr_tcp_floor_t *tcp_floor;
978 twr_ipv4_floor_t *ipv4_floor;
979 struct addrinfo *ai;
980 struct addrinfo hints;
981 int ret;
982 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
984 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
986 if (!tower_data)
987 return size;
989 tcp_floor = (twr_tcp_floor_t *)tower_data;
990 tower_data += sizeof(*tcp_floor);
992 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
994 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
995 tcp_floor->protid = EPM_PROTOCOL_TCP;
996 tcp_floor->count_rhs = sizeof(tcp_floor->port);
998 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
999 ipv4_floor->protid = EPM_PROTOCOL_IP;
1000 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
1002 hints.ai_flags = AI_NUMERICHOST;
1003 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
1004 hints.ai_family = PF_INET;
1005 hints.ai_socktype = SOCK_STREAM;
1006 hints.ai_protocol = IPPROTO_TCP;
1007 hints.ai_addrlen = 0;
1008 hints.ai_addr = NULL;
1009 hints.ai_canonname = NULL;
1010 hints.ai_next = NULL;
1012 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
1013 if (ret)
1015 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
1016 if (ret)
1018 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1019 return 0;
1023 if (ai->ai_family == PF_INET)
1025 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1026 tcp_floor->port = sin->sin_port;
1027 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1029 else
1031 ERR("unexpected protocol family %d\n", ai->ai_family);
1032 return 0;
1035 freeaddrinfo(ai);
1037 return size;
1040 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1041 size_t tower_size,
1042 char **networkaddr,
1043 char **endpoint)
1045 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1046 const twr_ipv4_floor_t *ipv4_floor;
1047 struct in_addr in_addr;
1049 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1051 if (tower_size < sizeof(*tcp_floor))
1052 return EPT_S_NOT_REGISTERED;
1054 tower_data += sizeof(*tcp_floor);
1055 tower_size -= sizeof(*tcp_floor);
1057 if (tower_size < sizeof(*ipv4_floor))
1058 return EPT_S_NOT_REGISTERED;
1060 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1062 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1063 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1064 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1065 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1066 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1067 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1068 return EPT_S_NOT_REGISTERED;
1070 if (endpoint)
1072 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1073 if (!*endpoint)
1074 return RPC_S_OUT_OF_RESOURCES;
1075 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1078 if (networkaddr)
1080 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1081 if (!*networkaddr)
1083 if (endpoint)
1085 I_RpcFree(*endpoint);
1086 *endpoint = NULL;
1088 return RPC_S_OUT_OF_RESOURCES;
1090 in_addr.s_addr = ipv4_floor->ipv4addr;
1091 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1093 ERR("inet_ntop: %s\n", strerror(errno));
1094 I_RpcFree(*networkaddr);
1095 *networkaddr = NULL;
1096 if (endpoint)
1098 I_RpcFree(*endpoint);
1099 *endpoint = NULL;
1101 return EPT_S_NOT_REGISTERED;
1105 return RPC_S_OK;
1108 typedef struct _RpcServerProtseq_sock
1110 RpcServerProtseq common;
1111 int mgr_event_rcv;
1112 int mgr_event_snd;
1113 } RpcServerProtseq_sock;
1115 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1117 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1118 if (ps)
1120 int fds[2];
1121 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1123 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1124 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1125 ps->mgr_event_rcv = fds[0];
1126 ps->mgr_event_snd = fds[1];
1128 else
1130 ERR("socketpair failed with error %s\n", strerror(errno));
1131 HeapFree(GetProcessHeap(), 0, ps);
1132 return NULL;
1135 return &ps->common;
1138 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1140 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1141 char dummy = 1;
1142 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1145 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1147 struct pollfd *poll_info = prev_array;
1148 RpcConnection_tcp *conn;
1149 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1151 EnterCriticalSection(&protseq->cs);
1153 /* open and count connections */
1154 *count = 1;
1155 conn = (RpcConnection_tcp *)protseq->conn;
1156 while (conn) {
1157 if (conn->sock != -1)
1158 (*count)++;
1159 conn = (RpcConnection_tcp *)conn->common.Next;
1162 /* make array of connections */
1163 if (poll_info)
1164 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1165 else
1166 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1167 if (!poll_info)
1169 ERR("couldn't allocate poll_info\n");
1170 LeaveCriticalSection(&protseq->cs);
1171 return NULL;
1174 poll_info[0].fd = sockps->mgr_event_rcv;
1175 poll_info[0].events = POLLIN;
1176 *count = 1;
1177 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1178 while (conn) {
1179 if (conn->sock != -1)
1181 poll_info[*count].fd = conn->sock;
1182 poll_info[*count].events = POLLIN;
1183 (*count)++;
1185 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1187 LeaveCriticalSection(&protseq->cs);
1188 return poll_info;
1191 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1193 HeapFree(GetProcessHeap(), 0, array);
1196 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1198 struct pollfd *poll_info = wait_array;
1199 int ret, i;
1200 RpcConnection *cconn;
1201 RpcConnection_tcp *conn;
1203 if (!poll_info)
1204 return -1;
1206 ret = poll(poll_info, count, -1);
1207 if (ret < 0)
1209 ERR("poll failed with error %d\n", ret);
1210 return -1;
1213 for (i = 0; i < count; i++)
1214 if (poll_info[i].revents & POLLIN)
1216 /* RPC server event */
1217 if (i == 0)
1219 char dummy;
1220 read(poll_info[0].fd, &dummy, sizeof(dummy));
1221 return 0;
1224 /* find which connection got a RPC */
1225 EnterCriticalSection(&protseq->cs);
1226 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1227 while (conn) {
1228 if (poll_info[i].fd == conn->sock) break;
1229 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1231 cconn = NULL;
1232 if (conn)
1233 RPCRT4_SpawnConnection(&cconn, &conn->common);
1234 else
1235 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1236 LeaveCriticalSection(&protseq->cs);
1237 if (cconn)
1238 RPCRT4_new_client(cconn);
1239 else
1240 return -1;
1243 return 1;
1246 static const struct connection_ops conn_protseq_list[] = {
1247 { "ncacn_np",
1248 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1249 rpcrt4_conn_np_alloc,
1250 rpcrt4_ncacn_np_open,
1251 rpcrt4_ncacn_np_handoff,
1252 rpcrt4_conn_np_read,
1253 rpcrt4_conn_np_write,
1254 rpcrt4_conn_np_close,
1255 rpcrt4_ncacn_np_get_top_of_tower,
1256 rpcrt4_ncacn_np_parse_top_of_tower,
1258 { "ncalrpc",
1259 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1260 rpcrt4_conn_np_alloc,
1261 rpcrt4_ncalrpc_open,
1262 rpcrt4_ncalrpc_handoff,
1263 rpcrt4_conn_np_read,
1264 rpcrt4_conn_np_write,
1265 rpcrt4_conn_np_close,
1266 rpcrt4_ncalrpc_get_top_of_tower,
1267 rpcrt4_ncalrpc_parse_top_of_tower,
1269 { "ncacn_ip_tcp",
1270 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1271 rpcrt4_conn_tcp_alloc,
1272 rpcrt4_ncacn_ip_tcp_open,
1273 rpcrt4_conn_tcp_handoff,
1274 rpcrt4_conn_tcp_read,
1275 rpcrt4_conn_tcp_write,
1276 rpcrt4_conn_tcp_close,
1277 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1278 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1283 static const struct protseq_ops protseq_list[] =
1286 "ncacn_np",
1287 rpcrt4_protseq_np_alloc,
1288 rpcrt4_protseq_np_signal_state_changed,
1289 rpcrt4_protseq_np_get_wait_array,
1290 rpcrt4_protseq_np_free_wait_array,
1291 rpcrt4_protseq_np_wait_for_new_connection,
1292 rpcrt4_protseq_ncacn_np_open_endpoint,
1295 "ncalrpc",
1296 rpcrt4_protseq_np_alloc,
1297 rpcrt4_protseq_np_signal_state_changed,
1298 rpcrt4_protseq_np_get_wait_array,
1299 rpcrt4_protseq_np_free_wait_array,
1300 rpcrt4_protseq_np_wait_for_new_connection,
1301 rpcrt4_protseq_ncalrpc_open_endpoint,
1304 "ncacn_ip_tcp",
1305 rpcrt4_protseq_sock_alloc,
1306 rpcrt4_protseq_sock_signal_state_changed,
1307 rpcrt4_protseq_sock_get_wait_array,
1308 rpcrt4_protseq_sock_free_wait_array,
1309 rpcrt4_protseq_sock_wait_for_new_connection,
1310 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1314 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1316 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1318 int i;
1319 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1320 if (!strcmp(protseq_list[i].name, protseq))
1321 return &protseq_list[i];
1322 return NULL;
1325 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1327 int i;
1328 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1329 if (!strcmp(conn_protseq_list[i].name, protseq))
1330 return &conn_protseq_list[i];
1331 return NULL;
1334 /**** interface to rest of code ****/
1336 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1338 TRACE("(Connection == ^%p)\n", Connection);
1340 assert(!Connection->server);
1341 return Connection->ops->open_connection_client(Connection);
1344 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1346 TRACE("(Connection == ^%p)\n", Connection);
1347 if (SecIsValidHandle(&Connection->ctx))
1349 DeleteSecurityContext(&Connection->ctx);
1350 SecInvalidateHandle(&Connection->ctx);
1352 rpcrt4_conn_close(Connection);
1353 return RPC_S_OK;
1356 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1357 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1358 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS,
1359 RpcBinding* Binding)
1361 const struct connection_ops *ops;
1362 RpcConnection* NewConnection;
1364 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1365 if (!ops)
1367 FIXME("not supported for protseq %s\n", Protseq);
1368 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1371 NewConnection = ops->alloc();
1372 NewConnection->Next = NULL;
1373 NewConnection->server = server;
1374 NewConnection->ops = ops;
1375 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1376 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1377 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1378 NewConnection->Used = Binding;
1379 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1380 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1381 NewConnection->NextCallId = 1;
1383 SecInvalidateHandle(&NewConnection->ctx);
1384 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1385 NewConnection->AuthInfo = AuthInfo;
1386 if (QOS) RpcQualityOfService_AddRef(QOS);
1387 NewConnection->QOS = QOS;
1388 list_init(&NewConnection->conn_pool_entry);
1390 TRACE("connection: %p\n", NewConnection);
1391 *Connection = NewConnection;
1393 return RPC_S_OK;
1396 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1397 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1398 LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS)
1400 RpcConnection *Connection;
1401 /* try to find a compatible connection from the connection pool */
1402 EnterCriticalSection(&connection_pool_cs);
1403 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1404 if ((Connection->AuthInfo == AuthInfo) &&
1405 (Connection->QOS == QOS) &&
1406 !memcmp(&Connection->ActiveInterface, InterfaceId,
1407 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1408 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1409 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1410 !strcmp(Connection->Endpoint, Endpoint))
1412 list_remove(&Connection->conn_pool_entry);
1413 LeaveCriticalSection(&connection_pool_cs);
1414 TRACE("got connection from pool %p\n", Connection);
1415 return Connection;
1418 LeaveCriticalSection(&connection_pool_cs);
1419 return NULL;
1422 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1424 assert(!Connection->server);
1425 EnterCriticalSection(&connection_pool_cs);
1426 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1427 LeaveCriticalSection(&connection_pool_cs);
1431 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1433 RPC_STATUS err;
1435 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1436 rpcrt4_conn_get_name(OldConnection),
1437 OldConnection->NetworkAddr,
1438 OldConnection->Endpoint, NULL,
1439 OldConnection->AuthInfo, OldConnection->QOS,
1440 NULL);
1441 if (err == RPC_S_OK)
1442 rpcrt4_conn_handoff(OldConnection, *Connection);
1443 return err;
1446 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1448 TRACE("connection: %p\n", Connection);
1450 RPCRT4_CloseConnection(Connection);
1451 RPCRT4_strfree(Connection->Endpoint);
1452 RPCRT4_strfree(Connection->NetworkAddr);
1453 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
1454 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1455 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
1456 HeapFree(GetProcessHeap(), 0, Connection);
1457 return RPC_S_OK;
1460 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1461 size_t *tower_size,
1462 const char *protseq,
1463 const char *networkaddr,
1464 const char *endpoint)
1466 twr_empty_floor_t *protocol_floor;
1467 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1469 *tower_size = 0;
1471 if (!protseq_ops)
1472 return RPC_S_INVALID_RPC_PROTSEQ;
1474 if (!tower_data)
1476 *tower_size = sizeof(*protocol_floor);
1477 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1478 return RPC_S_OK;
1481 protocol_floor = (twr_empty_floor_t *)tower_data;
1482 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1483 protocol_floor->protid = protseq_ops->epm_protocols[0];
1484 protocol_floor->count_rhs = 0;
1486 tower_data += sizeof(*protocol_floor);
1488 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1489 if (!*tower_size)
1490 return EPT_S_NOT_REGISTERED;
1492 *tower_size += sizeof(*protocol_floor);
1494 return RPC_S_OK;
1497 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1498 size_t tower_size,
1499 char **protseq,
1500 char **networkaddr,
1501 char **endpoint)
1503 const twr_empty_floor_t *protocol_floor;
1504 const twr_empty_floor_t *floor4;
1505 const struct connection_ops *protseq_ops = NULL;
1506 RPC_STATUS status;
1507 int i;
1509 if (tower_size < sizeof(*protocol_floor))
1510 return EPT_S_NOT_REGISTERED;
1512 protocol_floor = (const twr_empty_floor_t *)tower_data;
1513 tower_data += sizeof(*protocol_floor);
1514 tower_size -= sizeof(*protocol_floor);
1515 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1516 (protocol_floor->count_rhs > tower_size))
1517 return EPT_S_NOT_REGISTERED;
1518 tower_data += protocol_floor->count_rhs;
1519 tower_size -= protocol_floor->count_rhs;
1521 floor4 = (const twr_empty_floor_t *)tower_data;
1522 if ((tower_size < sizeof(*floor4)) ||
1523 (floor4->count_lhs != sizeof(floor4->protid)))
1524 return EPT_S_NOT_REGISTERED;
1526 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1527 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1528 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1530 protseq_ops = &conn_protseq_list[i];
1531 break;
1534 if (!protseq_ops)
1535 return EPT_S_NOT_REGISTERED;
1537 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1539 if ((status == RPC_S_OK) && protseq)
1541 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1542 strcpy(*protseq, protseq_ops->name);
1545 return status;
1548 /***********************************************************************
1549 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1551 * Checks if the given protocol sequence is known by the RPC system.
1552 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1555 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1557 char ps[0x10];
1559 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1560 ps, sizeof ps, NULL, NULL);
1561 if (rpcrt4_get_conn_protseq_ops(ps))
1562 return RPC_S_OK;
1564 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1566 return RPC_S_INVALID_RPC_PROTSEQ;
1569 /***********************************************************************
1570 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1572 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1574 UNICODE_STRING protseqW;
1576 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1578 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1579 RtlFreeUnicodeString(&protseqW);
1580 return ret;
1582 return RPC_S_OUT_OF_MEMORY;