rpcrt4: Move transport-specific server functions to rpc_transport.c.
[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 HANDLE rpcrt4_conn_np_get_connect_event(RpcConnection *Connection)
225 {
226   RpcConnection_np *npc = (RpcConnection_np *) Connection;
227   return npc->ovl.hEvent;
228 }
229
230 static RPC_STATUS rpcrt4_conn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
231 {
232   RpcConnection_np *old_npc = (RpcConnection_np *) old_conn;
233   RpcConnection_np *new_npc = (RpcConnection_np *) new_conn;
234   /* because of the way named pipes work, we'll transfer the connected pipe
235    * to the child, then reopen the server binding to continue listening */
236
237   new_npc->pipe = old_npc->pipe;
238   new_npc->ovl = old_npc->ovl;
239   old_npc->pipe = 0;
240   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
241   return RPCRT4_OpenConnection(old_conn);
242 }
243
244 static int rpcrt4_conn_np_read(RpcConnection *Connection,
245                         void *buffer, unsigned int count)
246 {
247   RpcConnection_np *npc = (RpcConnection_np *) Connection;
248   DWORD dwRead = 0;
249   if (!ReadFile(npc->pipe, buffer, count, &dwRead, NULL) &&
250       (GetLastError() != ERROR_MORE_DATA))
251     return -1;
252   return dwRead;
253 }
254
255 static int rpcrt4_conn_np_write(RpcConnection *Connection,
256                              const void *buffer, unsigned int count)
257 {
258   RpcConnection_np *npc = (RpcConnection_np *) Connection;
259   DWORD dwWritten = 0;
260   if (!WriteFile(npc->pipe, buffer, count, &dwWritten, NULL))
261     return -1;
262   return dwWritten;
263 }
264
265 static int rpcrt4_conn_np_close(RpcConnection *Connection)
266 {
267   RpcConnection_np *npc = (RpcConnection_np *) Connection;
268   if (npc->pipe) {
269     FlushFileBuffers(npc->pipe);
270     CloseHandle(npc->pipe);
271     npc->pipe = 0;
272   }
273   if (npc->ovl.hEvent) {
274     CloseHandle(npc->ovl.hEvent);
275     npc->ovl.hEvent = 0;
276   }
277   return 0;
278 }
279
280 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
281                                                const char *networkaddr,
282                                                const char *endpoint)
283 {
284     twr_empty_floor_t *smb_floor;
285     twr_empty_floor_t *nb_floor;
286     size_t size;
287     size_t networkaddr_size;
288     size_t endpoint_size;
289
290     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
291
292     networkaddr_size = strlen(networkaddr) + 1;
293     endpoint_size = strlen(endpoint) + 1;
294     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
295
296     if (!tower_data)
297         return size;
298
299     smb_floor = (twr_empty_floor_t *)tower_data;
300
301     tower_data += sizeof(*smb_floor);
302
303     smb_floor->count_lhs = sizeof(smb_floor->protid);
304     smb_floor->protid = EPM_PROTOCOL_SMB;
305     smb_floor->count_rhs = endpoint_size;
306
307     memcpy(tower_data, endpoint, endpoint_size);
308     tower_data += endpoint_size;
309
310     nb_floor = (twr_empty_floor_t *)tower_data;
311
312     tower_data += sizeof(*nb_floor);
313
314     nb_floor->count_lhs = sizeof(nb_floor->protid);
315     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
316     nb_floor->count_rhs = networkaddr_size;
317
318     memcpy(tower_data, networkaddr, networkaddr_size);
319     tower_data += networkaddr_size;
320
321     return size;
322 }
323
324 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
325                                                      size_t tower_size,
326                                                      char **networkaddr,
327                                                      char **endpoint)
328 {
329     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
330     const twr_empty_floor_t *nb_floor;
331
332     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
333
334     if (tower_size < sizeof(*smb_floor))
335         return EPT_S_NOT_REGISTERED;
336
337     tower_data += sizeof(*smb_floor);
338     tower_size -= sizeof(*smb_floor);
339
340     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
341         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
342         (smb_floor->count_rhs > tower_size))
343         return EPT_S_NOT_REGISTERED;
344
345     if (endpoint)
346     {
347         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
348         if (!*endpoint)
349             return RPC_S_OUT_OF_RESOURCES;
350         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
351     }
352     tower_data += smb_floor->count_rhs;
353     tower_size -= smb_floor->count_rhs;
354
355     if (tower_size < sizeof(*nb_floor))
356         return EPT_S_NOT_REGISTERED;
357
358     nb_floor = (const twr_empty_floor_t *)tower_data;
359
360     tower_data += sizeof(*nb_floor);
361     tower_size -= sizeof(*nb_floor);
362
363     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
364         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
365         (nb_floor->count_rhs > tower_size))
366         return EPT_S_NOT_REGISTERED;
367
368     if (networkaddr)
369     {
370         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
371         if (!*networkaddr)
372         {
373             if (endpoint)
374             {
375                 I_RpcFree(*endpoint);
376                 *endpoint = NULL;
377             }
378             return RPC_S_OUT_OF_RESOURCES;
379         }
380         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
381     }
382
383     return RPC_S_OK;
384 }
385
386 typedef struct _RpcServerProtseq_np
387 {
388     RpcServerProtseq common;
389     HANDLE mgr_event;
390 } RpcServerProtseq_np;
391
392 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
393 {
394     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
395     if (ps)
396         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
397     return &ps->common;
398 }
399
400 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
401 {
402     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
403     SetEvent(npps->mgr_event);
404 }
405
406 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
407 {
408     HANDLE *objs = prev_array;
409     RpcConnection* conn;
410     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
411     
412     EnterCriticalSection(&protseq->cs);
413     
414     /* open and count connections */
415     *count = 1;
416     conn = protseq->conn;
417     while (conn) {
418         RPCRT4_OpenConnection(conn);
419         if (rpcrt4_conn_get_wait_object(conn))
420             (*count)++;
421         conn = conn->Next;
422     }
423     
424     /* make array of connections */
425     if (objs)
426         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
427     else
428         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
429     if (!objs)
430     {
431         ERR("couldn't allocate objs\n");
432         LeaveCriticalSection(&protseq->cs);
433         return NULL;
434     }
435     
436     objs[0] = npps->mgr_event;
437     *count = 1;
438     conn = protseq->conn;
439     while (conn) {
440         if ((objs[*count] = rpcrt4_conn_get_wait_object(conn)))
441             (*count)++;
442         conn = conn->Next;
443     }
444     LeaveCriticalSection(&protseq->cs);
445     return objs;
446 }
447
448 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
449 {
450     HeapFree(GetProcessHeap(), 0, array);
451 }
452
453 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
454 {
455     HANDLE b_handle;
456     HANDLE *objs = wait_array;
457     DWORD res;
458     RpcConnection* cconn;
459     RpcConnection* conn;
460     
461     if (!objs)
462         return -1;
463     
464     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
465     if (res == WAIT_OBJECT_0)
466         return 0;
467     else if (res == WAIT_FAILED)
468     {
469         ERR("wait failed with error %ld\n", GetLastError());
470         return -1;
471     }
472     else
473     {
474         b_handle = objs[res - WAIT_OBJECT_0];
475         /* find which connection got a RPC */
476         EnterCriticalSection(&protseq->cs);
477         conn = protseq->conn;
478         while (conn) {
479             if (b_handle == rpcrt4_conn_get_wait_object(conn)) break;
480             conn = conn->Next;
481         }
482         cconn = NULL;
483         if (conn)
484             RPCRT4_SpawnConnection(&cconn, conn);
485         else
486             ERR("failed to locate connection for handle %p\n", b_handle);
487         LeaveCriticalSection(&protseq->cs);
488         if (cconn)
489         {
490             RPCRT4_new_client(cconn);
491             return 1;
492         }
493         else return -1;
494     }
495 }
496
497 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
498                                               const char *networkaddr,
499                                               const char *endpoint)
500 {
501     twr_empty_floor_t *pipe_floor;
502     size_t size;
503     size_t endpoint_size;
504
505     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
506
507     endpoint_size = strlen(networkaddr) + 1;
508     size = sizeof(*pipe_floor) + endpoint_size;
509
510     if (!tower_data)
511         return size;
512
513     pipe_floor = (twr_empty_floor_t *)tower_data;
514
515     tower_data += sizeof(*pipe_floor);
516
517     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
518     pipe_floor->protid = EPM_PROTOCOL_SMB;
519     pipe_floor->count_rhs = endpoint_size;
520
521     memcpy(tower_data, endpoint, endpoint_size);
522     tower_data += endpoint_size;
523
524     return size;
525 }
526
527 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
528                                                     size_t tower_size,
529                                                     char **networkaddr,
530                                                     char **endpoint)
531 {
532     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
533
534     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
535
536     *networkaddr = NULL;
537     *endpoint = NULL;
538
539     if (tower_size < sizeof(*pipe_floor))
540         return EPT_S_NOT_REGISTERED;
541
542     tower_data += sizeof(*pipe_floor);
543     tower_size -= sizeof(*pipe_floor);
544
545     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
546         (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
547         (pipe_floor->count_rhs > tower_size))
548         return EPT_S_NOT_REGISTERED;
549
550     if (endpoint)
551     {
552         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
553         if (!*endpoint)
554             return RPC_S_OUT_OF_RESOURCES;
555         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
556     }
557
558     return RPC_S_OK;
559 }
560
561 /**** ncacn_ip_tcp support ****/
562
563 typedef struct _RpcConnection_tcp
564 {
565   RpcConnection common;
566   int sock;
567   HANDLE onEventAvailable;
568   HANDLE onEventHandled;
569   BOOL quit;
570 } RpcConnection_tcp;
571
572 static DWORD WINAPI rpcrt4_tcp_poll_thread(LPVOID arg)
573 {
574   RpcConnection_tcp *tcpc;
575   int ret;
576   struct pollfd pollInfo;
577
578   tcpc = (RpcConnection_tcp*) arg;
579   pollInfo.fd = tcpc->sock;
580   pollInfo.events = POLLIN;
581
582   while (!tcpc->quit)
583   {
584     ret = poll(&pollInfo, 1, 1000);
585     if (ret < 0)
586       ERR("poll failed with error %d\n", ret);
587     else
588     {
589       if (pollInfo.revents & POLLIN)
590       {
591         SignalObjectAndWait(tcpc->onEventAvailable,
592           tcpc->onEventHandled, INFINITE, FALSE);
593       }
594     }
595   }
596
597   /* This avoids the tcpc being destroyed before we are done with it */
598   SetEvent(tcpc->onEventAvailable);
599
600   return 0;
601 }
602
603 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
604 {
605   RpcConnection_tcp *tcpc;
606   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
607   if (tcpc == NULL)
608     return NULL;
609   tcpc->sock = -1;
610   tcpc->onEventAvailable = NULL;
611   tcpc->onEventHandled = NULL;
612   tcpc->quit = FALSE;
613   return &tcpc->common;
614 }
615
616 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
617 {
618   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
619   int sock;
620   int ret;
621   struct addrinfo *ai;
622   struct addrinfo *ai_cur;
623   struct addrinfo hints;
624
625   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
626
627   if (tcpc->sock != -1)
628     return RPC_S_OK;
629
630   hints.ai_flags          = 0;
631   hints.ai_family         = PF_UNSPEC;
632   hints.ai_socktype       = SOCK_STREAM;
633   hints.ai_protocol       = IPPROTO_TCP;
634   hints.ai_addrlen        = 0;
635   hints.ai_addr           = NULL;
636   hints.ai_canonname      = NULL;
637   hints.ai_next           = NULL;
638
639   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
640   if (ret)
641   {
642     ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
643     return RPC_S_SERVER_UNAVAILABLE;
644   }
645
646   for (ai_cur = ai; ai_cur; ai_cur = ai->ai_next)
647   {
648     if (TRACE_ON(rpc))
649     {
650       char host[256];
651       char service[256];
652       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
653         host, sizeof(host), service, sizeof(service),
654         NI_NUMERICHOST | NI_NUMERICSERV);
655       TRACE("trying %s:%s\n", host, service);
656     }
657
658     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
659     if (sock < 0)
660     {
661       WARN("socket() failed\n");
662       continue;
663     }
664
665     if (Connection->server)
666     {
667       HANDLE thread = NULL;
668       ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
669       if (ret < 0)
670       {
671         WARN("bind failed, error %d\n", ret);
672         goto done;
673       }
674       ret = listen(sock, 10);
675       if (ret < 0)
676       {
677         WARN("listen failed, error %d\n", ret);
678         goto done;
679       }
680       /* need a non-blocking socket, otherwise accept() has a potential
681        * race-condition (poll() says it is readable, connection drops,
682        * and accept() blocks until the next connection comes...)
683        */
684       ret = fcntl(sock, F_SETFL, O_NONBLOCK);
685       if (ret < 0)
686       {
687         WARN("couldn't make socket non-blocking, error %d\n", ret);
688         goto done;
689       }
690       tcpc->onEventAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
691       if (tcpc->onEventAvailable == NULL)
692       {
693         WARN("creating available event failed, error %lu\n", GetLastError());
694         goto done;
695       }
696       tcpc->onEventHandled = CreateEventW(NULL, FALSE, FALSE, NULL);
697       if (tcpc->onEventHandled == NULL)
698       {
699         WARN("creating handled event failed, error %lu\n", GetLastError());
700         goto done;
701       }
702       tcpc->sock = sock;
703       thread = CreateThread(NULL, 0, rpcrt4_tcp_poll_thread, tcpc, 0, NULL);
704       if (thread == NULL)
705       {
706         WARN("creating server polling thread failed, error %lu\n",
707           GetLastError());
708         tcpc->sock = -1;
709         goto done;
710       }
711       CloseHandle(thread);
712
713     done:
714       if (thread == NULL) /* ie. we failed somewhere */
715       {
716         close(sock);
717         if (tcpc->onEventAvailable != NULL)
718         {
719           CloseHandle(tcpc->onEventAvailable);
720           tcpc->onEventAvailable = NULL;
721         }
722         if (tcpc->onEventHandled != NULL)
723         {
724           CloseHandle(tcpc->onEventHandled);
725           tcpc->onEventHandled = NULL;
726         }
727         continue;
728       }
729     }
730     else /* it's a client */
731     {
732       if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
733       {
734         WARN("connect() failed\n");
735         close(sock);
736         continue;
737       }
738       tcpc->sock = sock;
739     }
740
741     freeaddrinfo(ai);
742     TRACE("connected\n");
743     return RPC_S_OK;
744   }
745
746   freeaddrinfo(ai);
747   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
748   return RPC_S_SERVER_UNAVAILABLE;
749 }
750
751 static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
752 {
753   RpcConnection_tcp *tcpc = (RpcConnection_tcp*) Connection;
754   return tcpc->onEventAvailable;
755 }
756
757 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
758 {
759   int ret;
760   struct sockaddr_in address;
761   socklen_t addrsize;
762   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
763   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
764
765   addrsize = sizeof(address);
766   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
767   SetEvent(server->onEventHandled);
768   if (ret < 0)
769   {
770     ERR("Failed to accept a TCP connection: error %d\n", ret);
771     return RPC_S_SERVER_UNAVAILABLE;
772   }
773   client->sock = ret;
774   TRACE("Accepted a new TCP connection\n");
775   return RPC_S_OK;
776 }
777
778 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
779                                 void *buffer, unsigned int count)
780 {
781   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
782   int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
783   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
784   return r;
785 }
786
787 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
788                                  const void *buffer, unsigned int count)
789 {
790   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
791   int r = write(tcpc->sock, buffer, count);
792   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
793   return r;
794 }
795
796 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
797 {
798   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
799
800   TRACE("%d\n", tcpc->sock);
801
802   if (tcpc->onEventAvailable != NULL)
803   {
804     /* it's a server connection */
805     tcpc->quit = TRUE;
806     WaitForSingleObject(tcpc->onEventAvailable, INFINITE);
807     CloseHandle(tcpc->onEventAvailable);
808     CloseHandle(tcpc->onEventHandled);
809   }
810
811   if (tcpc->sock != -1)
812     close(tcpc->sock);
813   tcpc->sock = -1;
814   return 0;
815 }
816
817 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
818                                                    const char *networkaddr,
819                                                    const char *endpoint)
820 {
821     twr_tcp_floor_t *tcp_floor;
822     twr_ipv4_floor_t *ipv4_floor;
823     struct addrinfo *ai;
824     struct addrinfo hints;
825     int ret;
826     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
827
828     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
829
830     if (!tower_data)
831         return size;
832
833     tcp_floor = (twr_tcp_floor_t *)tower_data;
834     tower_data += sizeof(*tcp_floor);
835
836     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
837
838     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
839     tcp_floor->protid = EPM_PROTOCOL_TCP;
840     tcp_floor->count_rhs = sizeof(tcp_floor->port);
841
842     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
843     ipv4_floor->protid = EPM_PROTOCOL_IP;
844     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
845
846     hints.ai_flags          = AI_NUMERICHOST;
847     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
848     hints.ai_family         = PF_INET;
849     hints.ai_socktype       = SOCK_STREAM;
850     hints.ai_protocol       = IPPROTO_TCP;
851     hints.ai_addrlen        = 0;
852     hints.ai_addr           = NULL;
853     hints.ai_canonname      = NULL;
854     hints.ai_next           = NULL;
855
856     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
857     if (ret)
858     {
859         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
860         if (ret)
861         {
862             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
863             return 0;
864         }
865     }
866
867     if (ai->ai_family == PF_INET)
868     {
869         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
870         tcp_floor->port = sin->sin_port;
871         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
872     }
873     else
874     {
875         ERR("unexpected protocol family %d\n", ai->ai_family);
876         return 0;
877     }
878
879     freeaddrinfo(ai);
880
881     return size;
882 }
883
884 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
885                                                          size_t tower_size,
886                                                          char **networkaddr,
887                                                          char **endpoint)
888 {
889     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
890     const twr_ipv4_floor_t *ipv4_floor;
891     struct in_addr in_addr;
892
893     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
894
895     if (tower_size < sizeof(*tcp_floor))
896         return EPT_S_NOT_REGISTERED;
897
898     tower_data += sizeof(*tcp_floor);
899     tower_size -= sizeof(*tcp_floor);
900
901     if (tower_size < sizeof(*ipv4_floor))
902         return EPT_S_NOT_REGISTERED;
903
904     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
905
906     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
907         (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
908         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
909         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
910         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
911         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
912         return EPT_S_NOT_REGISTERED;
913
914     if (endpoint)
915     {
916         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
917         if (!*endpoint)
918             return RPC_S_OUT_OF_RESOURCES;
919         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
920     }
921
922     if (networkaddr)
923     {
924         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
925         if (!*networkaddr)
926         {
927             if (endpoint)
928             {
929                 I_RpcFree(*endpoint);
930                 *endpoint = NULL;
931             }
932             return RPC_S_OUT_OF_RESOURCES;
933         }
934         in_addr.s_addr = ipv4_floor->ipv4addr;
935         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
936         {
937             ERR("inet_ntop: %s\n", strerror(errno));
938             I_RpcFree(*networkaddr);
939             *networkaddr = NULL;
940             if (endpoint)
941             {
942                 I_RpcFree(*endpoint);
943                 *endpoint = NULL;
944             }
945             return EPT_S_NOT_REGISTERED;
946         }
947     }
948
949     return RPC_S_OK;
950 }
951
952 static const struct connection_ops conn_protseq_list[] = {
953   { "ncacn_np",
954     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
955     rpcrt4_conn_np_alloc,
956     rpcrt4_ncacn_np_open,
957     rpcrt4_conn_np_get_connect_event,
958     rpcrt4_conn_np_handoff,
959     rpcrt4_conn_np_read,
960     rpcrt4_conn_np_write,
961     rpcrt4_conn_np_close,
962     rpcrt4_ncacn_np_get_top_of_tower,
963     rpcrt4_ncacn_np_parse_top_of_tower,
964   },
965   { "ncalrpc",
966     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
967     rpcrt4_conn_np_alloc,
968     rpcrt4_ncalrpc_open,
969     rpcrt4_conn_np_get_connect_event,
970     rpcrt4_conn_np_handoff,
971     rpcrt4_conn_np_read,
972     rpcrt4_conn_np_write,
973     rpcrt4_conn_np_close,
974     rpcrt4_ncalrpc_get_top_of_tower,
975     rpcrt4_ncalrpc_parse_top_of_tower,
976   },
977   { "ncacn_ip_tcp",
978     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
979     rpcrt4_conn_tcp_alloc,
980     rpcrt4_ncacn_ip_tcp_open,
981     rpcrt4_conn_tcp_get_wait_handle,
982     rpcrt4_conn_tcp_handoff,
983     rpcrt4_conn_tcp_read,
984     rpcrt4_conn_tcp_write,
985     rpcrt4_conn_tcp_close,
986     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
987     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
988   }
989 };
990
991
992 static const struct protseq_ops protseq_list[] =
993 {
994     {
995         "ncacn_np",
996         rpcrt4_protseq_np_alloc,
997         rpcrt4_protseq_np_signal_state_changed,
998         rpcrt4_protseq_np_get_wait_array,
999         rpcrt4_protseq_np_free_wait_array,
1000         rpcrt4_protseq_np_wait_for_new_connection,
1001     },
1002     {
1003         "ncalrpc",
1004         rpcrt4_protseq_np_alloc,
1005         rpcrt4_protseq_np_signal_state_changed,
1006         rpcrt4_protseq_np_get_wait_array,
1007         rpcrt4_protseq_np_free_wait_array,
1008         rpcrt4_protseq_np_wait_for_new_connection,
1009     },
1010     {
1011         "ncacn_ip_tcp",
1012         rpcrt4_protseq_np_alloc,
1013         rpcrt4_protseq_np_signal_state_changed,
1014         rpcrt4_protseq_np_get_wait_array,
1015         rpcrt4_protseq_np_free_wait_array,
1016         rpcrt4_protseq_np_wait_for_new_connection,
1017     },
1018 };
1019
1020 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1021
1022 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1023 {
1024   int i;
1025   for(i=0; i<ARRAYSIZE(protseq_list); i++)
1026     if (!strcmp(protseq_list[i].name, protseq))
1027       return &protseq_list[i];
1028   return NULL;
1029 }
1030
1031 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1032 {
1033     int i;
1034     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1035         if (!strcmp(conn_protseq_list[i].name, protseq))
1036             return &conn_protseq_list[i];
1037     return NULL;
1038 }
1039
1040 /**** interface to rest of code ****/
1041
1042 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
1043 {
1044   TRACE("(Connection == ^%p)\n", Connection);
1045
1046   return Connection->ops->open_connection(Connection);
1047 }
1048
1049 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1050 {
1051   TRACE("(Connection == ^%p)\n", Connection);
1052   rpcrt4_conn_close(Connection);
1053   return RPC_S_OK;
1054 }
1055
1056 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1057     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1058     LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding)
1059 {
1060   const struct connection_ops *ops;
1061   RpcConnection* NewConnection;
1062
1063   ops = rpcrt4_get_conn_protseq_ops(Protseq);
1064   if (!ops)
1065     return RPC_S_PROTSEQ_NOT_SUPPORTED;
1066
1067   NewConnection = ops->alloc();
1068   NewConnection->Next = NULL;
1069   NewConnection->server = server;
1070   NewConnection->ops = ops;
1071   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1072   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1073   NewConnection->Used = Binding;
1074   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1075   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1076   NewConnection->NextCallId = 1;
1077
1078   memset(&NewConnection->ctx, 0, sizeof(NewConnection->ctx));
1079   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1080   NewConnection->AuthInfo = AuthInfo;
1081   list_init(&NewConnection->conn_pool_entry);
1082
1083   TRACE("connection: %p\n", NewConnection);
1084   *Connection = NewConnection;
1085
1086   return RPC_S_OK;
1087 }
1088
1089 RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1090     const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
1091     LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
1092 {
1093   RpcConnection *Connection;
1094   /* try to find a compatible connection from the connection pool */
1095   EnterCriticalSection(&connection_pool_cs);
1096   LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
1097     if ((Connection->AuthInfo == AuthInfo) &&
1098         !memcmp(&Connection->ActiveInterface, InterfaceId,
1099            sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1100         !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
1101         !strcmp(Connection->NetworkAddr, NetworkAddr) &&
1102         !strcmp(Connection->Endpoint, Endpoint))
1103     {
1104       list_remove(&Connection->conn_pool_entry);
1105       LeaveCriticalSection(&connection_pool_cs);
1106       TRACE("got connection from pool %p\n", Connection);
1107       return Connection;
1108     }
1109
1110   LeaveCriticalSection(&connection_pool_cs);
1111   return NULL;
1112 }
1113
1114 void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
1115 {
1116   assert(!Connection->server);
1117   EnterCriticalSection(&connection_pool_cs);
1118   list_add_head(&connection_pool, &Connection->conn_pool_entry);
1119   LeaveCriticalSection(&connection_pool_cs);
1120 }
1121
1122
1123 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1124 {
1125   RPC_STATUS err;
1126
1127   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1128                                 rpcrt4_conn_get_name(OldConnection),
1129                                 OldConnection->NetworkAddr,
1130                                 OldConnection->Endpoint, NULL,
1131                                 OldConnection->AuthInfo, NULL);
1132   if (err == RPC_S_OK)
1133     rpcrt4_conn_handoff(OldConnection, *Connection);
1134   return err;
1135 }
1136
1137 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1138 {
1139   TRACE("connection: %p\n", Connection);
1140
1141   RPCRT4_CloseConnection(Connection);
1142   RPCRT4_strfree(Connection->Endpoint);
1143   RPCRT4_strfree(Connection->NetworkAddr);
1144   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1145   HeapFree(GetProcessHeap(), 0, Connection);
1146   return RPC_S_OK;
1147 }
1148
1149 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1150                                       size_t *tower_size,
1151                                       const char *protseq,
1152                                       const char *networkaddr,
1153                                       const char *endpoint)
1154 {
1155     twr_empty_floor_t *protocol_floor;
1156     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1157
1158     *tower_size = 0;
1159
1160     if (!protseq_ops)
1161         return RPC_S_INVALID_RPC_PROTSEQ;
1162
1163     if (!tower_data)
1164     {
1165         *tower_size = sizeof(*protocol_floor);
1166         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1167         return RPC_S_OK;
1168     }
1169
1170     protocol_floor = (twr_empty_floor_t *)tower_data;
1171     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1172     protocol_floor->protid = protseq_ops->epm_protocols[0];
1173     protocol_floor->count_rhs = 0;
1174
1175     tower_data += sizeof(*protocol_floor);
1176
1177     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1178     if (!*tower_size)
1179         return EPT_S_NOT_REGISTERED;
1180
1181     *tower_size += sizeof(*protocol_floor);
1182
1183     return RPC_S_OK;
1184 }
1185
1186 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1187                                         size_t tower_size,
1188                                         char **protseq,
1189                                         char **networkaddr,
1190                                         char **endpoint)
1191 {
1192     const twr_empty_floor_t *protocol_floor;
1193     const twr_empty_floor_t *floor4;
1194     const struct connection_ops *protseq_ops = NULL;
1195     RPC_STATUS status;
1196     int i;
1197
1198     if (tower_size < sizeof(*protocol_floor))
1199         return EPT_S_NOT_REGISTERED;
1200
1201     protocol_floor = (const twr_empty_floor_t *)tower_data;
1202     tower_data += sizeof(*protocol_floor);
1203     tower_size -= sizeof(*protocol_floor);
1204     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1205         (protocol_floor->count_rhs > tower_size))
1206         return EPT_S_NOT_REGISTERED;
1207     tower_data += protocol_floor->count_rhs;
1208     tower_size -= protocol_floor->count_rhs;
1209
1210     floor4 = (const twr_empty_floor_t *)tower_data;
1211     if ((tower_size < sizeof(*floor4)) ||
1212         (floor4->count_lhs != sizeof(floor4->protid)))
1213         return EPT_S_NOT_REGISTERED;
1214
1215     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1216         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1217             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1218         {
1219             protseq_ops = &conn_protseq_list[i];
1220             break;
1221         }
1222
1223     if (!protseq_ops)
1224         return EPT_S_NOT_REGISTERED;
1225
1226     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1227
1228     if ((status == RPC_S_OK) && protseq)
1229     {
1230         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1231         strcpy(*protseq, protseq_ops->name);
1232     }
1233
1234     return status;
1235 }
1236
1237 /***********************************************************************
1238  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
1239  *
1240  * Checks if the given protocol sequence is known by the RPC system.
1241  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1242  *
1243  */
1244 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1245 {
1246   char ps[0x10];
1247
1248   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1249                       ps, sizeof ps, NULL, NULL);
1250   if (rpcrt4_get_conn_protseq_ops(ps))
1251     return RPC_S_OK;
1252
1253   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1254
1255   return RPC_S_INVALID_RPC_PROTSEQ;
1256 }
1257
1258 /***********************************************************************
1259  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
1260  */
1261 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1262 {
1263   UNICODE_STRING protseqW;
1264
1265   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1266   {
1267     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1268     RtlFreeUnicodeString(&protseqW);
1269     return ret;
1270   }
1271   return RPC_S_OUT_OF_MEMORY;
1272 }