rpcrt4: Convert the named pipe server code to look directly into the
[wine] / dlls / rpcrt4 / rpc_transport.c
1 /*
2  * RPC transport layer
3  *
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
9  *
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.
14  *
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.
19  *
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
23  *
24  */
25
26 #include "config.h"
27
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
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_ARPA_INET_H
47 # include <arpa/inet.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef HAVE_SYS_POLL_H
53 #include <sys/poll.h>
54 #endif
55
56 #include "windef.h"
57 #include "winbase.h"
58 #include "winnls.h"
59 #include "winerror.h"
60 #include "winreg.h"
61 #include "winternl.h"
62 #include "wine/unicode.h"
63
64 #include "rpc.h"
65 #include "rpcndr.h"
66
67 #include "wine/debug.h"
68
69 #include "rpc_binding.h"
70 #include "rpc_message.h"
71 #include "rpc_server.h"
72 #include "epm_towers.h"
73
74 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
75
76 static CRITICAL_SECTION connection_pool_cs;
77 static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
78 {
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") }
82 };
83 static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
84
85 static struct list connection_pool = LIST_INIT(connection_pool);
86
87 /**** ncacn_np support ****/
88
89 typedef struct _RpcConnection_np
90 {
91   RpcConnection common;
92   HANDLE pipe, thread;
93   OVERLAPPED ovl;
94 } RpcConnection_np;
95
96 static RpcConnection *rpcrt4_conn_np_alloc(void)
97 {
98   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
99   if (npc)
100   {
101     npc->pipe = NULL;
102     npc->thread = NULL;
103     memset(&npc->ovl, 0, sizeof(npc->ovl));
104   }
105   return &npc->common;
106 }
107
108 static RPC_STATUS rpcrt4_connect_pipe(RpcConnection *Connection, LPCSTR pname)
109 {
110   RpcConnection_np *npc = (RpcConnection_np *) Connection;
111   TRACE("listening on %s\n", pname);
112
113   npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
114                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
115                                PIPE_UNLIMITED_INSTANCES,
116                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
117   if (npc->pipe == INVALID_HANDLE_VALUE) {
118     WARN("CreateNamedPipe failed with error %ld\n", GetLastError());
119     return RPC_S_SERVER_UNAVAILABLE;
120   }
121
122   memset(&npc->ovl, 0, sizeof(npc->ovl));
123   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
124   if (ConnectNamedPipe(npc->pipe, &npc->ovl))
125      return RPC_S_OK;
126
127   WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
128   if (GetLastError() == ERROR_PIPE_CONNECTED) {
129     SetEvent(npc->ovl.hEvent);
130     return RPC_S_OK;
131   }
132   if (GetLastError() == ERROR_IO_PENDING) {
133     /* FIXME: looks like we need to GetOverlappedResult here? */
134     return RPC_S_OK;
135   }
136   return RPC_S_SERVER_UNAVAILABLE;
137 }
138
139 static RPC_STATUS rpcrt4_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
140 {
141   RpcConnection_np *npc = (RpcConnection_np *) Connection;
142   HANDLE pipe;
143   DWORD err, dwMode;
144
145   TRACE("connecting to %s\n", pname);
146
147   while (TRUE) {
148     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
149                        OPEN_EXISTING, 0, 0);
150     if (pipe != INVALID_HANDLE_VALUE) break;
151     err = GetLastError();
152     if (err == ERROR_PIPE_BUSY) {
153       TRACE("connection failed, error=%lx\n", err);
154       return RPC_S_SERVER_TOO_BUSY;
155     }
156     if (!wait)
157       return RPC_S_SERVER_UNAVAILABLE;
158     if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
159       err = GetLastError();
160       WARN("connection failed, error=%lx\n", err);
161       return RPC_S_SERVER_UNAVAILABLE;
162     }
163   }
164
165   /* success */
166   memset(&npc->ovl, 0, sizeof(npc->ovl));
167   /* pipe is connected; change to message-read mode. */
168   dwMode = PIPE_READMODE_MESSAGE;
169   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
170   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
171   npc->pipe = pipe;
172
173   return RPC_S_OK;
174 }
175
176 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
177 {
178   RpcConnection_np *npc = (RpcConnection_np *) Connection;
179   static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
180   RPC_STATUS r;
181   LPSTR pname;
182
183   /* already connected? */
184   if (npc->pipe)
185     return RPC_S_OK;
186
187   /* protseq=ncalrpc: supposed to use NT LPC ports,
188    * but we'll implement it with named pipes for now */
189   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
190   strcat(strcpy(pname, prefix), Connection->Endpoint);
191
192   if (Connection->server)
193     r = rpcrt4_connect_pipe(Connection, pname);
194   else
195     r = rpcrt4_open_pipe(Connection, pname, TRUE);
196   I_RpcFree(pname);
197
198   return r;
199 }
200
201 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
202 {
203   RpcConnection_np *npc = (RpcConnection_np *) Connection;
204   static LPCSTR prefix = "\\\\.";
205   RPC_STATUS r;
206   LPSTR pname;
207
208   /* already connected? */
209   if (npc->pipe)
210     return RPC_S_OK;
211
212   /* protseq=ncacn_np: named pipes */
213   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
214   strcat(strcpy(pname, prefix), Connection->Endpoint);
215   if (Connection->server)
216     r = rpcrt4_connect_pipe(Connection, pname);
217   else
218     r = rpcrt4_open_pipe(Connection, pname, FALSE);
219   I_RpcFree(pname);
220
221   return r;
222 }
223
224 static RPC_STATUS rpcrt4_conn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
225 {
226   RpcConnection_np *old_npc = (RpcConnection_np *) old_conn;
227   RpcConnection_np *new_npc = (RpcConnection_np *) new_conn;
228   /* because of the way named pipes work, we'll transfer the connected pipe
229    * to the child, then reopen the server binding to continue listening */
230
231   new_npc->pipe = old_npc->pipe;
232   new_npc->ovl = old_npc->ovl;
233   old_npc->pipe = 0;
234   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
235   return RPCRT4_OpenConnection(old_conn);
236 }
237
238 static int rpcrt4_conn_np_read(RpcConnection *Connection,
239                         void *buffer, unsigned int count)
240 {
241   RpcConnection_np *npc = (RpcConnection_np *) Connection;
242   DWORD dwRead = 0;
243   if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
244       (GetLastError() != ERROR_MORE_DATA))
245     return -1;
246   return dwRead;
247 }
248
249 static int rpcrt4_conn_np_write(RpcConnection *Connection,
250                              const void *buffer, unsigned int count)
251 {
252   RpcConnection_np *npc = (RpcConnection_np *) Connection;
253   DWORD dwWritten = 0;
254   if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
255     return -1;
256   return dwWritten;
257 }
258
259 static int rpcrt4_conn_np_close(RpcConnection *Connection)
260 {
261   RpcConnection_np *npc = (RpcConnection_np *) Connection;
262   if (npc->pipe) {
263     FlushFileBuffers(npc->pipe);
264     CloseHandle(npc->pipe);
265     npc->pipe = 0;
266   }
267   if (npc->ovl.hEvent) {
268     CloseHandle(npc->ovl.hEvent);
269     npc->ovl.hEvent = 0;
270   }
271   return 0;
272 }
273
274 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
275                                                const char *networkaddr,
276                                                const char *endpoint)
277 {
278     twr_empty_floor_t *smb_floor;
279     twr_empty_floor_t *nb_floor;
280     size_t size;
281     size_t networkaddr_size;
282     size_t endpoint_size;
283
284     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
285
286     networkaddr_size = strlen(networkaddr) + 1;
287     endpoint_size = strlen(endpoint) + 1;
288     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
289
290     if (!tower_data)
291         return size;
292
293     smb_floor = (twr_empty_floor_t *)tower_data;
294
295     tower_data += sizeof(*smb_floor);
296
297     smb_floor->count_lhs = sizeof(smb_floor->protid);
298     smb_floor->protid = EPM_PROTOCOL_SMB;
299     smb_floor->count_rhs = endpoint_size;
300
301     memcpy(tower_data, endpoint, endpoint_size);
302     tower_data += endpoint_size;
303
304     nb_floor = (twr_empty_floor_t *)tower_data;
305
306     tower_data += sizeof(*nb_floor);
307
308     nb_floor->count_lhs = sizeof(nb_floor->protid);
309     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
310     nb_floor->count_rhs = networkaddr_size;
311
312     memcpy(tower_data, networkaddr, networkaddr_size);
313     tower_data += networkaddr_size;
314
315     return size;
316 }
317
318 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
319                                                      size_t tower_size,
320                                                      char **networkaddr,
321                                                      char **endpoint)
322 {
323     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
324     const twr_empty_floor_t *nb_floor;
325
326     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
327
328     if (tower_size < sizeof(*smb_floor))
329         return EPT_S_NOT_REGISTERED;
330
331     tower_data += sizeof(*smb_floor);
332     tower_size -= sizeof(*smb_floor);
333
334     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
335         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
336         (smb_floor->count_rhs > tower_size))
337         return EPT_S_NOT_REGISTERED;
338
339     if (endpoint)
340     {
341         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
342         if (!*endpoint)
343             return RPC_S_OUT_OF_RESOURCES;
344         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
345     }
346     tower_data += smb_floor->count_rhs;
347     tower_size -= smb_floor->count_rhs;
348
349     if (tower_size < sizeof(*nb_floor))
350         return EPT_S_NOT_REGISTERED;
351
352     nb_floor = (const twr_empty_floor_t *)tower_data;
353
354     tower_data += sizeof(*nb_floor);
355     tower_size -= sizeof(*nb_floor);
356
357     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
358         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
359         (nb_floor->count_rhs > tower_size))
360         return EPT_S_NOT_REGISTERED;
361
362     if (networkaddr)
363     {
364         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
365         if (!*networkaddr)
366         {
367             if (endpoint)
368             {
369                 I_RpcFree(*endpoint);
370                 *endpoint = NULL;
371             }
372             return RPC_S_OUT_OF_RESOURCES;
373         }
374         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
375     }
376
377     return RPC_S_OK;
378 }
379
380 typedef struct _RpcServerProtseq_np
381 {
382     RpcServerProtseq common;
383     HANDLE mgr_event;
384 } RpcServerProtseq_np;
385
386 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
387 {
388     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
389     if (ps)
390         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
391     return &ps->common;
392 }
393
394 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
395 {
396     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
397     SetEvent(npps->mgr_event);
398 }
399
400 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
401 {
402     HANDLE *objs = prev_array;
403     RpcConnection_np *conn;
404     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
405     
406     EnterCriticalSection(&protseq->cs);
407     
408     /* open and count connections */
409     *count = 1;
410     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
411     while (conn) {
412         RPCRT4_OpenConnection(&conn->common);
413         if (conn->ovl.hEvent)
414             (*count)++;
415         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
416     }
417     
418     /* make array of connections */
419     if (objs)
420         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
421     else
422         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
423     if (!objs)
424     {
425         ERR("couldn't allocate objs\n");
426         LeaveCriticalSection(&protseq->cs);
427         return NULL;
428     }
429     
430     objs[0] = npps->mgr_event;
431     *count = 1;
432     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
433     while (conn) {
434         if ((objs[*count] = conn->ovl.hEvent))
435             (*count)++;
436         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
437     }
438     LeaveCriticalSection(&protseq->cs);
439     return objs;
440 }
441
442 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
443 {
444     HeapFree(GetProcessHeap(), 0, array);
445 }
446
447 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
448 {
449     HANDLE b_handle;
450     HANDLE *objs = wait_array;
451     DWORD res;
452     RpcConnection *cconn;
453     RpcConnection_np *conn;
454     
455     if (!objs)
456         return -1;
457     
458     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
459     if (res == WAIT_OBJECT_0)
460         return 0;
461     else if (res == WAIT_FAILED)
462     {
463         ERR("wait failed with error %ld\n", GetLastError());
464         return -1;
465     }
466     else
467     {
468         b_handle = objs[res - WAIT_OBJECT_0];
469         /* find which connection got a RPC */
470         EnterCriticalSection(&protseq->cs);
471         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
472         while (conn) {
473             if (b_handle == conn->ovl.hEvent) break;
474             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
475         }
476         cconn = NULL;
477         if (conn)
478             RPCRT4_SpawnConnection(&cconn, &conn->common);
479         else
480             ERR("failed to locate connection for handle %p\n", b_handle);
481         LeaveCriticalSection(&protseq->cs);
482         if (cconn)
483         {
484             RPCRT4_new_client(cconn);
485             return 1;
486         }
487         else return -1;
488     }
489 }
490
491 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
492                                               const char *networkaddr,
493                                               const char *endpoint)
494 {
495     twr_empty_floor_t *pipe_floor;
496     size_t size;
497     size_t endpoint_size;
498
499     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
500
501     endpoint_size = strlen(networkaddr) + 1;
502     size = sizeof(*pipe_floor) + endpoint_size;
503
504     if (!tower_data)
505         return size;
506
507     pipe_floor = (twr_empty_floor_t *)tower_data;
508
509     tower_data += sizeof(*pipe_floor);
510
511     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
512     pipe_floor->protid = EPM_PROTOCOL_SMB;
513     pipe_floor->count_rhs = endpoint_size;
514
515     memcpy(tower_data, endpoint, endpoint_size);
516     tower_data += endpoint_size;
517
518     return size;
519 }
520
521 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
522                                                     size_t tower_size,
523                                                     char **networkaddr,
524                                                     char **endpoint)
525 {
526     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
527
528     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
529
530     *networkaddr = NULL;
531     *endpoint = NULL;
532
533     if (tower_size < sizeof(*pipe_floor))
534         return EPT_S_NOT_REGISTERED;
535
536     tower_data += sizeof(*pipe_floor);
537     tower_size -= sizeof(*pipe_floor);
538
539     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
540         (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
541         (pipe_floor->count_rhs > tower_size))
542         return EPT_S_NOT_REGISTERED;
543
544     if (endpoint)
545     {
546         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
547         if (!*endpoint)
548             return RPC_S_OUT_OF_RESOURCES;
549         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
550     }
551
552     return RPC_S_OK;
553 }
554
555 /**** ncacn_ip_tcp support ****/
556
557 typedef struct _RpcConnection_tcp
558 {
559   RpcConnection common;
560   int sock;
561 } RpcConnection_tcp;
562
563 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
564 {
565   RpcConnection_tcp *tcpc;
566   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
567   if (tcpc == NULL)
568     return NULL;
569   tcpc->sock = -1;
570   return &tcpc->common;
571 }
572
573 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
574 {
575   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
576   int sock;
577   int ret;
578   struct addrinfo *ai;
579   struct addrinfo *ai_cur;
580   struct addrinfo hints;
581
582   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
583
584   if (tcpc->sock != -1)
585     return RPC_S_OK;
586
587   hints.ai_flags          = 0;
588   hints.ai_family         = PF_UNSPEC;
589   hints.ai_socktype       = SOCK_STREAM;
590   hints.ai_protocol       = IPPROTO_TCP;
591   hints.ai_addrlen        = 0;
592   hints.ai_addr           = NULL;
593   hints.ai_canonname      = NULL;
594   hints.ai_next           = NULL;
595
596   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
597   if (ret)
598   {
599     ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
600     return RPC_S_SERVER_UNAVAILABLE;
601   }
602
603   for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
604   {
605     if (TRACE_ON(rpc))
606     {
607       char host[256];
608       char service[256];
609       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
610         host, sizeof(host), service, sizeof(service),
611         NI_NUMERICHOST | NI_NUMERICSERV);
612       TRACE("trying %s:%s\n", host, service);
613     }
614
615     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
616     if (sock < 0)
617     {
618       WARN("socket() failed\n");
619       continue;
620     }
621
622     if (Connection->server)
623     {
624       ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
625       if (ret < 0)
626       {
627         WARN("bind failed, error %d\n", ret);
628         close(sock);
629         continue;
630       }
631       ret = listen(sock, 10);
632       if (ret < 0)
633       {
634         WARN("listen failed, error %d\n", ret);
635         close(sock);
636         continue;
637       }
638       /* need a non-blocking socket, otherwise accept() has a potential
639        * race-condition (poll() says it is readable, connection drops,
640        * and accept() blocks until the next connection comes...)
641        */
642       ret = fcntl(sock, F_SETFL, O_NONBLOCK);
643       if (ret < 0)
644       {
645         WARN("couldn't make socket non-blocking, error %d\n", ret);
646         close(sock);
647         continue;
648       }
649       tcpc->sock = sock;
650     }
651     else /* it's a client */
652     {
653       if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
654       {
655         WARN("connect() failed\n");
656         close(sock);
657         continue;
658       }
659       tcpc->sock = sock;
660     }
661
662     freeaddrinfo(ai);
663     TRACE("connected\n");
664     return RPC_S_OK;
665   }
666
667   freeaddrinfo(ai);
668   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
669   return RPC_S_SERVER_UNAVAILABLE;
670 }
671
672 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
673 {
674   int ret;
675   struct sockaddr_in address;
676   socklen_t addrsize;
677   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
678   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
679
680   addrsize = sizeof(address);
681   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
682   if (ret < 0)
683   {
684     ERR("Failed to accept a TCP connection: error %d\n", ret);
685     return RPC_S_SERVER_UNAVAILABLE;
686   }
687   client->sock = ret;
688   TRACE("Accepted a new TCP connection\n");
689   return RPC_S_OK;
690 }
691
692 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
693                                 void *buffer, unsigned int count)
694 {
695   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
696   int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
697   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
698   return r;
699 }
700
701 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
702                                  const void *buffer, unsigned int count)
703 {
704   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
705   int r = write(tcpc->sock, buffer, count);
706   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
707   return r;
708 }
709
710 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
711 {
712   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
713
714   TRACE("%d\n", tcpc->sock);
715
716   if (tcpc->sock != -1)
717     close(tcpc->sock);
718   tcpc->sock = -1;
719   return 0;
720 }
721
722 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
723                                                    const char *networkaddr,
724                                                    const char *endpoint)
725 {
726     twr_tcp_floor_t *tcp_floor;
727     twr_ipv4_floor_t *ipv4_floor;
728     struct addrinfo *ai;
729     struct addrinfo hints;
730     int ret;
731     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
732
733     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
734
735     if (!tower_data)
736         return size;
737
738     tcp_floor = (twr_tcp_floor_t *)tower_data;
739     tower_data += sizeof(*tcp_floor);
740
741     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
742
743     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
744     tcp_floor->protid = EPM_PROTOCOL_TCP;
745     tcp_floor->count_rhs = sizeof(tcp_floor->port);
746
747     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
748     ipv4_floor->protid = EPM_PROTOCOL_IP;
749     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
750
751     hints.ai_flags          = AI_NUMERICHOST;
752     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
753     hints.ai_family         = PF_INET;
754     hints.ai_socktype       = SOCK_STREAM;
755     hints.ai_protocol       = IPPROTO_TCP;
756     hints.ai_addrlen        = 0;
757     hints.ai_addr           = NULL;
758     hints.ai_canonname      = NULL;
759     hints.ai_next           = NULL;
760
761     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
762     if (ret)
763     {
764         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
765         if (ret)
766         {
767             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
768             return 0;
769         }
770     }
771
772     if (ai->ai_family == PF_INET)
773     {
774         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
775         tcp_floor->port = sin->sin_port;
776         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
777     }
778     else
779     {
780         ERR("unexpected protocol family %d\n", ai->ai_family);
781         return 0;
782     }
783
784     freeaddrinfo(ai);
785
786     return size;
787 }
788
789 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
790                                                          size_t tower_size,
791                                                          char **networkaddr,
792                                                          char **endpoint)
793 {
794     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
795     const twr_ipv4_floor_t *ipv4_floor;
796     struct in_addr in_addr;
797
798     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
799
800     if (tower_size < sizeof(*tcp_floor))
801         return EPT_S_NOT_REGISTERED;
802
803     tower_data += sizeof(*tcp_floor);
804     tower_size -= sizeof(*tcp_floor);
805
806     if (tower_size < sizeof(*ipv4_floor))
807         return EPT_S_NOT_REGISTERED;
808
809     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
810
811     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
812         (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
813         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
814         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
815         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
816         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
817         return EPT_S_NOT_REGISTERED;
818
819     if (endpoint)
820     {
821         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
822         if (!*endpoint)
823             return RPC_S_OUT_OF_RESOURCES;
824         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
825     }
826
827     if (networkaddr)
828     {
829         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
830         if (!*networkaddr)
831         {
832             if (endpoint)
833             {
834                 I_RpcFree(*endpoint);
835                 *endpoint = NULL;
836             }
837             return RPC_S_OUT_OF_RESOURCES;
838         }
839         in_addr.s_addr = ipv4_floor->ipv4addr;
840         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
841         {
842             ERR("inet_ntop: %s\n", strerror(errno));
843             I_RpcFree(*networkaddr);
844             *networkaddr = NULL;
845             if (endpoint)
846             {
847                 I_RpcFree(*endpoint);
848                 *endpoint = NULL;
849             }
850             return EPT_S_NOT_REGISTERED;
851         }
852     }
853
854     return RPC_S_OK;
855 }
856
857 typedef struct _RpcServerProtseq_sock
858 {
859     RpcServerProtseq common;
860     int mgr_event_rcv;
861     int mgr_event_snd;
862 } RpcServerProtseq_sock;
863
864 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
865 {
866     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
867     if (ps)
868     {
869         int fds[2];
870         if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
871         {
872             fcntl(fds[0], F_SETFL, O_NONBLOCK);
873             fcntl(fds[1], F_SETFL, O_NONBLOCK);
874             ps->mgr_event_rcv = fds[0];
875             ps->mgr_event_snd = fds[1];
876         }
877         else
878         {
879             ERR("socketpair failed with error %s\n", strerror(errno));
880             HeapFree(GetProcessHeap(), 0, ps);
881             return NULL;
882         }
883     }
884     return &ps->common;
885 }
886
887 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
888 {
889     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
890     char dummy = 1;
891     write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
892 }
893
894 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
895 {
896     struct pollfd *poll_info = prev_array;
897     RpcConnection_tcp *conn;
898     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
899
900     EnterCriticalSection(&protseq->cs);
901     
902     /* open and count connections */
903     *count = 1;
904     conn = (RpcConnection_tcp *)protseq->conn;
905     while (conn) {
906         RPCRT4_OpenConnection(&conn->common);
907         if (conn->sock != -1)
908             (*count)++;
909         conn = (RpcConnection_tcp *)conn->common.Next;
910     }
911     
912     /* make array of connections */
913     if (poll_info)
914         poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
915     else
916         poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
917     if (!poll_info)
918     {
919         ERR("couldn't allocate poll_info\n");
920         LeaveCriticalSection(&protseq->cs);
921         return NULL;
922     }
923
924     poll_info[0].fd = sockps->mgr_event_rcv;
925     poll_info[0].events = POLLIN;
926     *count = 1;
927     conn =  CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
928     while (conn) {
929         if (conn->sock != -1)
930         {
931             poll_info[*count].fd = conn->sock;
932             poll_info[*count].events = POLLIN;
933             (*count)++;
934         }
935         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
936     }
937     LeaveCriticalSection(&protseq->cs);
938     return poll_info;
939 }
940
941 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
942 {
943     HeapFree(GetProcessHeap(), 0, array);
944 }
945
946 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
947 {
948     struct pollfd *poll_info = wait_array;
949     int ret, i;
950     RpcConnection *cconn;
951     RpcConnection_tcp *conn;
952     
953     if (!poll_info)
954         return -1;
955     
956     ret = poll(poll_info, count, -1);
957     if (ret < 0)
958     {
959         ERR("poll failed with error %d\n", ret);
960         return -1;
961     }
962
963     for (i = 0; i < count; i++)
964         if (poll_info[i].revents & POLLIN)
965         {
966             /* RPC server event */
967             if (i == 0)
968             {
969                 char dummy;
970                 read(poll_info[0].fd, &dummy, sizeof(dummy));
971                 return 0;
972             }
973
974             /* find which connection got a RPC */
975             EnterCriticalSection(&protseq->cs);
976             conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
977             while (conn) {
978                 if (poll_info[i].fd == conn->sock) break;
979                 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
980             }
981             cconn = NULL;
982             if (conn)
983                 RPCRT4_SpawnConnection(&cconn, &conn->common);
984             else
985                 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
986             LeaveCriticalSection(&protseq->cs);
987             if (cconn)
988                 RPCRT4_new_client(cconn);
989             else
990                 return -1;
991         }
992
993     return 1;
994 }
995
996 static const struct connection_ops conn_protseq_list[] = {
997   { "ncacn_np",
998     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
999     rpcrt4_conn_np_alloc,
1000     rpcrt4_ncacn_np_open,
1001     rpcrt4_conn_np_handoff,
1002     rpcrt4_conn_np_read,
1003     rpcrt4_conn_np_write,
1004     rpcrt4_conn_np_close,
1005     rpcrt4_ncacn_np_get_top_of_tower,
1006     rpcrt4_ncacn_np_parse_top_of_tower,
1007   },
1008   { "ncalrpc",
1009     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1010     rpcrt4_conn_np_alloc,
1011     rpcrt4_ncalrpc_open,
1012     rpcrt4_conn_np_handoff,
1013     rpcrt4_conn_np_read,
1014     rpcrt4_conn_np_write,
1015     rpcrt4_conn_np_close,
1016     rpcrt4_ncalrpc_get_top_of_tower,
1017     rpcrt4_ncalrpc_parse_top_of_tower,
1018   },
1019   { "ncacn_ip_tcp",
1020     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1021     rpcrt4_conn_tcp_alloc,
1022     rpcrt4_ncacn_ip_tcp_open,
1023     rpcrt4_conn_tcp_handoff,
1024     rpcrt4_conn_tcp_read,
1025     rpcrt4_conn_tcp_write,
1026     rpcrt4_conn_tcp_close,
1027     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1028     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1029   }
1030 };
1031
1032
1033 static const struct protseq_ops protseq_list[] =
1034 {
1035     {
1036         "ncacn_np",
1037         rpcrt4_protseq_np_alloc,
1038         rpcrt4_protseq_np_signal_state_changed,
1039         rpcrt4_protseq_np_get_wait_array,
1040         rpcrt4_protseq_np_free_wait_array,
1041         rpcrt4_protseq_np_wait_for_new_connection,
1042     },
1043     {
1044         "ncalrpc",
1045         rpcrt4_protseq_np_alloc,
1046         rpcrt4_protseq_np_signal_state_changed,
1047         rpcrt4_protseq_np_get_wait_array,
1048         rpcrt4_protseq_np_free_wait_array,
1049         rpcrt4_protseq_np_wait_for_new_connection,
1050     },
1051     {
1052         "ncacn_ip_tcp",
1053         rpcrt4_protseq_sock_alloc,
1054         rpcrt4_protseq_sock_signal_state_changed,
1055         rpcrt4_protseq_sock_get_wait_array,
1056         rpcrt4_protseq_sock_free_wait_array,
1057         rpcrt4_protseq_sock_wait_for_new_connection,
1058     },
1059 };
1060
1061 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1062
1063 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1064 {
1065   int i;
1066   for(i=0; i<ARRAYSIZE(protseq_list); i++)
1067     if (!strcmp(protseq_list[i].name, protseq))
1068       return &protseq_list[i];
1069   return NULL;
1070 }
1071
1072 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1073 {
1074     int i;
1075     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1076         if (!strcmp(conn_protseq_list[i].name, protseq))
1077             return &conn_protseq_list[i];
1078     return NULL;
1079 }
1080
1081 /**** interface to rest of code ****/
1082
1083 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
1084 {
1085   TRACE("(Connection == ^%p)\n", Connection);
1086
1087   return Connection->ops->open_connection(Connection);
1088 }
1089
1090 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1091 {
1092   TRACE("(Connection == ^%p)\n", Connection);
1093   rpcrt4_conn_close(Connection);
1094   return RPC_S_OK;
1095 }
1096
1097 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1098     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1099     LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1100 {
1101   const struct connection_ops *ops;
1102   RpcConnection* NewConnection;
1103
1104   ops = rpcrt4_get_conn_protseq_ops(Protseq);
1105   if (!ops)
1106     return RPC_S_PROTSEQ_NOT_SUPPORTED;
1107
1108   NewConnection = ops->alloc();
1109   NewConnection->Next = NULL;
1110   NewConnection->server = server;
1111   NewConnection->ops = ops;
1112   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1113   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1114   NewConnection->Used = Binding;
1115   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1116   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1117   NewConnection->NextCallId = 1;
1118
1119   memset(&NewConnection->ctx, 0, sizeof(NewConnection->ctx));
1120   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1121   NewConnection->AuthInfo = AuthInfo;
1122   list_init(&NewConnection->conn_pool_entry);
1123
1124   TRACE("connection: %p\n", NewConnection);
1125   *Connection = NewConnection;
1126
1127   return RPC_S_OK;
1128 }
1129
1130 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1131     const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1132     LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1133 {
1134   RpcConnection *Connection;
1135   /* try to find a compatible connection from the connection pool */
1136   EnterCriticalSection(&connection_pool_cs);
1137   LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1138     if ((Connection->AuthInfo == AuthInfo) &&
1139         !memcmp(&Connection->ActiveInterface, InterfaceId,
1140            sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1141         !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1142         !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1143         !strcmp(Connection->Endpoint, Endpoint))
1144     {
1145       list_remove(&Connection->conn_pool_entry);
1146       LeaveCriticalSection(&connection_pool_cs);
1147       TRACE("got connection from pool %p\n", Connection);
1148       return Connection;
1149     }
1150
1151   LeaveCriticalSection(&connection_pool_cs);
1152   return NULL;
1153 }
1154
1155 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1156 {
1157   assert(!Connection->server);
1158   EnterCriticalSection(&connection_pool_cs);
1159   list_add_head(&connection_pool, &Connection->conn_pool_entry);
1160   LeaveCriticalSection(&connection_pool_cs);
1161 }
1162
1163
1164 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1165 {
1166   RPC_STATUS err;
1167
1168   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1169                                 rpcrt4_conn_get_name(OldConnection),
1170                                 OldConnection->NetworkAddr,
1171                                 OldConnection->Endpoint, NULL,
1172                                 OldConnection->AuthInfo, NULL);
1173   if (err == RPC_S_OK)
1174     rpcrt4_conn_handoff(OldConnection, *Connection);
1175   return err;
1176 }
1177
1178 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1179 {
1180   TRACE("connection: %p\n", Connection);
1181
1182   RPCRT4_CloseConnection(Connection);
1183   RPCRT4_strfree(Connection->Endpoint);
1184   RPCRT4_strfree(Connection->NetworkAddr);
1185   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1186   HeapFree(GetProcessHeap(), 0, Connection);
1187   return RPC_S_OK;
1188 }
1189
1190 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1191                                       size_t *tower_size,
1192                                       const char *protseq,
1193                                       const char *networkaddr,
1194                                       const char *endpoint)
1195 {
1196     twr_empty_floor_t *protocol_floor;
1197     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1198
1199     *tower_size = 0;
1200
1201     if (!protseq_ops)
1202         return RPC_S_INVALID_RPC_PROTSEQ;
1203
1204     if (!tower_data)
1205     {
1206         *tower_size = sizeof(*protocol_floor);
1207         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1208         return RPC_S_OK;
1209     }
1210
1211     protocol_floor = (twr_empty_floor_t *)tower_data;
1212     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1213     protocol_floor->protid = protseq_ops->epm_protocols[0];
1214     protocol_floor->count_rhs = 0;
1215
1216     tower_data += sizeof(*protocol_floor);
1217
1218     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1219     if (!*tower_size)
1220         return EPT_S_NOT_REGISTERED;
1221
1222     *tower_size += sizeof(*protocol_floor);
1223
1224     return RPC_S_OK;
1225 }
1226
1227 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1228                                         size_t tower_size,
1229                                         char **protseq,
1230                                         char **networkaddr,
1231                                         char **endpoint)
1232 {
1233     const twr_empty_floor_t *protocol_floor;
1234     const twr_empty_floor_t *floor4;
1235     const struct connection_ops *protseq_ops = NULL;
1236     RPC_STATUS status;
1237     int i;
1238
1239     if (tower_size < sizeof(*protocol_floor))
1240         return EPT_S_NOT_REGISTERED;
1241
1242     protocol_floor = (const twr_empty_floor_t *)tower_data;
1243     tower_data += sizeof(*protocol_floor);
1244     tower_size -= sizeof(*protocol_floor);
1245     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1246         (protocol_floor->count_rhs > tower_size))
1247         return EPT_S_NOT_REGISTERED;
1248     tower_data += protocol_floor->count_rhs;
1249     tower_size -= protocol_floor->count_rhs;
1250
1251     floor4 = (const twr_empty_floor_t *)tower_data;
1252     if ((tower_size < sizeof(*floor4)) ||
1253         (floor4->count_lhs != sizeof(floor4->protid)))
1254         return EPT_S_NOT_REGISTERED;
1255
1256     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1257         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1258             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1259         {
1260             protseq_ops = &conn_protseq_list[i];
1261             break;
1262         }
1263
1264     if (!protseq_ops)
1265         return EPT_S_NOT_REGISTERED;
1266
1267     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1268
1269     if ((status == RPC_S_OK) && protseq)
1270     {
1271         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1272         strcpy(*protseq, protseq_ops->name);
1273     }
1274
1275     return status;
1276 }
1277
1278 /***********************************************************************
1279  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
1280  *
1281  * Checks if the given protocol sequence is known by the RPC system.
1282  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1283  *
1284  */
1285 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1286 {
1287   char ps[0x10];
1288
1289   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1290                       ps, sizeof ps, NULL, NULL);
1291   if (rpcrt4_get_conn_protseq_ops(ps))
1292     return RPC_S_OK;
1293
1294   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1295
1296   return RPC_S_INVALID_RPC_PROTSEQ;
1297 }
1298
1299 /***********************************************************************
1300  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
1301  */
1302 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1303 {
1304   UNICODE_STRING protseqW;
1305
1306   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1307   {
1308     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1309     RtlFreeUnicodeString(&protseqW);
1310     return ret;
1311   }
1312   return RPC_S_OUT_OF_MEMORY;
1313 }