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