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);
304 EnterCriticalSection(&protseq->cs);
305 Connection->Next = protseq->conn;
306 protseq->conn = Connection;
307 LeaveCriticalSection(&protseq->cs);
312 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
314 /* because of the way named pipes work, we'll transfer the connected pipe
315 * to the child, then reopen the server binding to continue listening */
317 new_npc->pipe = old_npc->pipe;
318 new_npc->ovl = old_npc->ovl;
320 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
321 old_npc->listening = FALSE;
324 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
328 static const char prefix[] = "\\\\.";
330 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
332 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
333 strcat(strcpy(pname, prefix), old_conn->Endpoint);
334 status = rpcrt4_conn_create_pipe(old_conn, pname);
340 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
344 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
346 TRACE("%s\n", old_conn->Endpoint);
348 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
350 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
351 strcat(strcpy(pname, prefix), old_conn->Endpoint);
352 status = rpcrt4_conn_create_pipe(old_conn, pname);
358 static int rpcrt4_conn_np_read(RpcConnection *Connection,
359 void *buffer, unsigned int count)
361 RpcConnection_np *npc = (RpcConnection_np *) Connection;
364 unsigned int bytes_left = count;
369 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
370 if (!ret || !bytes_read)
372 bytes_left -= bytes_read;
375 return ret ? count : -1;
378 static int rpcrt4_conn_np_write(RpcConnection *Connection,
379 const void *buffer, unsigned int count)
381 RpcConnection_np *npc = (RpcConnection_np *) Connection;
382 const char *buf = buffer;
384 unsigned int bytes_left = count;
389 ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
390 if (!ret || !bytes_written)
392 bytes_left -= bytes_written;
393 buf += bytes_written;
395 return ret ? count : -1;
398 static int rpcrt4_conn_np_close(RpcConnection *Connection)
400 RpcConnection_np *npc = (RpcConnection_np *) Connection;
402 FlushFileBuffers(npc->pipe);
403 CloseHandle(npc->pipe);
406 if (npc->ovl.hEvent) {
407 CloseHandle(npc->ovl.hEvent);
413 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
414 const char *networkaddr,
415 const char *endpoint)
417 twr_empty_floor_t *smb_floor;
418 twr_empty_floor_t *nb_floor;
420 size_t networkaddr_size;
421 size_t endpoint_size;
423 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
425 networkaddr_size = strlen(networkaddr) + 1;
426 endpoint_size = strlen(endpoint) + 1;
427 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
432 smb_floor = (twr_empty_floor_t *)tower_data;
434 tower_data += sizeof(*smb_floor);
436 smb_floor->count_lhs = sizeof(smb_floor->protid);
437 smb_floor->protid = EPM_PROTOCOL_SMB;
438 smb_floor->count_rhs = endpoint_size;
440 memcpy(tower_data, endpoint, endpoint_size);
441 tower_data += endpoint_size;
443 nb_floor = (twr_empty_floor_t *)tower_data;
445 tower_data += sizeof(*nb_floor);
447 nb_floor->count_lhs = sizeof(nb_floor->protid);
448 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
449 nb_floor->count_rhs = networkaddr_size;
451 memcpy(tower_data, networkaddr, networkaddr_size);
452 tower_data += networkaddr_size;
457 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
462 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
463 const twr_empty_floor_t *nb_floor;
465 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
467 if (tower_size < sizeof(*smb_floor))
468 return EPT_S_NOT_REGISTERED;
470 tower_data += sizeof(*smb_floor);
471 tower_size -= sizeof(*smb_floor);
473 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
474 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
475 (smb_floor->count_rhs > tower_size))
476 return EPT_S_NOT_REGISTERED;
480 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
482 return RPC_S_OUT_OF_RESOURCES;
483 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
485 tower_data += smb_floor->count_rhs;
486 tower_size -= smb_floor->count_rhs;
488 if (tower_size < sizeof(*nb_floor))
489 return EPT_S_NOT_REGISTERED;
491 nb_floor = (const twr_empty_floor_t *)tower_data;
493 tower_data += sizeof(*nb_floor);
494 tower_size -= sizeof(*nb_floor);
496 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
497 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
498 (nb_floor->count_rhs > tower_size))
499 return EPT_S_NOT_REGISTERED;
503 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
508 I_RpcFree(*endpoint);
511 return RPC_S_OUT_OF_RESOURCES;
513 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
519 typedef struct _RpcServerProtseq_np
521 RpcServerProtseq common;
523 } RpcServerProtseq_np;
525 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
527 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
529 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
533 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
535 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
536 SetEvent(npps->mgr_event);
539 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
541 HANDLE *objs = prev_array;
542 RpcConnection_np *conn;
543 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
545 EnterCriticalSection(&protseq->cs);
547 /* open and count connections */
549 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
551 rpcrt4_conn_listen_pipe(conn);
552 if (conn->ovl.hEvent)
554 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
557 /* make array of connections */
559 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
561 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
564 ERR("couldn't allocate objs\n");
565 LeaveCriticalSection(&protseq->cs);
569 objs[0] = npps->mgr_event;
571 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
573 if ((objs[*count] = conn->ovl.hEvent))
575 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
577 LeaveCriticalSection(&protseq->cs);
581 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
583 HeapFree(GetProcessHeap(), 0, array);
586 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
589 HANDLE *objs = wait_array;
591 RpcConnection *cconn;
592 RpcConnection_np *conn;
597 res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
598 if (res == WAIT_OBJECT_0)
600 else if (res == WAIT_FAILED)
602 ERR("wait failed with error %d\n", GetLastError());
607 b_handle = objs[res - WAIT_OBJECT_0];
608 /* find which connection got a RPC */
609 EnterCriticalSection(&protseq->cs);
610 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
612 if (b_handle == conn->ovl.hEvent) break;
613 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
617 RPCRT4_SpawnConnection(&cconn, &conn->common);
619 ERR("failed to locate connection for handle %p\n", b_handle);
620 LeaveCriticalSection(&protseq->cs);
623 RPCRT4_new_client(cconn);
630 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
631 const char *networkaddr,
632 const char *endpoint)
634 twr_empty_floor_t *pipe_floor;
636 size_t endpoint_size;
638 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
640 endpoint_size = strlen(networkaddr) + 1;
641 size = sizeof(*pipe_floor) + endpoint_size;
646 pipe_floor = (twr_empty_floor_t *)tower_data;
648 tower_data += sizeof(*pipe_floor);
650 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
651 pipe_floor->protid = EPM_PROTOCOL_SMB;
652 pipe_floor->count_rhs = endpoint_size;
654 memcpy(tower_data, endpoint, endpoint_size);
655 tower_data += endpoint_size;
660 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
665 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
667 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
672 if (tower_size < sizeof(*pipe_floor))
673 return EPT_S_NOT_REGISTERED;
675 tower_data += sizeof(*pipe_floor);
676 tower_size -= sizeof(*pipe_floor);
678 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
679 (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
680 (pipe_floor->count_rhs > tower_size))
681 return EPT_S_NOT_REGISTERED;
685 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
687 return RPC_S_OUT_OF_RESOURCES;
688 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
694 /**** ncacn_ip_tcp support ****/
696 typedef struct _RpcConnection_tcp
698 RpcConnection common;
702 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
704 RpcConnection_tcp *tcpc;
705 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
709 return &tcpc->common;
712 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
714 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
718 struct addrinfo *ai_cur;
719 struct addrinfo hints;
721 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
723 if (tcpc->sock != -1)
727 hints.ai_family = PF_UNSPEC;
728 hints.ai_socktype = SOCK_STREAM;
729 hints.ai_protocol = IPPROTO_TCP;
730 hints.ai_addrlen = 0;
731 hints.ai_addr = NULL;
732 hints.ai_canonname = NULL;
733 hints.ai_next = NULL;
735 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
738 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
739 Connection->Endpoint, gai_strerror(ret));
740 return RPC_S_SERVER_UNAVAILABLE;
743 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
749 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
750 host, sizeof(host), service, sizeof(service),
751 NI_NUMERICHOST | NI_NUMERICSERV);
752 TRACE("trying %s:%s\n", host, service);
755 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
758 WARN("socket() failed: %s\n", strerror(errno));
762 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
764 WARN("connect() failed: %s\n", strerror(errno));
771 TRACE("connected\n");
776 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
777 return RPC_S_SERVER_UNAVAILABLE;
780 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
782 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
786 struct addrinfo *ai_cur;
787 struct addrinfo hints;
788 RpcConnection *first_connection = NULL;
790 TRACE("(%p, %s)\n", protseq, endpoint);
792 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
793 hints.ai_family = PF_UNSPEC;
794 hints.ai_socktype = SOCK_STREAM;
795 hints.ai_protocol = IPPROTO_TCP;
796 hints.ai_addrlen = 0;
797 hints.ai_addr = NULL;
798 hints.ai_canonname = NULL;
799 hints.ai_next = NULL;
801 ret = getaddrinfo(NULL, endpoint, &hints, &ai);
804 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
806 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
807 return RPC_S_INVALID_ENDPOINT_FORMAT;
808 return RPC_S_CANT_CREATE_ENDPOINT;
811 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
813 RpcConnection_tcp *tcpc;
814 RPC_STATUS create_status;
820 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
821 host, sizeof(host), service, sizeof(service),
822 NI_NUMERICHOST | NI_NUMERICSERV);
823 TRACE("trying %s:%s\n", host, service);
826 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
829 WARN("socket() failed: %s\n", strerror(errno));
830 status = RPC_S_CANT_CREATE_ENDPOINT;
834 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
837 WARN("bind failed: %s\n", strerror(errno));
839 if (errno == EADDRINUSE)
840 status = RPC_S_DUPLICATE_ENDPOINT;
842 status = RPC_S_CANT_CREATE_ENDPOINT;
845 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
846 protseq->Protseq, NULL,
847 endpoint, NULL, NULL, NULL,
849 if (create_status != RPC_S_OK)
852 status = create_status;
857 ret = listen(sock, protseq->MaxCalls);
860 WARN("listen failed: %s\n", strerror(errno));
861 RPCRT4_DestroyConnection(&tcpc->common);
862 status = RPC_S_OUT_OF_RESOURCES;
865 /* need a non-blocking socket, otherwise accept() has a potential
866 * race-condition (poll() says it is readable, connection drops,
867 * and accept() blocks until the next connection comes...)
869 ret = fcntl(sock, F_SETFL, O_NONBLOCK);
872 WARN("couldn't make socket non-blocking, error %d\n", ret);
873 RPCRT4_DestroyConnection(&tcpc->common);
874 status = RPC_S_OUT_OF_RESOURCES;
878 tcpc->common.Next = first_connection;
879 first_connection = &tcpc->common;
884 /* if at least one connection was created for an endpoint then
886 if (first_connection)
890 /* find last element in list */
891 for (conn = first_connection; conn->Next; conn = conn->Next)
894 EnterCriticalSection(&protseq->cs);
895 conn->Next = protseq->conn;
896 protseq->conn = first_connection;
897 LeaveCriticalSection(&protseq->cs);
899 TRACE("listening on %s\n", endpoint);
903 ERR("couldn't listen on port %s\n", endpoint);
907 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
910 struct sockaddr_in address;
912 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
913 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
915 addrsize = sizeof(address);
916 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
919 ERR("Failed to accept a TCP connection: error %d\n", ret);
920 return RPC_S_OUT_OF_RESOURCES;
922 /* reset to blocking behaviour */
923 fcntl(ret, F_SETFL, 0);
925 TRACE("Accepted a new TCP connection\n");
929 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
930 void *buffer, unsigned int count)
932 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
933 int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
934 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
938 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
939 const void *buffer, unsigned int count)
941 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
942 int r = write(tcpc->sock, buffer, count);
943 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
947 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
949 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
951 TRACE("%d\n", tcpc->sock);
953 if (tcpc->sock != -1)
959 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
960 const char *networkaddr,
961 const char *endpoint)
963 twr_tcp_floor_t *tcp_floor;
964 twr_ipv4_floor_t *ipv4_floor;
966 struct addrinfo hints;
968 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
970 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
975 tcp_floor = (twr_tcp_floor_t *)tower_data;
976 tower_data += sizeof(*tcp_floor);
978 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
980 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
981 tcp_floor->protid = EPM_PROTOCOL_TCP;
982 tcp_floor->count_rhs = sizeof(tcp_floor->port);
984 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
985 ipv4_floor->protid = EPM_PROTOCOL_IP;
986 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
988 hints.ai_flags = AI_NUMERICHOST;
989 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
990 hints.ai_family = PF_INET;
991 hints.ai_socktype = SOCK_STREAM;
992 hints.ai_protocol = IPPROTO_TCP;
993 hints.ai_addrlen = 0;
994 hints.ai_addr = NULL;
995 hints.ai_canonname = NULL;
996 hints.ai_next = NULL;
998 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
1001 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
1004 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1009 if (ai->ai_family == PF_INET)
1011 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1012 tcp_floor->port = sin->sin_port;
1013 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1017 ERR("unexpected protocol family %d\n", ai->ai_family);
1026 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1031 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1032 const twr_ipv4_floor_t *ipv4_floor;
1033 struct in_addr in_addr;
1035 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1037 if (tower_size < sizeof(*tcp_floor))
1038 return EPT_S_NOT_REGISTERED;
1040 tower_data += sizeof(*tcp_floor);
1041 tower_size -= sizeof(*tcp_floor);
1043 if (tower_size < sizeof(*ipv4_floor))
1044 return EPT_S_NOT_REGISTERED;
1046 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1048 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1049 (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1050 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1051 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1052 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1053 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1054 return EPT_S_NOT_REGISTERED;
1058 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1060 return RPC_S_OUT_OF_RESOURCES;
1061 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1066 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1071 I_RpcFree(*endpoint);
1074 return RPC_S_OUT_OF_RESOURCES;
1076 in_addr.s_addr = ipv4_floor->ipv4addr;
1077 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1079 ERR("inet_ntop: %s\n", strerror(errno));
1080 I_RpcFree(*networkaddr);
1081 *networkaddr = NULL;
1084 I_RpcFree(*endpoint);
1087 return EPT_S_NOT_REGISTERED;
1094 typedef struct _RpcServerProtseq_sock
1096 RpcServerProtseq common;
1099 } RpcServerProtseq_sock;
1101 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1103 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1107 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1109 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1110 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1111 ps->mgr_event_rcv = fds[0];
1112 ps->mgr_event_snd = fds[1];
1116 ERR("socketpair failed with error %s\n", strerror(errno));
1117 HeapFree(GetProcessHeap(), 0, ps);
1124 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1126 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1128 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1131 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1133 struct pollfd *poll_info = prev_array;
1134 RpcConnection_tcp *conn;
1135 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1137 EnterCriticalSection(&protseq->cs);
1139 /* open and count connections */
1141 conn = (RpcConnection_tcp *)protseq->conn;
1143 if (conn->sock != -1)
1145 conn = (RpcConnection_tcp *)conn->common.Next;
1148 /* make array of connections */
1150 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1152 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1155 ERR("couldn't allocate poll_info\n");
1156 LeaveCriticalSection(&protseq->cs);
1160 poll_info[0].fd = sockps->mgr_event_rcv;
1161 poll_info[0].events = POLLIN;
1163 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1165 if (conn->sock != -1)
1167 poll_info[*count].fd = conn->sock;
1168 poll_info[*count].events = POLLIN;
1171 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1173 LeaveCriticalSection(&protseq->cs);
1177 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1179 HeapFree(GetProcessHeap(), 0, array);
1182 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1184 struct pollfd *poll_info = wait_array;
1186 RpcConnection *cconn;
1187 RpcConnection_tcp *conn;
1192 ret = poll(poll_info, count, -1);
1195 ERR("poll failed with error %d\n", ret);
1199 for (i = 0; i < count; i++)
1200 if (poll_info[i].revents & POLLIN)
1202 /* RPC server event */
1206 read(poll_info[0].fd, &dummy, sizeof(dummy));
1210 /* find which connection got a RPC */
1211 EnterCriticalSection(&protseq->cs);
1212 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1214 if (poll_info[i].fd == conn->sock) break;
1215 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1219 RPCRT4_SpawnConnection(&cconn, &conn->common);
1221 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1222 LeaveCriticalSection(&protseq->cs);
1224 RPCRT4_new_client(cconn);
1232 static const struct connection_ops conn_protseq_list[] = {
1234 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1235 rpcrt4_conn_np_alloc,
1236 rpcrt4_ncacn_np_open,
1237 rpcrt4_ncacn_np_handoff,
1238 rpcrt4_conn_np_read,
1239 rpcrt4_conn_np_write,
1240 rpcrt4_conn_np_close,
1241 rpcrt4_ncacn_np_get_top_of_tower,
1242 rpcrt4_ncacn_np_parse_top_of_tower,
1245 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1246 rpcrt4_conn_np_alloc,
1247 rpcrt4_ncalrpc_open,
1248 rpcrt4_ncalrpc_handoff,
1249 rpcrt4_conn_np_read,
1250 rpcrt4_conn_np_write,
1251 rpcrt4_conn_np_close,
1252 rpcrt4_ncalrpc_get_top_of_tower,
1253 rpcrt4_ncalrpc_parse_top_of_tower,
1256 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1257 rpcrt4_conn_tcp_alloc,
1258 rpcrt4_ncacn_ip_tcp_open,
1259 rpcrt4_conn_tcp_handoff,
1260 rpcrt4_conn_tcp_read,
1261 rpcrt4_conn_tcp_write,
1262 rpcrt4_conn_tcp_close,
1263 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1264 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1269 static const struct protseq_ops protseq_list[] =
1273 rpcrt4_protseq_np_alloc,
1274 rpcrt4_protseq_np_signal_state_changed,
1275 rpcrt4_protseq_np_get_wait_array,
1276 rpcrt4_protseq_np_free_wait_array,
1277 rpcrt4_protseq_np_wait_for_new_connection,
1278 rpcrt4_protseq_ncacn_np_open_endpoint,
1282 rpcrt4_protseq_np_alloc,
1283 rpcrt4_protseq_np_signal_state_changed,
1284 rpcrt4_protseq_np_get_wait_array,
1285 rpcrt4_protseq_np_free_wait_array,
1286 rpcrt4_protseq_np_wait_for_new_connection,
1287 rpcrt4_protseq_ncalrpc_open_endpoint,
1291 rpcrt4_protseq_sock_alloc,
1292 rpcrt4_protseq_sock_signal_state_changed,
1293 rpcrt4_protseq_sock_get_wait_array,
1294 rpcrt4_protseq_sock_free_wait_array,
1295 rpcrt4_protseq_sock_wait_for_new_connection,
1296 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1300 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1302 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1305 for(i=0; i<ARRAYSIZE(protseq_list); i++)
1306 if (!strcmp(protseq_list[i].name, protseq))
1307 return &protseq_list[i];
1311 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1314 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1315 if (!strcmp(conn_protseq_list[i].name, protseq))
1316 return &conn_protseq_list[i];
1320 /**** interface to rest of code ****/
1322 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1324 TRACE("(Connection == ^%p)\n", Connection);
1326 assert(!Connection->server);
1327 return Connection->ops->open_connection_client(Connection);
1330 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1332 TRACE("(Connection == ^%p)\n", Connection);
1333 if (SecIsValidHandle(&Connection->ctx))
1335 DeleteSecurityContext(&Connection->ctx);
1336 SecInvalidateHandle(&Connection->ctx);
1338 rpcrt4_conn_close(Connection);
1342 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1343 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1344 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS,
1345 RpcBinding* Binding)
1347 const struct connection_ops *ops;
1348 RpcConnection* NewConnection;
1350 ops = rpcrt4_get_conn_protseq_ops(Protseq);
1353 FIXME("not supported for protseq %s\n", Protseq);
1354 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1357 NewConnection = ops->alloc();
1358 NewConnection->Next = NULL;
1359 NewConnection->server = server;
1360 NewConnection->ops = ops;
1361 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1362 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1363 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1364 NewConnection->Used = Binding;
1365 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1366 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1367 NewConnection->NextCallId = 1;
1369 SecInvalidateHandle(&NewConnection->ctx);
1370 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1371 NewConnection->AuthInfo = AuthInfo;
1372 if (QOS) RpcQualityOfService_AddRef(QOS);
1373 NewConnection->QOS = QOS;
1374 list_init(&NewConnection->conn_pool_entry);
1376 TRACE("connection: %p\n", NewConnection);
1377 *Connection = NewConnection;
1382 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1383 const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1384 LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS)
1386 RpcConnection *Connection;
1387 /* try to find a compatible connection from the connection pool */
1388 EnterCriticalSection(&connection_pool_cs);
1389 LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1390 if ((Connection->AuthInfo == AuthInfo) &&
1391 (Connection->QOS == QOS) &&
1392 !memcmp(&Connection->ActiveInterface, InterfaceId,
1393 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1394 !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1395 !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1396 !strcmp(Connection->Endpoint, Endpoint))
1398 list_remove(&Connection->conn_pool_entry);
1399 LeaveCriticalSection(&connection_pool_cs);
1400 TRACE("got connection from pool %p\n", Connection);
1404 LeaveCriticalSection(&connection_pool_cs);
1408 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1410 assert(!Connection->server);
1411 EnterCriticalSection(&connection_pool_cs);
1412 list_add_head(&connection_pool, &Connection->conn_pool_entry);
1413 LeaveCriticalSection(&connection_pool_cs);
1417 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1421 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1422 rpcrt4_conn_get_name(OldConnection),
1423 OldConnection->NetworkAddr,
1424 OldConnection->Endpoint, NULL,
1425 OldConnection->AuthInfo, OldConnection->QOS,
1427 if (err == RPC_S_OK)
1428 rpcrt4_conn_handoff(OldConnection, *Connection);
1432 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1434 TRACE("connection: %p\n", Connection);
1436 RPCRT4_CloseConnection(Connection);
1437 RPCRT4_strfree(Connection->Endpoint);
1438 RPCRT4_strfree(Connection->NetworkAddr);
1439 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
1440 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1441 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
1442 HeapFree(GetProcessHeap(), 0, Connection);
1446 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1448 const char *protseq,
1449 const char *networkaddr,
1450 const char *endpoint)
1452 twr_empty_floor_t *protocol_floor;
1453 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1458 return RPC_S_INVALID_RPC_PROTSEQ;
1462 *tower_size = sizeof(*protocol_floor);
1463 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1467 protocol_floor = (twr_empty_floor_t *)tower_data;
1468 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1469 protocol_floor->protid = protseq_ops->epm_protocols[0];
1470 protocol_floor->count_rhs = 0;
1472 tower_data += sizeof(*protocol_floor);
1474 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1476 return EPT_S_NOT_REGISTERED;
1478 *tower_size += sizeof(*protocol_floor);
1483 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1489 const twr_empty_floor_t *protocol_floor;
1490 const twr_empty_floor_t *floor4;
1491 const struct connection_ops *protseq_ops = NULL;
1495 if (tower_size < sizeof(*protocol_floor))
1496 return EPT_S_NOT_REGISTERED;
1498 protocol_floor = (const twr_empty_floor_t *)tower_data;
1499 tower_data += sizeof(*protocol_floor);
1500 tower_size -= sizeof(*protocol_floor);
1501 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1502 (protocol_floor->count_rhs > tower_size))
1503 return EPT_S_NOT_REGISTERED;
1504 tower_data += protocol_floor->count_rhs;
1505 tower_size -= protocol_floor->count_rhs;
1507 floor4 = (const twr_empty_floor_t *)tower_data;
1508 if ((tower_size < sizeof(*floor4)) ||
1509 (floor4->count_lhs != sizeof(floor4->protid)))
1510 return EPT_S_NOT_REGISTERED;
1512 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1513 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1514 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1516 protseq_ops = &conn_protseq_list[i];
1521 return EPT_S_NOT_REGISTERED;
1523 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1525 if ((status == RPC_S_OK) && protseq)
1527 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1528 strcpy(*protseq, protseq_ops->name);
1534 /***********************************************************************
1535 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1537 * Checks if the given protocol sequence is known by the RPC system.
1538 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1541 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1545 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1546 ps, sizeof ps, NULL, NULL);
1547 if (rpcrt4_get_conn_protseq_ops(ps))
1550 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1552 return RPC_S_INVALID_RPC_PROTSEQ;
1555 /***********************************************************************
1556 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1558 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1560 UNICODE_STRING protseqW;
1562 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1564 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1565 RtlFreeUnicodeString(&protseqW);
1568 return RPC_S_OUT_OF_MEMORY;