4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
7 * Copyright 2006 Mike McCormack
8 * Copyright 2006 Damjan Jovanovic
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 # include <arpa/inet.h>
52 #ifdef HAVE_SYS_POLL_H
62 #include "wine/unicode.h"
67 #include "wine/debug.h"
69 #include "rpc_binding.h"
70 #include "rpc_message.h"
71 #include "rpc_server.h"
72 #include "epm_towers.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
76 static CRITICAL_SECTION connection_pool_cs;
77 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
79 0, 0, &connection_pool_cs,
80 { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
81 0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
83 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
85 static struct list connection_pool = LIST_INIT(connection_pool);
87 /**** ncacn_np support ****/
89 typedef struct _RpcConnection_np
97 static RpcConnection *rpcrt4_conn_np_alloc(void)
99 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
103 memset(&npc->ovl, 0, sizeof(npc->ovl));
104 npc->listening = FALSE;
109 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
114 npc->listening = TRUE;
115 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
118 if (GetLastError() == ERROR_PIPE_CONNECTED) {
119 SetEvent(npc->ovl.hEvent);
122 if (GetLastError() == ERROR_IO_PENDING) {
123 /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
126 npc->listening = FALSE;
127 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
128 return RPC_S_OUT_OF_RESOURCES;
131 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
133 RpcConnection_np *npc = (RpcConnection_np *) Connection;
134 TRACE("listening on %s\n", pname);
136 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
137 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
138 PIPE_UNLIMITED_INSTANCES,
139 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
140 if (npc->pipe == INVALID_HANDLE_VALUE) {
141 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
142 if (GetLastError() == ERROR_FILE_EXISTS)
143 return RPC_S_DUPLICATE_ENDPOINT;
145 return RPC_S_CANT_CREATE_ENDPOINT;
148 memset(&npc->ovl, 0, sizeof(npc->ovl));
149 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
151 /* Note: we don't call ConnectNamedPipe here because it must be done in the
152 * server thread as the thread must be alertable */
156 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
158 RpcConnection_np *npc = (RpcConnection_np *) Connection;
162 TRACE("connecting to %s\n", pname);
168 dwFlags = SECURITY_SQOS_PRESENT;
169 switch (Connection->QOS->qos->ImpersonationType)
171 case RPC_C_IMP_LEVEL_DEFAULT:
172 /* FIXME: what to do here? */
174 case RPC_C_IMP_LEVEL_ANONYMOUS:
175 dwFlags |= SECURITY_ANONYMOUS;
177 case RPC_C_IMP_LEVEL_IDENTIFY:
178 dwFlags |= SECURITY_IDENTIFICATION;
180 case RPC_C_IMP_LEVEL_IMPERSONATE:
181 dwFlags |= SECURITY_IMPERSONATION;
183 case RPC_C_IMP_LEVEL_DELEGATE:
184 dwFlags |= SECURITY_DELEGATION;
187 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
188 dwFlags |= SECURITY_CONTEXT_TRACKING;
190 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
191 OPEN_EXISTING, dwFlags, 0);
192 if (pipe != INVALID_HANDLE_VALUE) break;
193 err = GetLastError();
194 if (err == ERROR_PIPE_BUSY) {
195 TRACE("connection failed, error=%x\n", err);
196 return RPC_S_SERVER_TOO_BUSY;
199 return RPC_S_SERVER_UNAVAILABLE;
200 if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
201 err = GetLastError();
202 WARN("connection failed, error=%x\n", err);
203 return RPC_S_SERVER_UNAVAILABLE;
208 memset(&npc->ovl, 0, sizeof(npc->ovl));
209 /* pipe is connected; change to message-read mode. */
210 dwMode = PIPE_READMODE_MESSAGE;
211 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
212 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
218 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
220 RpcConnection_np *npc = (RpcConnection_np *) Connection;
221 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
225 /* already connected? */
229 /* protseq=ncalrpc: supposed to use NT LPC ports,
230 * but we'll implement it with named pipes for now */
231 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
232 strcat(strcpy(pname, prefix), Connection->Endpoint);
233 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
239 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
241 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
244 RpcConnection *Connection;
246 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
247 endpoint, NULL, NULL, NULL, NULL);
251 /* protseq=ncalrpc: supposed to use NT LPC ports,
252 * but we'll implement it with named pipes for now */
253 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
254 strcat(strcpy(pname, prefix), Connection->Endpoint);
255 r = rpcrt4_conn_create_pipe(Connection, pname);
258 EnterCriticalSection(&protseq->cs);
259 Connection->Next = protseq->conn;
260 protseq->conn = Connection;
261 LeaveCriticalSection(&protseq->cs);
266 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
268 RpcConnection_np *npc = (RpcConnection_np *) Connection;
269 static const char prefix[] = "\\\\.";
273 /* already connected? */
277 /* protseq=ncacn_np: named pipes */
278 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
279 strcat(strcpy(pname, prefix), Connection->Endpoint);
280 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
286 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
288 static const char prefix[] = "\\\\.";
291 RpcConnection *Connection;
293 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
294 endpoint, NULL, NULL, NULL, NULL);
298 /* protseq=ncacn_np: named pipes */
299 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
300 strcat(strcpy(pname, prefix), Connection->Endpoint);
301 r = rpcrt4_conn_create_pipe(Connection, pname);
307 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
309 /* because of the way named pipes work, we'll transfer the connected pipe
310 * to the child, then reopen the server binding to continue listening */
312 new_npc->pipe = old_npc->pipe;
313 new_npc->ovl = old_npc->ovl;
315 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
316 old_npc->listening = FALSE;
319 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
323 static const char prefix[] = "\\\\.";
325 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
327 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
328 strcat(strcpy(pname, prefix), old_conn->Endpoint);
329 status = rpcrt4_conn_create_pipe(old_conn, pname);
335 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
339 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
341 TRACE("%s\n", old_conn->Endpoint);
343 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
345 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
346 strcat(strcpy(pname, prefix), old_conn->Endpoint);
347 status = rpcrt4_conn_create_pipe(old_conn, pname);
353 static int rpcrt4_conn_np_read(RpcConnection *Connection,
354 void *buffer, unsigned int count)
356 RpcConnection_np *npc = (RpcConnection_np *) Connection;
359 unsigned int bytes_left = count;
364 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
365 if (!ret || !bytes_read)
367 bytes_left -= bytes_read;
370 return ret ? count : -1;
373 static int rpcrt4_conn_np_write(RpcConnection *Connection,
374 const void *buffer, unsigned int count)
376 RpcConnection_np *npc = (RpcConnection_np *) Connection;
377 const char *buf = buffer;
379 unsigned int bytes_left = count;
384 ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
385 if (!ret || !bytes_written)
387 bytes_left -= bytes_written;
388 buf += bytes_written;
390 return ret ? count : -1;
393 static int rpcrt4_conn_np_close(RpcConnection *Connection)
395 RpcConnection_np *npc = (RpcConnection_np *) Connection;
397 FlushFileBuffers(npc->pipe);
398 CloseHandle(npc->pipe);
401 if (npc->ovl.hEvent) {
402 CloseHandle(npc->ovl.hEvent);
408 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
409 const char *networkaddr,
410 const char *endpoint)
412 twr_empty_floor_t *smb_floor;
413 twr_empty_floor_t *nb_floor;
415 size_t networkaddr_size;
416 size_t endpoint_size;
418 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
420 networkaddr_size = strlen(networkaddr) + 1;
421 endpoint_size = strlen(endpoint) + 1;
422 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
427 smb_floor = (twr_empty_floor_t *)tower_data;
429 tower_data += sizeof(*smb_floor);
431 smb_floor->count_lhs = sizeof(smb_floor->protid);
432 smb_floor->protid = EPM_PROTOCOL_SMB;
433 smb_floor->count_rhs = endpoint_size;
435 memcpy(tower_data, endpoint, endpoint_size);
436 tower_data += endpoint_size;
438 nb_floor = (twr_empty_floor_t *)tower_data;
440 tower_data += sizeof(*nb_floor);
442 nb_floor->count_lhs = sizeof(nb_floor->protid);
443 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
444 nb_floor->count_rhs = networkaddr_size;
446 memcpy(tower_data, networkaddr, networkaddr_size);
447 tower_data += networkaddr_size;
452 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
457 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
458 const twr_empty_floor_t *nb_floor;
460 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
462 if (tower_size < sizeof(*smb_floor))
463 return EPT_S_NOT_REGISTERED;
465 tower_data += sizeof(*smb_floor);
466 tower_size -= sizeof(*smb_floor);
468 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
469 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
470 (smb_floor->count_rhs > tower_size))
471 return EPT_S_NOT_REGISTERED;
475 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
477 return RPC_S_OUT_OF_RESOURCES;
478 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
480 tower_data += smb_floor->count_rhs;
481 tower_size -= smb_floor->count_rhs;
483 if (tower_size < sizeof(*nb_floor))
484 return EPT_S_NOT_REGISTERED;
486 nb_floor = (const twr_empty_floor_t *)tower_data;
488 tower_data += sizeof(*nb_floor);
489 tower_size -= sizeof(*nb_floor);
491 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
492 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
493 (nb_floor->count_rhs > tower_size))
494 return EPT_S_NOT_REGISTERED;
498 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
503 I_RpcFree(*endpoint);
506 return RPC_S_OUT_OF_RESOURCES;
508 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
514 typedef struct _RpcServerProtseq_np
516 RpcServerProtseq common;
518 } RpcServerProtseq_np;
520 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
522 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
524 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
528 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
530 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
531 SetEvent(npps->mgr_event);
534 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
536 HANDLE *objs = prev_array;
537 RpcConnection_np *conn;
538 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
540 EnterCriticalSection(&protseq->cs);
542 /* open and count connections */
544 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
546 rpcrt4_conn_listen_pipe(conn);
547 if (conn->ovl.hEvent)
549 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
552 /* make array of connections */
554 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
556 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
559 ERR("couldn't allocate objs\n");
560 LeaveCriticalSection(&protseq->cs);
564 objs[0] = npps->mgr_event;
566 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
568 if ((objs[*count] = conn->ovl.hEvent))
570 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
572 LeaveCriticalSection(&protseq->cs);
576 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
578 HeapFree(GetProcessHeap(), 0, array);
581 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
584 HANDLE *objs = wait_array;
586 RpcConnection *cconn;
587 RpcConnection_np *conn;
592 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
593 if (res == WAIT_OBJECT_0)
595 else if (res == WAIT_FAILED)
597 ERR("wait failed with error %d\n", GetLastError());
602 b_handle = objs[res - WAIT_OBJECT_0];
603 /* find which connection got a RPC */
604 EnterCriticalSection(&protseq->cs);
605 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
607 if (b_handle == conn->ovl.hEvent) break;
608 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
612 RPCRT4_SpawnConnection(&cconn, &conn->common);
614 ERR("failed to locate connection for handle %p\n", b_handle);
615 LeaveCriticalSection(&protseq->cs);
618 RPCRT4_new_client(cconn);
625 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
626 const char *networkaddr,
627 const char *endpoint)
629 twr_empty_floor_t *pipe_floor;
631 size_t endpoint_size;
633 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
635 endpoint_size = strlen(networkaddr) + 1;
636 size = sizeof(*pipe_floor) + endpoint_size;
641 pipe_floor = (twr_empty_floor_t *)tower_data;
643 tower_data += sizeof(*pipe_floor);
645 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
646 pipe_floor->protid = EPM_PROTOCOL_SMB;
647 pipe_floor->count_rhs = endpoint_size;
649 memcpy(tower_data, endpoint, endpoint_size);
650 tower_data += endpoint_size;
655 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
660 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
662 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
667 if (tower_size < sizeof(*pipe_floor))
668 return EPT_S_NOT_REGISTERED;
670 tower_data += sizeof(*pipe_floor);
671 tower_size -= sizeof(*pipe_floor);
673 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
674 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
675 (pipe_floor->count_rhs > tower_size))
676 return EPT_S_NOT_REGISTERED;
680 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
682 return RPC_S_OUT_OF_RESOURCES;
683 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
689 /**** ncacn_ip_tcp support ****/
691 typedef struct _RpcConnection_tcp
693 RpcConnection common;
697 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
699 RpcConnection_tcp *tcpc;
700 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
704 return &tcpc->common;
707 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
709 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
713 struct addrinfo *ai_cur;
714 struct addrinfo hints;
716 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
718 if (tcpc->sock != -1)
722 hints.ai_family = PF_UNSPEC;
723 hints.ai_socktype = SOCK_STREAM;
724 hints.ai_protocol = IPPROTO_TCP;
725 hints.ai_addrlen = 0;
726 hints.ai_addr = NULL;
727 hints.ai_canonname = NULL;
728 hints.ai_next = NULL;
730 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
733 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
734 Connection->Endpoint, gai_strerror(ret));
735 return RPC_S_SERVER_UNAVAILABLE;
738 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
744 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
745 host, sizeof(host), service, sizeof(service),
746 NI_NUMERICHOST | NI_NUMERICSERV);
747 TRACE("trying %s:%s\n", host, service);
750 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
753 WARN("socket() failed: %s\n", strerror(errno));
757 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
759 WARN("connect() failed: %s\n", strerror(errno));
766 TRACE("connected\n");
771 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
772 return RPC_S_SERVER_UNAVAILABLE;
775 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
777 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
781 struct addrinfo *ai_cur;
782 struct addrinfo hints;
783 RpcConnection *first_connection = NULL;
785 TRACE("(%p, %s)\n", protseq, endpoint);
787 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
788 hints.ai_family = PF_UNSPEC;
789 hints.ai_socktype = SOCK_STREAM;
790 hints.ai_protocol = IPPROTO_TCP;
791 hints.ai_addrlen = 0;
792 hints.ai_addr = NULL;
793 hints.ai_canonname = NULL;
794 hints.ai_next = NULL;
796 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
799 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
801 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
802 return RPC_S_INVALID_ENDPOINT_FORMAT;
803 return RPC_S_CANT_CREATE_ENDPOINT;
806 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
808 RpcConnection_tcp *tcpc;
809 RPC_STATUS create_status;
815 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
816 host, sizeof(host), service, sizeof(service),
817 NI_NUMERICHOST | NI_NUMERICSERV);
818 TRACE("trying %s:%s\n", host, service);
821 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
824 WARN("socket() failed: %s\n", strerror(errno));
825 status = RPC_S_CANT_CREATE_ENDPOINT;
829 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
832 WARN("bind failed: %s\n", strerror(errno));
834 if (errno == EADDRINUSE)
835 status = RPC_S_DUPLICATE_ENDPOINT;
837 status = RPC_S_CANT_CREATE_ENDPOINT;
840 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
841 protseq->Protseq, NULL,
842 endpoint, NULL, NULL, NULL,
844 if (create_status != RPC_S_OK)
847 status = create_status;
852 ret = listen(sock, protseq->MaxCalls);
855 WARN("listen failed: %s\n", strerror(errno));
856 RPCRT4_DestroyConnection(&tcpc->common);
857 status = RPC_S_OUT_OF_RESOURCES;
860 /* need a non-blocking socket, otherwise accept() has a potential
861 * race-condition (poll() says it is readable, connection drops,
862 * and accept() blocks until the next connection comes...)
864 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
867 WARN("couldn't make socket non-blocking, error %d\n", ret);
868 RPCRT4_DestroyConnection(&tcpc->common);
869 status = RPC_S_OUT_OF_RESOURCES;
873 tcpc->common.Next = first_connection;
874 first_connection = &tcpc->common;
879 /* if at least one connection was created for an endpoint then
881 if (first_connection)
885 /* find last element in list */
886 for (conn = first_connection; conn->Next; conn = conn->Next)
889 EnterCriticalSection(&protseq->cs);
890 conn->Next = protseq->conn;
891 protseq->conn = first_connection;
892 LeaveCriticalSection(&protseq->cs);
894 TRACE("listening on %s\n", endpoint);
898 ERR("couldn't listen on port %s\n", endpoint);
902 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
905 struct sockaddr_in address;
907 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
908 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
910 addrsize = sizeof(address);
911 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
914 ERR("Failed to accept a TCP connection: error %d\n", ret);
915 return RPC_S_OUT_OF_RESOURCES;
917 /* reset to blocking behaviour */
918 fcntl(ret, F_SETFL, 0);
920 TRACE("Accepted a new TCP connection\n");
924 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
925 void *buffer, unsigned int count)
927 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
928 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
929 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
933 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
934 const void *buffer, unsigned int count)
936 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
937 int r = write(tcpc->sock, buffer, count);
938 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
942 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
944 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
946 TRACE("%d\n", tcpc->sock);
948 if (tcpc->sock != -1)
954 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
955 const char *networkaddr,
956 const char *endpoint)
958 twr_tcp_floor_t *tcp_floor;
959 twr_ipv4_floor_t *ipv4_floor;
961 struct addrinfo hints;
963 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
965 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
970 tcp_floor = (twr_tcp_floor_t *)tower_data;
971 tower_data += sizeof(*tcp_floor);
973 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
975 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
976 tcp_floor->protid = EPM_PROTOCOL_TCP;
977 tcp_floor->count_rhs = sizeof(tcp_floor->port);
979 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
980 ipv4_floor->protid = EPM_PROTOCOL_IP;
981 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
983 hints.ai_flags = AI_NUMERICHOST;
984 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
985 hints.ai_family = PF_INET;
986 hints.ai_socktype = SOCK_STREAM;
987 hints.ai_protocol = IPPROTO_TCP;
988 hints.ai_addrlen = 0;
989 hints.ai_addr = NULL;
990 hints.ai_canonname = NULL;
991 hints.ai_next = NULL;
993 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
996 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
999 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1004 if (ai->ai_family == PF_INET)
1006 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1007 tcp_floor->port = sin->sin_port;
1008 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1012 ERR("unexpected protocol family %d\n", ai->ai_family);
1021 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1026 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1027 const twr_ipv4_floor_t *ipv4_floor;
1028 struct in_addr in_addr;
1030 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1032 if (tower_size < sizeof(*tcp_floor))
1033 return EPT_S_NOT_REGISTERED;
1035 tower_data += sizeof(*tcp_floor);
1036 tower_size -= sizeof(*tcp_floor);
1038 if (tower_size < sizeof(*ipv4_floor))
1039 return EPT_S_NOT_REGISTERED;
1041 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1043 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1044 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1045 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1046 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1047 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1048 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1049 return EPT_S_NOT_REGISTERED;
1053 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1055 return RPC_S_OUT_OF_RESOURCES;
1056 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1061 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1066 I_RpcFree(*endpoint);
1069 return RPC_S_OUT_OF_RESOURCES;
1071 in_addr.s_addr = ipv4_floor->ipv4addr;
1072 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1074 ERR("inet_ntop: %s\n", strerror(errno));
1075 I_RpcFree(*networkaddr);
1076 *networkaddr = NULL;
1079 I_RpcFree(*endpoint);
1082 return EPT_S_NOT_REGISTERED;
1089 typedef struct _RpcServerProtseq_sock
1091 RpcServerProtseq common;
1094 } RpcServerProtseq_sock;
1096 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1098 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1102 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1104 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1105 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1106 ps->mgr_event_rcv = fds[0];
1107 ps->mgr_event_snd = fds[1];
1111 ERR("socketpair failed with error %s\n", strerror(errno));
1112 HeapFree(GetProcessHeap(), 0, ps);
1119 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1121 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1123 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1126 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1128 struct pollfd *poll_info = prev_array;
1129 RpcConnection_tcp *conn;
1130 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1132 EnterCriticalSection(&protseq->cs);
1134 /* open and count connections */
1136 conn = (RpcConnection_tcp *)protseq->conn;
1138 if (conn->sock != -1)
1140 conn = (RpcConnection_tcp *)conn->common.Next;
1143 /* make array of connections */
1145 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1147 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1150 ERR("couldn't allocate poll_info\n");
1151 LeaveCriticalSection(&protseq->cs);
1155 poll_info[0].fd = sockps->mgr_event_rcv;
1156 poll_info[0].events = POLLIN;
1158 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1160 if (conn->sock != -1)
1162 poll_info[*count].fd = conn->sock;
1163 poll_info[*count].events = POLLIN;
1166 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1168 LeaveCriticalSection(&protseq->cs);
1172 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1174 HeapFree(GetProcessHeap(), 0, array);
1177 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1179 struct pollfd *poll_info = wait_array;
1181 RpcConnection *cconn;
1182 RpcConnection_tcp *conn;
1187 ret = poll(poll_info, count, -1);
1190 ERR("poll failed with error %d\n", ret);
1194 for (i = 0; i < count; i++)
1195 if (poll_info[i].revents & POLLIN)
1197 /* RPC server event */
1201 read(poll_info[0].fd, &dummy, sizeof(dummy));
1205 /* find which connection got a RPC */
1206 EnterCriticalSection(&protseq->cs);
1207 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1209 if (poll_info[i].fd == conn->sock) break;
1210 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1214 RPCRT4_SpawnConnection(&cconn, &conn->common);
1216 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1217 LeaveCriticalSection(&protseq->cs);
1219 RPCRT4_new_client(cconn);
1227 static const struct connection_ops conn_protseq_list[] = {
1229 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1230 rpcrt4_conn_np_alloc,
1231 rpcrt4_ncacn_np_open,
1232 rpcrt4_ncacn_np_handoff,
1233 rpcrt4_conn_np_read,
1234 rpcrt4_conn_np_write,
1235 rpcrt4_conn_np_close,
1236 rpcrt4_ncacn_np_get_top_of_tower,
1237 rpcrt4_ncacn_np_parse_top_of_tower,
1240 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1241 rpcrt4_conn_np_alloc,
1242 rpcrt4_ncalrpc_open,
1243 rpcrt4_ncalrpc_handoff,
1244 rpcrt4_conn_np_read,
1245 rpcrt4_conn_np_write,
1246 rpcrt4_conn_np_close,
1247 rpcrt4_ncalrpc_get_top_of_tower,
1248 rpcrt4_ncalrpc_parse_top_of_tower,
1251 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1252 rpcrt4_conn_tcp_alloc,
1253 rpcrt4_ncacn_ip_tcp_open,
1254 rpcrt4_conn_tcp_handoff,
1255 rpcrt4_conn_tcp_read,
1256 rpcrt4_conn_tcp_write,
1257 rpcrt4_conn_tcp_close,
1258 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1259 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1264 static const struct protseq_ops protseq_list[] =
1268 rpcrt4_protseq_np_alloc,
1269 rpcrt4_protseq_np_signal_state_changed,
1270 rpcrt4_protseq_np_get_wait_array,
1271 rpcrt4_protseq_np_free_wait_array,
1272 rpcrt4_protseq_np_wait_for_new_connection,
1273 rpcrt4_protseq_ncacn_np_open_endpoint,
1277 rpcrt4_protseq_np_alloc,
1278 rpcrt4_protseq_np_signal_state_changed,
1279 rpcrt4_protseq_np_get_wait_array,
1280 rpcrt4_protseq_np_free_wait_array,
1281 rpcrt4_protseq_np_wait_for_new_connection,
1282 rpcrt4_protseq_ncalrpc_open_endpoint,
1286 rpcrt4_protseq_sock_alloc,
1287 rpcrt4_protseq_sock_signal_state_changed,
1288 rpcrt4_protseq_sock_get_wait_array,
1289 rpcrt4_protseq_sock_free_wait_array,
1290 rpcrt4_protseq_sock_wait_for_new_connection,
1291 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1295 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1297 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1300 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1301 if (!strcmp(protseq_list[i].name, protseq))
1302 return &protseq_list[i];
1306 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1309 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1310 if (!strcmp(conn_protseq_list[i].name, protseq))
1311 return &conn_protseq_list[i];
1315 /**** interface to rest of code ****/
1317 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1319 TRACE("(Connection == ^%p)\n", Connection);
1321 assert(!Connection->server);
1322 return Connection->ops->open_connection_client(Connection);
1325 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1327 TRACE("(Connection == ^%p)\n", Connection);
1328 if (SecIsValidHandle(&Connection->ctx))
1330 DeleteSecurityContext(&Connection->ctx);
1331 SecInvalidateHandle(&Connection->ctx);
1333 rpcrt4_conn_close(Connection);
1337 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1338 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1339 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS,
1340 RpcBinding* Binding)
1342 const struct connection_ops *ops;
1343 RpcConnection* NewConnection;
1345 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1348 FIXME("not supported for protseq %s\n", Protseq);
1349 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1352 NewConnection = ops->alloc();
1353 NewConnection->Next = NULL;
1354 NewConnection->server = server;
1355 NewConnection->ops = ops;
1356 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1357 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1358 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1359 NewConnection->Used = Binding;
1360 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1361 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1362 NewConnection->NextCallId = 1;
1364 SecInvalidateHandle(&NewConnection->ctx);
1365 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1366 NewConnection->AuthInfo = AuthInfo;
1367 if (QOS) RpcQualityOfService_AddRef(QOS);
1368 NewConnection->QOS = QOS;
1369 list_init(&NewConnection->conn_pool_entry);
1371 TRACE("connection: %p\n", NewConnection);
1372 *Connection = NewConnection;
1377 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1378 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1379 LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS)
1381 RpcConnection *Connection;
1382 /* try to find a compatible connection from the connection pool */
1383 EnterCriticalSection(&connection_pool_cs);
1384 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1385 if ((Connection->AuthInfo == AuthInfo) &&
1386 (Connection->QOS == QOS) &&
1387 !memcmp(&Connection->ActiveInterface, InterfaceId,
1388 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1389 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1390 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1391 !strcmp(Connection->Endpoint, Endpoint))
1393 list_remove(&Connection->conn_pool_entry);
1394 LeaveCriticalSection(&connection_pool_cs);
1395 TRACE("got connection from pool %p\n", Connection);
1399 LeaveCriticalSection(&connection_pool_cs);
1403 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1405 assert(!Connection->server);
1406 EnterCriticalSection(&connection_pool_cs);
1407 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1408 LeaveCriticalSection(&connection_pool_cs);
1412 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1416 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1417 rpcrt4_conn_get_name(OldConnection),
1418 OldConnection->NetworkAddr,
1419 OldConnection->Endpoint, NULL,
1420 OldConnection->AuthInfo, OldConnection->QOS,
1422 if (err == RPC_S_OK)
1423 rpcrt4_conn_handoff(OldConnection, *Connection);
1427 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1429 TRACE("connection: %p\n", Connection);
1431 RPCRT4_CloseConnection(Connection);
1432 RPCRT4_strfree(Connection->Endpoint);
1433 RPCRT4_strfree(Connection->NetworkAddr);
1434 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
1435 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1436 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
1437 HeapFree(GetProcessHeap(), 0, Connection);
1441 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1443 const char *protseq,
1444 const char *networkaddr,
1445 const char *endpoint)
1447 twr_empty_floor_t *protocol_floor;
1448 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1453 return RPC_S_INVALID_RPC_PROTSEQ;
1457 *tower_size = sizeof(*protocol_floor);
1458 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1462 protocol_floor = (twr_empty_floor_t *)tower_data;
1463 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1464 protocol_floor->protid = protseq_ops->epm_protocols[0];
1465 protocol_floor->count_rhs = 0;
1467 tower_data += sizeof(*protocol_floor);
1469 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1471 return EPT_S_NOT_REGISTERED;
1473 *tower_size += sizeof(*protocol_floor);
1478 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1484 const twr_empty_floor_t *protocol_floor;
1485 const twr_empty_floor_t *floor4;
1486 const struct connection_ops *protseq_ops = NULL;
1490 if (tower_size < sizeof(*protocol_floor))
1491 return EPT_S_NOT_REGISTERED;
1493 protocol_floor = (const twr_empty_floor_t *)tower_data;
1494 tower_data += sizeof(*protocol_floor);
1495 tower_size -= sizeof(*protocol_floor);
1496 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1497 (protocol_floor->count_rhs > tower_size))
1498 return EPT_S_NOT_REGISTERED;
1499 tower_data += protocol_floor->count_rhs;
1500 tower_size -= protocol_floor->count_rhs;
1502 floor4 = (const twr_empty_floor_t *)tower_data;
1503 if ((tower_size < sizeof(*floor4)) ||
1504 (floor4->count_lhs != sizeof(floor4->protid)))
1505 return EPT_S_NOT_REGISTERED;
1507 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1508 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1509 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1511 protseq_ops = &conn_protseq_list[i];
1516 return EPT_S_NOT_REGISTERED;
1518 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1520 if ((status == RPC_S_OK) && protseq)
1522 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1523 strcpy(*protseq, protseq_ops->name);
1529 /***********************************************************************
1530 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1532 * Checks if the given protocol sequence is known by the RPC system.
1533 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1536 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1540 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1541 ps, sizeof ps, NULL, NULL);
1542 if (rpcrt4_get_conn_protseq_ops(ps))
1545 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1547 return RPC_S_INVALID_RPC_PROTSEQ;
1550 /***********************************************************************
1551 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1553 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1555 UNICODE_STRING protseqW;
1557 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1559 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1560 RtlFreeUnicodeString(&protseqW);
1563 return RPC_S_OUT_OF_MEMORY;