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