ole32/tests: Relax the reference counting tests a bit. We only care whether reference...
[wine/hramrach.git] / dlls / rpcrt4 / rpc_transport.c
blob07a1e0401b40e84d78c86b4144d63b984bfbb8f9
1 /*
2 * RPC transport layer
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
7 * Copyright 2006 Mike McCormack
8 * Copyright 2006 Damjan Jovanovic
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
35 #if defined(__MINGW32__) || defined (_MSC_VER)
36 # include <ws2tcpip.h>
37 # ifndef EADDRINUSE
38 # define EADDRINUSE WSAEADDRINUSE
39 # endif
40 # ifndef EAGAIN
41 # define EAGAIN WSAEWOULDBLOCK
42 # endif
43 # undef errno
44 # define errno WSAGetLastError()
45 #else
46 # include <errno.h>
47 # ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 # endif
50 # include <fcntl.h>
51 # ifdef HAVE_SYS_SOCKET_H
52 # include <sys/socket.h>
53 # endif
54 # ifdef HAVE_NETINET_IN_H
55 # include <netinet/in.h>
56 # endif
57 # ifdef HAVE_NETINET_TCP_H
58 # include <netinet/tcp.h>
59 # endif
60 # ifdef HAVE_ARPA_INET_H
61 # include <arpa/inet.h>
62 # endif
63 # ifdef HAVE_NETDB_H
64 # include <netdb.h>
65 # endif
66 # ifdef HAVE_SYS_POLL_H
67 # include <sys/poll.h>
68 # endif
69 # ifdef HAVE_SYS_FILIO_H
70 # include <sys/filio.h>
71 # endif
72 # ifdef HAVE_SYS_IOCTL_H
73 # include <sys/ioctl.h>
74 # endif
75 # define closesocket close
76 # define ioctlsocket ioctl
77 #endif /* defined(__MINGW32__) || defined (_MSC_VER) */
79 #include "windef.h"
80 #include "winbase.h"
81 #include "winnls.h"
82 #include "winerror.h"
83 #include "wininet.h"
84 #include "winternl.h"
85 #include "wine/unicode.h"
87 #include "rpc.h"
88 #include "rpcndr.h"
90 #include "wine/debug.h"
92 #include "rpc_binding.h"
93 #include "rpc_assoc.h"
94 #include "rpc_message.h"
95 #include "rpc_server.h"
96 #include "epm_towers.h"
98 #ifndef SOL_TCP
99 # define SOL_TCP IPPROTO_TCP
100 #endif
102 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
104 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
106 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
108 /**** ncacn_np support ****/
110 typedef struct _RpcConnection_np
112 RpcConnection common;
113 HANDLE pipe;
114 OVERLAPPED ovl;
115 BOOL listening;
116 } RpcConnection_np;
118 static RpcConnection *rpcrt4_conn_np_alloc(void)
120 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
121 if (npc)
123 npc->pipe = NULL;
124 memset(&npc->ovl, 0, sizeof(npc->ovl));
125 npc->listening = FALSE;
127 return &npc->common;
130 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
132 if (npc->listening)
133 return RPC_S_OK;
135 npc->listening = TRUE;
136 for (;;)
138 if (ConnectNamedPipe(npc->pipe, &npc->ovl))
139 return RPC_S_OK;
141 switch(GetLastError())
143 case ERROR_PIPE_CONNECTED:
144 SetEvent(npc->ovl.hEvent);
145 return RPC_S_OK;
146 case ERROR_IO_PENDING:
147 /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
148 return RPC_S_OK;
149 case ERROR_NO_DATA_DETECTED:
150 /* client has disconnected, retry */
151 DisconnectNamedPipe( npc->pipe );
152 break;
153 default:
154 npc->listening = FALSE;
155 WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
156 return RPC_S_OUT_OF_RESOURCES;
161 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
163 RpcConnection_np *npc = (RpcConnection_np *) Connection;
164 TRACE("listening on %s\n", pname);
166 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
167 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
168 PIPE_UNLIMITED_INSTANCES,
169 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
170 if (npc->pipe == INVALID_HANDLE_VALUE) {
171 WARN("CreateNamedPipe failed with error %d\n", GetLastError());
172 if (GetLastError() == ERROR_FILE_EXISTS)
173 return RPC_S_DUPLICATE_ENDPOINT;
174 else
175 return RPC_S_CANT_CREATE_ENDPOINT;
178 memset(&npc->ovl, 0, sizeof(npc->ovl));
179 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
181 /* Note: we don't call ConnectNamedPipe here because it must be done in the
182 * server thread as the thread must be alertable */
183 return RPC_S_OK;
186 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
188 RpcConnection_np *npc = (RpcConnection_np *) Connection;
189 HANDLE pipe;
190 DWORD err, dwMode;
192 TRACE("connecting to %s\n", pname);
194 while (TRUE) {
195 DWORD dwFlags = 0;
196 if (Connection->QOS)
198 dwFlags = SECURITY_SQOS_PRESENT;
199 switch (Connection->QOS->qos->ImpersonationType)
201 case RPC_C_IMP_LEVEL_DEFAULT:
202 /* FIXME: what to do here? */
203 break;
204 case RPC_C_IMP_LEVEL_ANONYMOUS:
205 dwFlags |= SECURITY_ANONYMOUS;
206 break;
207 case RPC_C_IMP_LEVEL_IDENTIFY:
208 dwFlags |= SECURITY_IDENTIFICATION;
209 break;
210 case RPC_C_IMP_LEVEL_IMPERSONATE:
211 dwFlags |= SECURITY_IMPERSONATION;
212 break;
213 case RPC_C_IMP_LEVEL_DELEGATE:
214 dwFlags |= SECURITY_DELEGATION;
215 break;
217 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
218 dwFlags |= SECURITY_CONTEXT_TRACKING;
220 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
221 OPEN_EXISTING, dwFlags, 0);
222 if (pipe != INVALID_HANDLE_VALUE) break;
223 err = GetLastError();
224 if (err == ERROR_PIPE_BUSY) {
225 TRACE("connection failed, error=%x\n", err);
226 return RPC_S_SERVER_TOO_BUSY;
228 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
229 err = GetLastError();
230 WARN("connection failed, error=%x\n", err);
231 return RPC_S_SERVER_UNAVAILABLE;
235 /* success */
236 memset(&npc->ovl, 0, sizeof(npc->ovl));
237 /* pipe is connected; change to message-read mode. */
238 dwMode = PIPE_READMODE_MESSAGE;
239 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
240 npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
241 npc->pipe = pipe;
243 return RPC_S_OK;
246 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
248 RpcConnection_np *npc = (RpcConnection_np *) Connection;
249 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
250 RPC_STATUS r;
251 LPSTR pname;
253 /* already connected? */
254 if (npc->pipe)
255 return RPC_S_OK;
257 /* protseq=ncalrpc: supposed to use NT LPC ports,
258 * but we'll implement it with named pipes for now */
259 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
260 strcat(strcpy(pname, prefix), Connection->Endpoint);
261 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
262 I_RpcFree(pname);
264 return r;
267 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
269 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
270 RPC_STATUS r;
271 LPSTR pname;
272 RpcConnection *Connection;
273 char generated_endpoint[22];
275 if (!endpoint)
277 static LONG lrpc_nameless_id;
278 DWORD process_id = GetCurrentProcessId();
279 ULONG id = InterlockedIncrement(&lrpc_nameless_id);
280 snprintf(generated_endpoint, sizeof(generated_endpoint),
281 "LRPC%08x.%08x", process_id, id);
282 endpoint = generated_endpoint;
285 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
286 endpoint, NULL, NULL, NULL);
287 if (r != RPC_S_OK)
288 return r;
290 /* protseq=ncalrpc: supposed to use NT LPC ports,
291 * but we'll implement it with named pipes for now */
292 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
293 strcat(strcpy(pname, prefix), Connection->Endpoint);
294 r = rpcrt4_conn_create_pipe(Connection, pname);
295 I_RpcFree(pname);
297 EnterCriticalSection(&protseq->cs);
298 Connection->Next = protseq->conn;
299 protseq->conn = Connection;
300 LeaveCriticalSection(&protseq->cs);
302 return r;
305 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
307 RpcConnection_np *npc = (RpcConnection_np *) Connection;
308 static const char prefix[] = "\\\\.";
309 RPC_STATUS r;
310 LPSTR pname;
312 /* already connected? */
313 if (npc->pipe)
314 return RPC_S_OK;
316 /* protseq=ncacn_np: named pipes */
317 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
318 strcat(strcpy(pname, prefix), Connection->Endpoint);
319 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
320 I_RpcFree(pname);
322 return r;
325 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
327 static const char prefix[] = "\\\\.";
328 RPC_STATUS r;
329 LPSTR pname;
330 RpcConnection *Connection;
331 char generated_endpoint[21];
333 if (!endpoint)
335 static LONG np_nameless_id;
336 DWORD process_id = GetCurrentProcessId();
337 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
338 snprintf(generated_endpoint, sizeof(generated_endpoint),
339 "\\\\pipe\\\\%08x.%03x", process_id, id);
340 endpoint = generated_endpoint;
343 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
344 endpoint, NULL, NULL, NULL);
345 if (r != RPC_S_OK)
346 return r;
348 /* protseq=ncacn_np: named pipes */
349 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
350 strcat(strcpy(pname, prefix), Connection->Endpoint);
351 r = rpcrt4_conn_create_pipe(Connection, pname);
352 I_RpcFree(pname);
354 EnterCriticalSection(&protseq->cs);
355 Connection->Next = protseq->conn;
356 protseq->conn = Connection;
357 LeaveCriticalSection(&protseq->cs);
359 return r;
362 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
364 /* because of the way named pipes work, we'll transfer the connected pipe
365 * to the child, then reopen the server binding to continue listening */
367 new_npc->pipe = old_npc->pipe;
368 new_npc->ovl = old_npc->ovl;
369 old_npc->pipe = 0;
370 memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
371 old_npc->listening = FALSE;
374 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
376 RPC_STATUS status;
377 LPSTR pname;
378 static const char prefix[] = "\\\\.";
380 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
382 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
383 strcat(strcpy(pname, prefix), old_conn->Endpoint);
384 status = rpcrt4_conn_create_pipe(old_conn, pname);
385 I_RpcFree(pname);
387 return status;
390 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
392 RPC_STATUS status;
393 LPSTR pname;
394 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
396 TRACE("%s\n", old_conn->Endpoint);
398 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
400 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
401 strcat(strcpy(pname, prefix), old_conn->Endpoint);
402 status = rpcrt4_conn_create_pipe(old_conn, pname);
403 I_RpcFree(pname);
405 return status;
408 static int rpcrt4_conn_np_read(RpcConnection *Connection,
409 void *buffer, unsigned int count)
411 RpcConnection_np *npc = (RpcConnection_np *) Connection;
412 char *buf = buffer;
413 BOOL ret = TRUE;
414 unsigned int bytes_left = count;
416 while (bytes_left)
418 DWORD bytes_read;
419 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
420 if (!ret && GetLastError() == ERROR_MORE_DATA)
421 ret = TRUE;
422 if (!ret || !bytes_read)
423 break;
424 bytes_left -= bytes_read;
425 buf += bytes_read;
427 return ret ? count : -1;
430 static int rpcrt4_conn_np_write(RpcConnection *Connection,
431 const void *buffer, unsigned int count)
433 RpcConnection_np *npc = (RpcConnection_np *) Connection;
434 const char *buf = buffer;
435 BOOL ret = TRUE;
436 unsigned int bytes_left = count;
438 while (bytes_left)
440 DWORD bytes_written;
441 ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, NULL);
442 if (!ret || !bytes_written)
443 break;
444 bytes_left -= bytes_written;
445 buf += bytes_written;
447 return ret ? count : -1;
450 static int rpcrt4_conn_np_close(RpcConnection *Connection)
452 RpcConnection_np *npc = (RpcConnection_np *) Connection;
453 if (npc->pipe) {
454 FlushFileBuffers(npc->pipe);
455 CloseHandle(npc->pipe);
456 npc->pipe = 0;
458 if (npc->ovl.hEvent) {
459 CloseHandle(npc->ovl.hEvent);
460 npc->ovl.hEvent = 0;
462 return 0;
465 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
467 /* FIXME: implement when named pipe writes use overlapped I/O */
470 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
472 /* FIXME: implement when named pipe writes use overlapped I/O */
473 return -1;
476 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
477 const char *networkaddr,
478 const char *endpoint)
480 twr_empty_floor_t *smb_floor;
481 twr_empty_floor_t *nb_floor;
482 size_t size;
483 size_t networkaddr_size;
484 size_t endpoint_size;
486 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
488 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
489 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
490 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
492 if (!tower_data)
493 return size;
495 smb_floor = (twr_empty_floor_t *)tower_data;
497 tower_data += sizeof(*smb_floor);
499 smb_floor->count_lhs = sizeof(smb_floor->protid);
500 smb_floor->protid = EPM_PROTOCOL_SMB;
501 smb_floor->count_rhs = endpoint_size;
503 if (endpoint)
504 memcpy(tower_data, endpoint, endpoint_size);
505 else
506 tower_data[0] = 0;
507 tower_data += endpoint_size;
509 nb_floor = (twr_empty_floor_t *)tower_data;
511 tower_data += sizeof(*nb_floor);
513 nb_floor->count_lhs = sizeof(nb_floor->protid);
514 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
515 nb_floor->count_rhs = networkaddr_size;
517 if (networkaddr)
518 memcpy(tower_data, networkaddr, networkaddr_size);
519 else
520 tower_data[0] = 0;
522 return size;
525 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
526 size_t tower_size,
527 char **networkaddr,
528 char **endpoint)
530 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
531 const twr_empty_floor_t *nb_floor;
533 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
535 if (tower_size < sizeof(*smb_floor))
536 return EPT_S_NOT_REGISTERED;
538 tower_data += sizeof(*smb_floor);
539 tower_size -= sizeof(*smb_floor);
541 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
542 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
543 (smb_floor->count_rhs > tower_size) ||
544 (tower_data[smb_floor->count_rhs - 1] != '\0'))
545 return EPT_S_NOT_REGISTERED;
547 if (endpoint)
549 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
550 if (!*endpoint)
551 return RPC_S_OUT_OF_RESOURCES;
552 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
554 tower_data += smb_floor->count_rhs;
555 tower_size -= smb_floor->count_rhs;
557 if (tower_size < sizeof(*nb_floor))
558 return EPT_S_NOT_REGISTERED;
560 nb_floor = (const twr_empty_floor_t *)tower_data;
562 tower_data += sizeof(*nb_floor);
563 tower_size -= sizeof(*nb_floor);
565 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
566 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
567 (nb_floor->count_rhs > tower_size) ||
568 (tower_data[nb_floor->count_rhs - 1] != '\0'))
569 return EPT_S_NOT_REGISTERED;
571 if (networkaddr)
573 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
574 if (!*networkaddr)
576 if (endpoint)
578 I_RpcFree(*endpoint);
579 *endpoint = NULL;
581 return RPC_S_OUT_OF_RESOURCES;
583 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
586 return RPC_S_OK;
589 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
591 RpcConnection_np *npc = (RpcConnection_np *)conn;
592 BOOL ret;
594 TRACE("(%p)\n", conn);
596 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
597 return RPCRT4_default_impersonate_client(conn);
599 ret = ImpersonateNamedPipeClient(npc->pipe);
600 if (!ret)
602 DWORD error = GetLastError();
603 WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
604 switch (error)
606 case ERROR_CANNOT_IMPERSONATE:
607 return RPC_S_NO_CONTEXT_AVAILABLE;
610 return RPC_S_OK;
613 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
615 BOOL ret;
617 TRACE("(%p)\n", conn);
619 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
620 return RPCRT4_default_revert_to_self(conn);
622 ret = RevertToSelf();
623 if (!ret)
625 WARN("RevertToSelf failed with error %u\n", GetLastError());
626 return RPC_S_NO_CONTEXT_AVAILABLE;
628 return RPC_S_OK;
631 typedef struct _RpcServerProtseq_np
633 RpcServerProtseq common;
634 HANDLE mgr_event;
635 } RpcServerProtseq_np;
637 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
639 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
640 if (ps)
641 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
642 return &ps->common;
645 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
647 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
648 SetEvent(npps->mgr_event);
651 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
653 HANDLE *objs = prev_array;
654 RpcConnection_np *conn;
655 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
657 EnterCriticalSection(&protseq->cs);
659 /* open and count connections */
660 *count = 1;
661 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
662 while (conn) {
663 rpcrt4_conn_listen_pipe(conn);
664 if (conn->ovl.hEvent)
665 (*count)++;
666 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
669 /* make array of connections */
670 if (objs)
671 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
672 else
673 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
674 if (!objs)
676 ERR("couldn't allocate objs\n");
677 LeaveCriticalSection(&protseq->cs);
678 return NULL;
681 objs[0] = npps->mgr_event;
682 *count = 1;
683 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
684 while (conn) {
685 if ((objs[*count] = conn->ovl.hEvent))
686 (*count)++;
687 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
689 LeaveCriticalSection(&protseq->cs);
690 return objs;
693 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
695 HeapFree(GetProcessHeap(), 0, array);
698 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
700 HANDLE b_handle;
701 HANDLE *objs = wait_array;
702 DWORD res;
703 RpcConnection *cconn;
704 RpcConnection_np *conn;
706 if (!objs)
707 return -1;
711 /* an alertable wait isn't strictly necessary, but due to our
712 * overlapped I/O implementation in Wine we need to free some memory
713 * by the file user APC being called, even if no completion routine was
714 * specified at the time of starting the async operation */
715 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
716 } while (res == WAIT_IO_COMPLETION);
718 if (res == WAIT_OBJECT_0)
719 return 0;
720 else if (res == WAIT_FAILED)
722 ERR("wait failed with error %d\n", GetLastError());
723 return -1;
725 else
727 b_handle = objs[res - WAIT_OBJECT_0];
728 /* find which connection got a RPC */
729 EnterCriticalSection(&protseq->cs);
730 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
731 while (conn) {
732 if (b_handle == conn->ovl.hEvent) break;
733 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
735 cconn = NULL;
736 if (conn)
737 RPCRT4_SpawnConnection(&cconn, &conn->common);
738 else
739 ERR("failed to locate connection for handle %p\n", b_handle);
740 LeaveCriticalSection(&protseq->cs);
741 if (cconn)
743 RPCRT4_new_client(cconn);
744 return 1;
746 else return -1;
750 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
751 const char *networkaddr,
752 const char *endpoint)
754 twr_empty_floor_t *pipe_floor;
755 size_t size;
756 size_t endpoint_size;
758 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
760 endpoint_size = strlen(endpoint) + 1;
761 size = sizeof(*pipe_floor) + endpoint_size;
763 if (!tower_data)
764 return size;
766 pipe_floor = (twr_empty_floor_t *)tower_data;
768 tower_data += sizeof(*pipe_floor);
770 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
771 pipe_floor->protid = EPM_PROTOCOL_PIPE;
772 pipe_floor->count_rhs = endpoint_size;
774 memcpy(tower_data, endpoint, endpoint_size);
776 return size;
779 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
780 size_t tower_size,
781 char **networkaddr,
782 char **endpoint)
784 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
786 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
788 if (tower_size < sizeof(*pipe_floor))
789 return EPT_S_NOT_REGISTERED;
791 tower_data += sizeof(*pipe_floor);
792 tower_size -= sizeof(*pipe_floor);
794 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
795 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
796 (pipe_floor->count_rhs > tower_size) ||
797 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
798 return EPT_S_NOT_REGISTERED;
800 if (networkaddr)
801 *networkaddr = NULL;
803 if (endpoint)
805 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
806 if (!*endpoint)
807 return RPC_S_OUT_OF_RESOURCES;
808 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
811 return RPC_S_OK;
814 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
816 return FALSE;
819 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
820 unsigned char *in_buffer,
821 unsigned int in_size,
822 unsigned char *out_buffer,
823 unsigned int *out_size)
825 /* since this protocol is local to the machine there is no need to
826 * authenticate the caller */
827 *out_size = 0;
828 return RPC_S_OK;
831 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
832 enum secure_packet_direction dir,
833 RpcPktHdr *hdr, unsigned int hdr_size,
834 unsigned char *stub_data, unsigned int stub_data_size,
835 RpcAuthVerifier *auth_hdr,
836 unsigned char *auth_value, unsigned int auth_value_size)
838 /* since this protocol is local to the machine there is no need to secure
839 * the packet */
840 return RPC_S_OK;
843 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
844 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
845 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
847 TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
848 server_princ_name, authn_level, authn_svc, authz_svc, flags);
850 if (privs)
852 FIXME("privs not implemented\n");
853 *privs = NULL;
855 if (server_princ_name)
857 FIXME("server_princ_name not implemented\n");
858 *server_princ_name = NULL;
860 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
861 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
862 if (authz_svc)
864 FIXME("authorization service not implemented\n");
865 *authz_svc = RPC_C_AUTHZ_NONE;
867 if (flags)
868 FIXME("flags 0x%x not implemented\n", flags);
870 return RPC_S_OK;
873 /**** ncacn_ip_tcp support ****/
875 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
876 const char *networkaddr,
877 unsigned char tcp_protid,
878 const char *endpoint)
880 twr_tcp_floor_t *tcp_floor;
881 twr_ipv4_floor_t *ipv4_floor;
882 struct addrinfo *ai;
883 struct addrinfo hints;
884 int ret;
885 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
887 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
889 if (!tower_data)
890 return size;
892 tcp_floor = (twr_tcp_floor_t *)tower_data;
893 tower_data += sizeof(*tcp_floor);
895 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
897 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
898 tcp_floor->protid = tcp_protid;
899 tcp_floor->count_rhs = sizeof(tcp_floor->port);
901 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
902 ipv4_floor->protid = EPM_PROTOCOL_IP;
903 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
905 hints.ai_flags = AI_NUMERICHOST;
906 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
907 hints.ai_family = PF_INET;
908 hints.ai_socktype = SOCK_STREAM;
909 hints.ai_protocol = IPPROTO_TCP;
910 hints.ai_addrlen = 0;
911 hints.ai_addr = NULL;
912 hints.ai_canonname = NULL;
913 hints.ai_next = NULL;
915 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
916 if (ret)
918 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
919 if (ret)
921 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
922 return 0;
926 if (ai->ai_family == PF_INET)
928 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
929 tcp_floor->port = sin->sin_port;
930 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
932 else
934 ERR("unexpected protocol family %d\n", ai->ai_family);
935 return 0;
938 freeaddrinfo(ai);
940 return size;
943 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
944 size_t tower_size,
945 char **networkaddr,
946 unsigned char tcp_protid,
947 char **endpoint)
949 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
950 const twr_ipv4_floor_t *ipv4_floor;
951 struct in_addr in_addr;
953 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
955 if (tower_size < sizeof(*tcp_floor))
956 return EPT_S_NOT_REGISTERED;
958 tower_data += sizeof(*tcp_floor);
959 tower_size -= sizeof(*tcp_floor);
961 if (tower_size < sizeof(*ipv4_floor))
962 return EPT_S_NOT_REGISTERED;
964 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
966 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
967 (tcp_floor->protid != tcp_protid) ||
968 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
969 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
970 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
971 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
972 return EPT_S_NOT_REGISTERED;
974 if (endpoint)
976 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
977 if (!*endpoint)
978 return RPC_S_OUT_OF_RESOURCES;
979 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
982 if (networkaddr)
984 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
985 if (!*networkaddr)
987 if (endpoint)
989 I_RpcFree(*endpoint);
990 *endpoint = NULL;
992 return RPC_S_OUT_OF_RESOURCES;
994 in_addr.s_addr = ipv4_floor->ipv4addr;
995 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
997 ERR("inet_ntop: %s\n", strerror(errno));
998 I_RpcFree(*networkaddr);
999 *networkaddr = NULL;
1000 if (endpoint)
1002 I_RpcFree(*endpoint);
1003 *endpoint = NULL;
1005 return EPT_S_NOT_REGISTERED;
1009 return RPC_S_OK;
1012 typedef struct _RpcConnection_tcp
1014 RpcConnection common;
1015 int sock;
1016 #ifdef HAVE_SOCKETPAIR
1017 int cancel_fds[2];
1018 #else
1019 HANDLE sock_event;
1020 HANDLE cancel_event;
1021 #endif
1022 } RpcConnection_tcp;
1024 #ifdef HAVE_SOCKETPAIR
1026 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1028 if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
1030 ERR("socketpair() failed: %s\n", strerror(errno));
1031 return FALSE;
1033 return TRUE;
1036 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1038 struct pollfd pfds[2];
1039 pfds[0].fd = tcpc->sock;
1040 pfds[0].events = POLLIN;
1041 pfds[1].fd = tcpc->cancel_fds[0];
1042 pfds[1].events = POLLIN;
1043 if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
1045 ERR("poll() failed: %s\n", strerror(errno));
1046 return FALSE;
1048 if (pfds[1].revents & POLLIN) /* canceled */
1050 char dummy;
1051 read(pfds[1].fd, &dummy, sizeof(dummy));
1052 return FALSE;
1054 return TRUE;
1057 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1059 struct pollfd pfd;
1060 pfd.fd = tcpc->sock;
1061 pfd.events = POLLOUT;
1062 if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
1064 ERR("poll() failed: %s\n", strerror(errno));
1065 return FALSE;
1067 return TRUE;
1070 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1072 char dummy = 1;
1074 write(tcpc->cancel_fds[1], &dummy, 1);
1077 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1079 close(tcpc->cancel_fds[0]);
1080 close(tcpc->cancel_fds[1]);
1083 #else /* HAVE_SOCKETPAIR */
1085 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1087 static BOOL wsa_inited;
1088 if (!wsa_inited)
1090 WSADATA wsadata;
1091 WSAStartup(MAKEWORD(2, 2), &wsadata);
1092 /* Note: WSAStartup can be called more than once so we don't bother with
1093 * making accesses to wsa_inited thread-safe */
1094 wsa_inited = TRUE;
1096 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1097 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1098 if (!tcpc->sock_event || !tcpc->cancel_event)
1100 ERR("event creation failed\n");
1101 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1102 return FALSE;
1104 return TRUE;
1107 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1109 HANDLE wait_handles[2];
1110 DWORD res;
1111 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1113 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1114 return FALSE;
1116 wait_handles[0] = tcpc->sock_event;
1117 wait_handles[1] = tcpc->cancel_event;
1118 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1119 switch (res)
1121 case WAIT_OBJECT_0:
1122 return TRUE;
1123 case WAIT_OBJECT_0 + 1:
1124 return FALSE;
1125 default:
1126 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1127 return FALSE;
1131 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1133 DWORD res;
1134 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1136 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1137 return FALSE;
1139 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1140 switch (res)
1142 case WAIT_OBJECT_0:
1143 return TRUE;
1144 default:
1145 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1146 return FALSE;
1150 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1152 SetEvent(tcpc->cancel_event);
1155 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1157 CloseHandle(tcpc->sock_event);
1158 CloseHandle(tcpc->cancel_event);
1161 #endif
1163 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1165 RpcConnection_tcp *tcpc;
1166 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
1167 if (tcpc == NULL)
1168 return NULL;
1169 tcpc->sock = -1;
1170 if (!rpcrt4_sock_wait_init(tcpc))
1172 HeapFree(GetProcessHeap(), 0, tcpc);
1173 return NULL;
1175 return &tcpc->common;
1178 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1180 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1181 int sock;
1182 int ret;
1183 struct addrinfo *ai;
1184 struct addrinfo *ai_cur;
1185 struct addrinfo hints;
1187 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1189 if (tcpc->sock != -1)
1190 return RPC_S_OK;
1192 hints.ai_flags = 0;
1193 hints.ai_family = PF_UNSPEC;
1194 hints.ai_socktype = SOCK_STREAM;
1195 hints.ai_protocol = IPPROTO_TCP;
1196 hints.ai_addrlen = 0;
1197 hints.ai_addr = NULL;
1198 hints.ai_canonname = NULL;
1199 hints.ai_next = NULL;
1201 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1202 if (ret)
1204 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1205 Connection->Endpoint, gai_strerror(ret));
1206 return RPC_S_SERVER_UNAVAILABLE;
1209 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1211 int val;
1212 u_long nonblocking;
1214 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1216 TRACE("skipping non-IP/IPv6 address family\n");
1217 continue;
1220 if (TRACE_ON(rpc))
1222 char host[256];
1223 char service[256];
1224 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1225 host, sizeof(host), service, sizeof(service),
1226 NI_NUMERICHOST | NI_NUMERICSERV);
1227 TRACE("trying %s:%s\n", host, service);
1230 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1231 if (sock == -1)
1233 WARN("socket() failed: %s\n", strerror(errno));
1234 continue;
1237 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1239 WARN("connect() failed: %s\n", strerror(errno));
1240 closesocket(sock);
1241 continue;
1244 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1245 val = 1;
1246 setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1247 nonblocking = 1;
1248 ioctlsocket(sock, FIONBIO, &nonblocking);
1250 tcpc->sock = sock;
1252 freeaddrinfo(ai);
1253 TRACE("connected\n");
1254 return RPC_S_OK;
1257 freeaddrinfo(ai);
1258 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1259 return RPC_S_SERVER_UNAVAILABLE;
1262 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1264 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1265 int sock;
1266 int ret;
1267 struct addrinfo *ai;
1268 struct addrinfo *ai_cur;
1269 struct addrinfo hints;
1270 RpcConnection *first_connection = NULL;
1272 TRACE("(%p, %s)\n", protseq, endpoint);
1274 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1275 hints.ai_family = PF_UNSPEC;
1276 hints.ai_socktype = SOCK_STREAM;
1277 hints.ai_protocol = IPPROTO_TCP;
1278 hints.ai_addrlen = 0;
1279 hints.ai_addr = NULL;
1280 hints.ai_canonname = NULL;
1281 hints.ai_next = NULL;
1283 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1284 if (ret)
1286 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1287 gai_strerror(ret));
1288 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1289 return RPC_S_INVALID_ENDPOINT_FORMAT;
1290 return RPC_S_CANT_CREATE_ENDPOINT;
1293 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1295 RpcConnection_tcp *tcpc;
1296 RPC_STATUS create_status;
1297 struct sockaddr_storage sa;
1298 socklen_t sa_len;
1299 char service[NI_MAXSERV];
1300 u_long nonblocking;
1302 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1304 TRACE("skipping non-IP/IPv6 address family\n");
1305 continue;
1308 if (TRACE_ON(rpc))
1310 char host[256];
1311 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1312 host, sizeof(host), service, sizeof(service),
1313 NI_NUMERICHOST | NI_NUMERICSERV);
1314 TRACE("trying %s:%s\n", host, service);
1317 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1318 if (sock == -1)
1320 WARN("socket() failed: %s\n", strerror(errno));
1321 status = RPC_S_CANT_CREATE_ENDPOINT;
1322 continue;
1325 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1326 if (ret < 0)
1328 WARN("bind failed: %s\n", strerror(errno));
1329 closesocket(sock);
1330 if (errno == EADDRINUSE)
1331 status = RPC_S_DUPLICATE_ENDPOINT;
1332 else
1333 status = RPC_S_CANT_CREATE_ENDPOINT;
1334 continue;
1337 sa_len = sizeof(sa);
1338 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1340 WARN("getsockname() failed: %s\n", strerror(errno));
1341 status = RPC_S_CANT_CREATE_ENDPOINT;
1342 continue;
1345 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1346 NULL, 0, service, sizeof(service),
1347 NI_NUMERICSERV);
1348 if (ret)
1350 WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1351 status = RPC_S_CANT_CREATE_ENDPOINT;
1352 continue;
1355 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1356 protseq->Protseq, NULL,
1357 service, NULL, NULL, NULL);
1358 if (create_status != RPC_S_OK)
1360 closesocket(sock);
1361 status = create_status;
1362 continue;
1365 tcpc->sock = sock;
1366 ret = listen(sock, protseq->MaxCalls);
1367 if (ret < 0)
1369 WARN("listen failed: %s\n", strerror(errno));
1370 RPCRT4_DestroyConnection(&tcpc->common);
1371 status = RPC_S_OUT_OF_RESOURCES;
1372 continue;
1374 /* need a non-blocking socket, otherwise accept() has a potential
1375 * race-condition (poll() says it is readable, connection drops,
1376 * and accept() blocks until the next connection comes...)
1378 nonblocking = 1;
1379 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1380 if (ret < 0)
1382 WARN("couldn't make socket non-blocking, error %d\n", ret);
1383 RPCRT4_DestroyConnection(&tcpc->common);
1384 status = RPC_S_OUT_OF_RESOURCES;
1385 continue;
1388 tcpc->common.Next = first_connection;
1389 first_connection = &tcpc->common;
1391 /* since IPv4 and IPv6 share the same port space, we only need one
1392 * successful bind to listen for both */
1393 break;
1396 freeaddrinfo(ai);
1398 /* if at least one connection was created for an endpoint then
1399 * return success */
1400 if (first_connection)
1402 RpcConnection *conn;
1404 /* find last element in list */
1405 for (conn = first_connection; conn->Next; conn = conn->Next)
1408 EnterCriticalSection(&protseq->cs);
1409 conn->Next = protseq->conn;
1410 protseq->conn = first_connection;
1411 LeaveCriticalSection(&protseq->cs);
1413 TRACE("listening on %s\n", endpoint);
1414 return RPC_S_OK;
1417 ERR("couldn't listen on port %s\n", endpoint);
1418 return status;
1421 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1423 int ret;
1424 struct sockaddr_in address;
1425 socklen_t addrsize;
1426 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1427 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1428 u_long nonblocking;
1430 addrsize = sizeof(address);
1431 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1432 if (ret < 0)
1434 ERR("Failed to accept a TCP connection: error %d\n", ret);
1435 return RPC_S_OUT_OF_RESOURCES;
1437 nonblocking = 1;
1438 ioctlsocket(ret, FIONBIO, &nonblocking);
1439 client->sock = ret;
1440 TRACE("Accepted a new TCP connection\n");
1441 return RPC_S_OK;
1444 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1445 void *buffer, unsigned int count)
1447 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1448 int bytes_read = 0;
1449 while (bytes_read != count)
1451 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1452 if (!r)
1453 return -1;
1454 else if (r > 0)
1455 bytes_read += r;
1456 else if (errno != EAGAIN)
1458 WARN("recv() failed: %s\n", strerror(errno));
1459 return -1;
1461 else
1463 if (!rpcrt4_sock_wait_for_recv(tcpc))
1464 return -1;
1467 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1468 return bytes_read;
1471 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1472 const void *buffer, unsigned int count)
1474 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1475 int bytes_written = 0;
1476 while (bytes_written != count)
1478 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1479 if (r >= 0)
1480 bytes_written += r;
1481 else if (errno != EAGAIN)
1482 return -1;
1483 else
1485 if (!rpcrt4_sock_wait_for_send(tcpc))
1486 return -1;
1489 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1490 return bytes_written;
1493 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1495 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1497 TRACE("%d\n", tcpc->sock);
1499 if (tcpc->sock != -1)
1500 closesocket(tcpc->sock);
1501 tcpc->sock = -1;
1502 rpcrt4_sock_wait_destroy(tcpc);
1503 return 0;
1506 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1508 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1509 TRACE("%p\n", Connection);
1510 rpcrt4_sock_wait_cancel(tcpc);
1513 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1515 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1517 TRACE("%p\n", Connection);
1519 if (!rpcrt4_sock_wait_for_recv(tcpc))
1520 return -1;
1521 return 0;
1524 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1525 const char *networkaddr,
1526 const char *endpoint)
1528 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1529 EPM_PROTOCOL_TCP, endpoint);
1532 #ifdef HAVE_SOCKETPAIR
1534 typedef struct _RpcServerProtseq_sock
1536 RpcServerProtseq common;
1537 int mgr_event_rcv;
1538 int mgr_event_snd;
1539 } RpcServerProtseq_sock;
1541 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1543 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1544 if (ps)
1546 int fds[2];
1547 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1549 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1550 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1551 ps->mgr_event_rcv = fds[0];
1552 ps->mgr_event_snd = fds[1];
1554 else
1556 ERR("socketpair failed with error %s\n", strerror(errno));
1557 HeapFree(GetProcessHeap(), 0, ps);
1558 return NULL;
1561 return &ps->common;
1564 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1566 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1567 char dummy = 1;
1568 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1571 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1573 struct pollfd *poll_info = prev_array;
1574 RpcConnection_tcp *conn;
1575 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1577 EnterCriticalSection(&protseq->cs);
1579 /* open and count connections */
1580 *count = 1;
1581 conn = (RpcConnection_tcp *)protseq->conn;
1582 while (conn) {
1583 if (conn->sock != -1)
1584 (*count)++;
1585 conn = (RpcConnection_tcp *)conn->common.Next;
1588 /* make array of connections */
1589 if (poll_info)
1590 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1591 else
1592 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1593 if (!poll_info)
1595 ERR("couldn't allocate poll_info\n");
1596 LeaveCriticalSection(&protseq->cs);
1597 return NULL;
1600 poll_info[0].fd = sockps->mgr_event_rcv;
1601 poll_info[0].events = POLLIN;
1602 *count = 1;
1603 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1604 while (conn) {
1605 if (conn->sock != -1)
1607 poll_info[*count].fd = conn->sock;
1608 poll_info[*count].events = POLLIN;
1609 (*count)++;
1611 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1613 LeaveCriticalSection(&protseq->cs);
1614 return poll_info;
1617 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1619 HeapFree(GetProcessHeap(), 0, array);
1622 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1624 struct pollfd *poll_info = wait_array;
1625 int ret;
1626 unsigned int i;
1627 RpcConnection *cconn;
1628 RpcConnection_tcp *conn;
1630 if (!poll_info)
1631 return -1;
1633 ret = poll(poll_info, count, -1);
1634 if (ret < 0)
1636 ERR("poll failed with error %d\n", ret);
1637 return -1;
1640 for (i = 0; i < count; i++)
1641 if (poll_info[i].revents & POLLIN)
1643 /* RPC server event */
1644 if (i == 0)
1646 char dummy;
1647 read(poll_info[0].fd, &dummy, sizeof(dummy));
1648 return 0;
1651 /* find which connection got a RPC */
1652 EnterCriticalSection(&protseq->cs);
1653 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1654 while (conn) {
1655 if (poll_info[i].fd == conn->sock) break;
1656 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1658 cconn = NULL;
1659 if (conn)
1660 RPCRT4_SpawnConnection(&cconn, &conn->common);
1661 else
1662 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1663 LeaveCriticalSection(&protseq->cs);
1664 if (cconn)
1665 RPCRT4_new_client(cconn);
1666 else
1667 return -1;
1670 return 1;
1673 #else /* HAVE_SOCKETPAIR */
1675 typedef struct _RpcServerProtseq_sock
1677 RpcServerProtseq common;
1678 HANDLE mgr_event;
1679 } RpcServerProtseq_sock;
1681 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1683 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1684 if (ps)
1686 static BOOL wsa_inited;
1687 if (!wsa_inited)
1689 WSADATA wsadata;
1690 WSAStartup(MAKEWORD(2, 2), &wsadata);
1691 /* Note: WSAStartup can be called more than once so we don't bother with
1692 * making accesses to wsa_inited thread-safe */
1693 wsa_inited = TRUE;
1695 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1697 return &ps->common;
1700 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1702 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1703 SetEvent(sockps->mgr_event);
1706 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1708 HANDLE *objs = prev_array;
1709 RpcConnection_tcp *conn;
1710 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1712 EnterCriticalSection(&protseq->cs);
1714 /* open and count connections */
1715 *count = 1;
1716 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1717 while (conn)
1719 if (conn->sock != -1)
1720 (*count)++;
1721 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1724 /* make array of connections */
1725 if (objs)
1726 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1727 else
1728 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1729 if (!objs)
1731 ERR("couldn't allocate objs\n");
1732 LeaveCriticalSection(&protseq->cs);
1733 return NULL;
1736 objs[0] = sockps->mgr_event;
1737 *count = 1;
1738 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1739 while (conn)
1741 if (conn->sock != -1)
1743 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1744 if (res == SOCKET_ERROR)
1745 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1746 else
1748 objs[*count] = conn->sock_event;
1749 (*count)++;
1752 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1754 LeaveCriticalSection(&protseq->cs);
1755 return objs;
1758 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1760 HeapFree(GetProcessHeap(), 0, array);
1763 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1765 HANDLE b_handle;
1766 HANDLE *objs = wait_array;
1767 DWORD res;
1768 RpcConnection *cconn;
1769 RpcConnection_tcp *conn;
1771 if (!objs)
1772 return -1;
1776 /* an alertable wait isn't strictly necessary, but due to our
1777 * overlapped I/O implementation in Wine we need to free some memory
1778 * by the file user APC being called, even if no completion routine was
1779 * specified at the time of starting the async operation */
1780 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1781 } while (res == WAIT_IO_COMPLETION);
1783 if (res == WAIT_OBJECT_0)
1784 return 0;
1785 else if (res == WAIT_FAILED)
1787 ERR("wait failed with error %d\n", GetLastError());
1788 return -1;
1790 else
1792 b_handle = objs[res - WAIT_OBJECT_0];
1793 /* find which connection got a RPC */
1794 EnterCriticalSection(&protseq->cs);
1795 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1796 while (conn)
1798 if (b_handle == conn->sock_event) break;
1799 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1801 cconn = NULL;
1802 if (conn)
1803 RPCRT4_SpawnConnection(&cconn, &conn->common);
1804 else
1805 ERR("failed to locate connection for handle %p\n", b_handle);
1806 LeaveCriticalSection(&protseq->cs);
1807 if (cconn)
1809 RPCRT4_new_client(cconn);
1810 return 1;
1812 else return -1;
1816 #endif /* HAVE_SOCKETPAIR */
1818 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1819 size_t tower_size,
1820 char **networkaddr,
1821 char **endpoint)
1823 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1824 networkaddr, EPM_PROTOCOL_TCP,
1825 endpoint);
1828 /**** ncacn_http support ****/
1830 /* 60 seconds is the period native uses */
1831 #define HTTP_IDLE_TIME 60000
1833 /* reference counted to avoid a race between a cancelled call's connection
1834 * being destroyed and the asynchronous InternetReadFileEx call being
1835 * completed */
1836 typedef struct _RpcHttpAsyncData
1838 LONG refs;
1839 HANDLE completion_event;
1840 INTERNET_BUFFERSA inet_buffers;
1841 void *destination_buffer; /* the address that inet_buffers.lpvBuffer will be
1842 * copied into when the call completes */
1843 CRITICAL_SECTION cs;
1844 } RpcHttpAsyncData;
1846 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1848 return InterlockedIncrement(&data->refs);
1851 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1853 ULONG refs = InterlockedDecrement(&data->refs);
1854 if (!refs)
1856 TRACE("destroying async data %p\n", data);
1857 CloseHandle(data->completion_event);
1858 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1859 DeleteCriticalSection(&data->cs);
1860 HeapFree(GetProcessHeap(), 0, data);
1862 return refs;
1865 typedef struct _RpcConnection_http
1867 RpcConnection common;
1868 HINTERNET app_info;
1869 HINTERNET session;
1870 HINTERNET in_request;
1871 HINTERNET out_request;
1872 HANDLE timer_cancelled;
1873 HANDLE cancel_event;
1874 DWORD last_sent_time;
1875 ULONG bytes_received;
1876 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1877 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1878 UUID connection_uuid;
1879 UUID in_pipe_uuid;
1880 UUID out_pipe_uuid;
1881 RpcHttpAsyncData *async_data;
1882 } RpcConnection_http;
1884 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1886 RpcConnection_http *httpc;
1887 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1888 if (!httpc) return NULL;
1889 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1890 if (!httpc->async_data)
1892 HeapFree(GetProcessHeap(), 0, httpc);
1893 return NULL;
1895 TRACE("async data = %p\n", httpc->async_data);
1896 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1897 httpc->async_data->refs = 1;
1898 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
1899 httpc->async_data->inet_buffers.lpvBuffer = NULL;
1900 httpc->async_data->destination_buffer = NULL;
1901 InitializeCriticalSection(&httpc->async_data->cs);
1902 return &httpc->common;
1905 typedef struct _HttpTimerThreadData
1907 PVOID timer_param;
1908 DWORD *last_sent_time;
1909 HANDLE timer_cancelled;
1910 } HttpTimerThreadData;
1912 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1914 HINTERNET in_request = param;
1915 RpcPktHdr *idle_pkt;
1917 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1918 0, 0);
1919 if (idle_pkt)
1921 DWORD bytes_written;
1922 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1923 RPCRT4_FreeHeader(idle_pkt);
1927 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1929 DWORD cur_time = GetTickCount();
1930 DWORD cached_last_sent_time = *last_sent_time;
1931 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1934 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1936 HttpTimerThreadData *data_in = param;
1937 HttpTimerThreadData data;
1938 DWORD timeout;
1940 data = *data_in;
1941 HeapFree(GetProcessHeap(), 0, data_in);
1943 for (timeout = HTTP_IDLE_TIME;
1944 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1945 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1947 /* are we too soon after last send? */
1948 if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time)
1949 continue;
1950 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1953 CloseHandle(data.timer_cancelled);
1954 return 0;
1957 static VOID WINAPI rpcrt4_http_internet_callback(
1958 HINTERNET hInternet,
1959 DWORD_PTR dwContext,
1960 DWORD dwInternetStatus,
1961 LPVOID lpvStatusInformation,
1962 DWORD dwStatusInformationLength)
1964 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1966 switch (dwInternetStatus)
1968 case INTERNET_STATUS_REQUEST_COMPLETE:
1969 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1970 if (async_data)
1972 if (async_data->inet_buffers.lpvBuffer)
1974 EnterCriticalSection(&async_data->cs);
1975 if (async_data->destination_buffer)
1977 memcpy(async_data->destination_buffer,
1978 async_data->inet_buffers.lpvBuffer,
1979 async_data->inet_buffers.dwBufferLength);
1980 async_data->destination_buffer = NULL;
1982 LeaveCriticalSection(&async_data->cs);
1984 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
1985 async_data->inet_buffers.lpvBuffer = NULL;
1986 SetEvent(async_data->completion_event);
1987 RpcHttpAsyncData_Release(async_data);
1989 break;
1993 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1995 BOOL ret;
1996 DWORD status_code;
1997 DWORD size;
1998 DWORD index;
1999 WCHAR buf[32];
2000 WCHAR *status_text = buf;
2001 TRACE("\n");
2003 index = 0;
2004 size = sizeof(status_code);
2005 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
2006 if (!ret)
2007 return GetLastError();
2008 if (status_code < 400)
2009 return RPC_S_OK;
2010 index = 0;
2011 size = sizeof(buf);
2012 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2013 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2015 status_text = HeapAlloc(GetProcessHeap(), 0, size);
2016 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
2019 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
2020 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
2022 if (status_code == HTTP_STATUS_DENIED)
2023 return ERROR_ACCESS_DENIED;
2024 return RPC_S_SERVER_UNAVAILABLE;
2027 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
2029 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
2030 LPWSTR proxy = NULL;
2031 LPWSTR user = NULL;
2032 LPWSTR password = NULL;
2033 LPWSTR servername = NULL;
2034 const WCHAR *option;
2035 INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */
2037 if (httpc->common.QOS &&
2038 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
2040 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
2041 if (http_cred->TransportCredentials)
2043 WCHAR *p;
2044 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
2045 ULONG len = cred->DomainLength + 1 + cred->UserLength;
2046 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2047 if (!user)
2048 return RPC_S_OUT_OF_RESOURCES;
2049 p = user;
2050 if (cred->DomainLength)
2052 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
2053 p += cred->DomainLength;
2054 *p = '\\';
2055 p++;
2057 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
2058 p[cred->UserLength] = 0;
2060 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
2064 for (option = httpc->common.NetworkOptions; option;
2065 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
2067 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
2068 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
2070 if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
2072 const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
2073 const WCHAR *value_end;
2074 const WCHAR *p;
2076 value_end = strchrW(option, ',');
2077 if (!value_end)
2078 value_end = value_start + strlenW(value_start);
2079 for (p = value_start; p < value_end; p++)
2080 if (*p == ':')
2082 port = atoiW(p+1);
2083 value_end = p;
2084 break;
2086 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2087 servername = RPCRT4_strndupW(value_start, value_end-value_start);
2089 else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
2091 const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
2092 const WCHAR *value_end;
2094 value_end = strchrW(option, ',');
2095 if (!value_end)
2096 value_end = value_start + strlenW(value_start);
2097 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2098 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
2100 else
2101 FIXME("unhandled option %s\n", debugstr_w(option));
2104 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
2105 NULL, NULL, INTERNET_FLAG_ASYNC);
2106 if (!httpc->app_info)
2108 HeapFree(GetProcessHeap(), 0, password);
2109 HeapFree(GetProcessHeap(), 0, user);
2110 ERR("InternetOpenW failed with error %d\n", GetLastError());
2111 return RPC_S_SERVER_UNAVAILABLE;
2113 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
2115 /* if no RpcProxy option specified, set the HTTP server address to the
2116 * RPC server address */
2117 if (!servername)
2119 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
2120 if (!servername)
2122 HeapFree(GetProcessHeap(), 0, password);
2123 HeapFree(GetProcessHeap(), 0, user);
2124 return RPC_S_OUT_OF_RESOURCES;
2126 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
2129 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
2130 INTERNET_SERVICE_HTTP, 0, 0);
2132 HeapFree(GetProcessHeap(), 0, password);
2133 HeapFree(GetProcessHeap(), 0, user);
2134 HeapFree(GetProcessHeap(), 0, servername);
2136 if (!httpc->session)
2138 ERR("InternetConnectW failed with error %d\n", GetLastError());
2139 return RPC_S_SERVER_UNAVAILABLE;
2142 return RPC_S_OK;
2145 /* prepare the in pipe for use by RPC packets */
2146 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data,
2147 const UUID *connection_uuid,
2148 const UUID *in_pipe_uuid,
2149 const UUID *association_uuid)
2151 BYTE packet[44];
2152 BOOL ret;
2153 RPC_STATUS status;
2154 RpcPktHdr *hdr;
2155 INTERNET_BUFFERSW buffers_in;
2156 DWORD bytes_read, bytes_written;
2158 /* prepare in pipe */
2159 ResetEvent(async_data->completion_event);
2160 RpcHttpAsyncData_AddRef(async_data);
2161 ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0);
2162 if (!ret)
2164 if (GetLastError() == ERROR_IO_PENDING)
2165 WaitForSingleObject(async_data->completion_event, INFINITE);
2166 else
2168 RpcHttpAsyncData_Release(async_data);
2169 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2170 return RPC_S_SERVER_UNAVAILABLE;
2173 status = rpcrt4_http_check_response(in_request);
2174 if (status != RPC_S_OK) return status;
2176 InternetReadFile(in_request, packet, 20, &bytes_read);
2177 /* FIXME: do something with retrieved data */
2179 memset(&buffers_in, 0, sizeof(buffers_in));
2180 buffers_in.dwStructSize = sizeof(buffers_in);
2181 /* FIXME: get this from the registry */
2182 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2183 ResetEvent(async_data->completion_event);
2184 RpcHttpAsyncData_AddRef(async_data);
2185 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2186 if (!ret)
2188 if (GetLastError() == ERROR_IO_PENDING)
2189 WaitForSingleObject(async_data->completion_event, INFINITE);
2190 else
2192 RpcHttpAsyncData_Release(async_data);
2193 ERR("HttpSendRequestExW failed with error %d\n", GetLastError());
2194 return RPC_S_SERVER_UNAVAILABLE;
2198 TRACE("sending HTTP connect header to server\n");
2199 hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2200 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2201 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2202 RPCRT4_FreeHeader(hdr);
2203 if (!ret)
2205 ERR("InternetWriteFile failed with error %d\n", GetLastError());
2206 return RPC_S_SERVER_UNAVAILABLE;
2209 return RPC_S_OK;
2212 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data)
2214 BOOL ret;
2215 DWORD bytes_read;
2216 unsigned short data_len;
2218 ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read);
2219 if (!ret)
2220 return RPC_S_SERVER_UNAVAILABLE;
2221 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2223 ERR("wrong packet type received %d or wrong frag_len %d\n",
2224 hdr->common.ptype, hdr->common.frag_len);
2225 return RPC_S_PROTOCOL_ERROR;
2228 ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read);
2229 if (!ret)
2230 return RPC_S_SERVER_UNAVAILABLE;
2232 data_len = hdr->common.frag_len - sizeof(hdr->http);
2233 if (data_len)
2235 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2236 if (!*data)
2237 return RPC_S_OUT_OF_RESOURCES;
2238 ret = InternetReadFile(request, *data, data_len, &bytes_read);
2239 if (!ret)
2241 HeapFree(GetProcessHeap(), 0, *data);
2242 return RPC_S_SERVER_UNAVAILABLE;
2245 else
2246 *data = NULL;
2248 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2250 ERR("invalid http packet\n");
2251 return RPC_S_PROTOCOL_ERROR;
2254 return RPC_S_OK;
2257 /* prepare the out pipe for use by RPC packets */
2258 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
2259 RpcHttpAsyncData *async_data,
2260 const UUID *connection_uuid,
2261 const UUID *out_pipe_uuid,
2262 ULONG *flow_control_increment)
2264 BYTE packet[20];
2265 BOOL ret;
2266 RPC_STATUS status;
2267 RpcPktHdr *hdr;
2268 DWORD bytes_read;
2269 BYTE *data_from_server;
2270 RpcPktHdr pkt_from_server;
2271 ULONG field1, field3;
2273 ResetEvent(async_data->completion_event);
2274 RpcHttpAsyncData_AddRef(async_data);
2275 ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0);
2276 if (!ret)
2278 if (GetLastError() == ERROR_IO_PENDING)
2279 WaitForSingleObject(async_data->completion_event, INFINITE);
2280 else
2282 RpcHttpAsyncData_Release(async_data);
2283 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2284 return RPC_S_SERVER_UNAVAILABLE;
2287 status = rpcrt4_http_check_response(out_request);
2288 if (status != RPC_S_OK) return status;
2290 InternetReadFile(out_request, packet, 20, &bytes_read);
2291 /* FIXME: do something with retrieved data */
2293 hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid, NULL);
2294 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2295 ResetEvent(async_data->completion_event);
2296 RpcHttpAsyncData_AddRef(async_data);
2297 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2298 if (!ret)
2300 if (GetLastError() == ERROR_IO_PENDING)
2301 WaitForSingleObject(async_data->completion_event, INFINITE);
2302 else
2304 RpcHttpAsyncData_Release(async_data);
2305 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2306 RPCRT4_FreeHeader(hdr);
2307 return RPC_S_SERVER_UNAVAILABLE;
2310 RPCRT4_FreeHeader(hdr);
2311 status = rpcrt4_http_check_response(out_request);
2312 if (status != RPC_S_OK) return status;
2314 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2315 &data_from_server);
2316 if (status != RPC_S_OK) return status;
2317 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2318 &field1);
2319 HeapFree(GetProcessHeap(), 0, data_from_server);
2320 if (status != RPC_S_OK) return status;
2321 TRACE("received (%d) from first prepare header\n", field1);
2323 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2324 &data_from_server);
2325 if (status != RPC_S_OK) return status;
2326 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2327 &field1, flow_control_increment,
2328 &field3);
2329 HeapFree(GetProcessHeap(), 0, data_from_server);
2330 if (status != RPC_S_OK) return status;
2331 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2333 return RPC_S_OK;
2336 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2338 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2339 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2340 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2341 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2342 static const WCHAR wszColon[] = {':',0};
2343 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2344 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2345 WCHAR *url;
2346 RPC_STATUS status;
2347 BOOL secure;
2348 HttpTimerThreadData *timer_data;
2349 HANDLE thread;
2351 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2353 if (Connection->server)
2355 ERR("ncacn_http servers not supported yet\n");
2356 return RPC_S_SERVER_UNAVAILABLE;
2359 if (httpc->in_request)
2360 return RPC_S_OK;
2362 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2364 status = UuidCreate(&httpc->connection_uuid);
2365 status = UuidCreate(&httpc->in_pipe_uuid);
2366 status = UuidCreate(&httpc->out_pipe_uuid);
2368 status = rpcrt4_http_internet_connect(httpc);
2369 if (status != RPC_S_OK)
2370 return status;
2372 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2373 if (!url)
2374 return RPC_S_OUT_OF_MEMORY;
2375 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2376 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
2377 strcatW(url, wszColon);
2378 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
2380 secure = httpc->common.QOS &&
2381 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2382 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2384 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL,
2385 wszAcceptTypes,
2386 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2387 (DWORD_PTR)httpc->async_data);
2388 if (!httpc->in_request)
2390 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2391 return RPC_S_SERVER_UNAVAILABLE;
2393 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL,
2394 wszAcceptTypes,
2395 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2396 (DWORD_PTR)httpc->async_data);
2397 if (!httpc->out_request)
2399 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2400 return RPC_S_SERVER_UNAVAILABLE;
2403 status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
2404 httpc->async_data,
2405 &httpc->connection_uuid,
2406 &httpc->in_pipe_uuid,
2407 &Connection->assoc->http_uuid);
2408 if (status != RPC_S_OK)
2409 return status;
2411 status = rpcrt4_http_prepare_out_pipe(httpc->out_request,
2412 httpc->async_data,
2413 &httpc->connection_uuid,
2414 &httpc->out_pipe_uuid,
2415 &httpc->flow_control_increment);
2416 if (status != RPC_S_OK)
2417 return status;
2419 httpc->flow_control_mark = httpc->flow_control_increment / 2;
2420 httpc->last_sent_time = GetTickCount();
2421 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2423 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2424 if (!timer_data)
2425 return ERROR_OUTOFMEMORY;
2426 timer_data->timer_param = httpc->in_request;
2427 timer_data->last_sent_time = &httpc->last_sent_time;
2428 timer_data->timer_cancelled = httpc->timer_cancelled;
2429 /* FIXME: should use CreateTimerQueueTimer when implemented */
2430 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2431 if (!thread)
2433 HeapFree(GetProcessHeap(), 0, timer_data);
2434 return GetLastError();
2436 CloseHandle(thread);
2438 return RPC_S_OK;
2441 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2443 assert(0);
2444 return RPC_S_SERVER_UNAVAILABLE;
2447 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2448 void *buffer, unsigned int count)
2450 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2451 char *buf = buffer;
2452 BOOL ret = TRUE;
2453 unsigned int bytes_left = count;
2455 ResetEvent(httpc->async_data->completion_event);
2456 while (bytes_left)
2458 RpcHttpAsyncData_AddRef(httpc->async_data);
2459 httpc->async_data->inet_buffers.dwBufferLength = bytes_left;
2460 httpc->async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, bytes_left);
2461 httpc->async_data->destination_buffer = buf;
2462 ret = InternetReadFileExA(httpc->out_request, &httpc->async_data->inet_buffers, IRF_ASYNC, 0);
2463 if (ret)
2465 /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2466 * async ref now */
2467 RpcHttpAsyncData_Release(httpc->async_data);
2468 memcpy(buf, httpc->async_data->inet_buffers.lpvBuffer,
2469 httpc->async_data->inet_buffers.dwBufferLength);
2470 HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2471 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2472 httpc->async_data->destination_buffer = NULL;
2474 else
2476 if (GetLastError() == ERROR_IO_PENDING)
2478 HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2479 DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2480 if (result == WAIT_OBJECT_0)
2481 ret = TRUE;
2482 else
2484 TRACE("call cancelled\n");
2485 EnterCriticalSection(&httpc->async_data->cs);
2486 httpc->async_data->destination_buffer = NULL;
2487 LeaveCriticalSection(&httpc->async_data->cs);
2488 break;
2491 else
2493 HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2494 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2495 httpc->async_data->destination_buffer = NULL;
2496 RpcHttpAsyncData_Release(httpc->async_data);
2497 break;
2500 if (!httpc->async_data->inet_buffers.dwBufferLength)
2501 break;
2502 bytes_left -= httpc->async_data->inet_buffers.dwBufferLength;
2503 buf += httpc->async_data->inet_buffers.dwBufferLength;
2505 TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE");
2506 return ret ? count : -1;
2509 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2511 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2512 RPC_STATUS status;
2513 DWORD hdr_length;
2514 LONG dwRead;
2515 RpcPktCommonHdr common_hdr;
2517 *Header = NULL;
2519 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2521 again:
2522 /* read packet common header */
2523 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2524 if (dwRead != sizeof(common_hdr)) {
2525 WARN("Short read of header, %d bytes\n", dwRead);
2526 status = RPC_S_PROTOCOL_ERROR;
2527 goto fail;
2529 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2530 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2532 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2533 status = RPC_S_PROTOCOL_ERROR;
2534 goto fail;
2537 status = RPCRT4_ValidateCommonHeader(&common_hdr);
2538 if (status != RPC_S_OK) goto fail;
2540 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
2541 if (hdr_length == 0) {
2542 WARN("header length == 0\n");
2543 status = RPC_S_PROTOCOL_ERROR;
2544 goto fail;
2547 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
2548 if (!*Header)
2550 status = RPC_S_OUT_OF_RESOURCES;
2551 goto fail;
2553 memcpy(*Header, &common_hdr, sizeof(common_hdr));
2555 /* read the rest of packet header */
2556 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
2557 if (dwRead != hdr_length - sizeof(common_hdr)) {
2558 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
2559 status = RPC_S_PROTOCOL_ERROR;
2560 goto fail;
2563 if (common_hdr.frag_len - hdr_length)
2565 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
2566 if (!*Payload)
2568 status = RPC_S_OUT_OF_RESOURCES;
2569 goto fail;
2572 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
2573 if (dwRead != common_hdr.frag_len - hdr_length)
2575 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
2576 status = RPC_S_PROTOCOL_ERROR;
2577 goto fail;
2580 else
2581 *Payload = NULL;
2583 if ((*Header)->common.ptype == PKT_HTTP)
2585 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
2587 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
2588 status = RPC_S_PROTOCOL_ERROR;
2589 goto fail;
2591 if ((*Header)->http.flags == 0x0001)
2593 TRACE("http idle packet, waiting for real packet\n");
2594 if ((*Header)->http.num_data_items != 0)
2596 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
2597 status = RPC_S_PROTOCOL_ERROR;
2598 goto fail;
2601 else if ((*Header)->http.flags == 0x0002)
2603 ULONG bytes_transmitted;
2604 ULONG flow_control_increment;
2605 UUID pipe_uuid;
2606 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
2607 Connection->server,
2608 &bytes_transmitted,
2609 &flow_control_increment,
2610 &pipe_uuid);
2611 if (status != RPC_S_OK)
2612 goto fail;
2613 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
2614 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
2615 /* FIXME: do something with parsed data */
2617 else
2619 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
2620 status = RPC_S_PROTOCOL_ERROR;
2621 goto fail;
2623 RPCRT4_FreeHeader(*Header);
2624 *Header = NULL;
2625 HeapFree(GetProcessHeap(), 0, *Payload);
2626 *Payload = NULL;
2627 goto again;
2630 /* success */
2631 status = RPC_S_OK;
2633 httpc->bytes_received += common_hdr.frag_len;
2635 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
2637 if (httpc->bytes_received > httpc->flow_control_mark)
2639 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
2640 httpc->bytes_received,
2641 httpc->flow_control_increment,
2642 &httpc->out_pipe_uuid);
2643 if (hdr)
2645 DWORD bytes_written;
2646 BOOL ret2;
2647 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
2648 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
2649 RPCRT4_FreeHeader(hdr);
2650 if (ret2)
2651 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
2655 fail:
2656 if (status != RPC_S_OK) {
2657 RPCRT4_FreeHeader(*Header);
2658 *Header = NULL;
2659 HeapFree(GetProcessHeap(), 0, *Payload);
2660 *Payload = NULL;
2662 return status;
2665 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
2666 const void *buffer, unsigned int count)
2668 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2669 DWORD bytes_written;
2670 BOOL ret;
2672 httpc->last_sent_time = ~0U; /* disable idle packet sending */
2673 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
2674 httpc->last_sent_time = GetTickCount();
2675 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
2676 return ret ? bytes_written : -1;
2679 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
2681 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2683 TRACE("\n");
2685 SetEvent(httpc->timer_cancelled);
2686 if (httpc->in_request)
2687 InternetCloseHandle(httpc->in_request);
2688 httpc->in_request = NULL;
2689 if (httpc->out_request)
2690 InternetCloseHandle(httpc->out_request);
2691 httpc->out_request = NULL;
2692 if (httpc->app_info)
2693 InternetCloseHandle(httpc->app_info);
2694 httpc->app_info = NULL;
2695 if (httpc->session)
2696 InternetCloseHandle(httpc->session);
2697 httpc->session = NULL;
2698 RpcHttpAsyncData_Release(httpc->async_data);
2699 if (httpc->cancel_event)
2700 CloseHandle(httpc->cancel_event);
2702 return 0;
2705 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
2707 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2709 SetEvent(httpc->cancel_event);
2712 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
2714 BOOL ret;
2715 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2717 RpcHttpAsyncData_AddRef(httpc->async_data);
2718 ret = InternetQueryDataAvailable(httpc->out_request,
2719 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
2720 if (ret)
2722 /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2723 * async ref now */
2724 RpcHttpAsyncData_Release(httpc->async_data);
2726 else
2728 if (GetLastError() == ERROR_IO_PENDING)
2730 HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2731 DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2732 if (result != WAIT_OBJECT_0)
2734 TRACE("call cancelled\n");
2735 return -1;
2738 else
2740 RpcHttpAsyncData_Release(httpc->async_data);
2741 return -1;
2745 /* success */
2746 return 0;
2749 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
2750 const char *networkaddr,
2751 const char *endpoint)
2753 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
2754 EPM_PROTOCOL_HTTP, endpoint);
2757 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
2758 size_t tower_size,
2759 char **networkaddr,
2760 char **endpoint)
2762 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
2763 networkaddr, EPM_PROTOCOL_HTTP,
2764 endpoint);
2767 static const struct connection_ops conn_protseq_list[] = {
2768 { "ncacn_np",
2769 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
2770 rpcrt4_conn_np_alloc,
2771 rpcrt4_ncacn_np_open,
2772 rpcrt4_ncacn_np_handoff,
2773 rpcrt4_conn_np_read,
2774 rpcrt4_conn_np_write,
2775 rpcrt4_conn_np_close,
2776 rpcrt4_conn_np_cancel_call,
2777 rpcrt4_conn_np_wait_for_incoming_data,
2778 rpcrt4_ncacn_np_get_top_of_tower,
2779 rpcrt4_ncacn_np_parse_top_of_tower,
2780 NULL,
2781 RPCRT4_default_is_authorized,
2782 RPCRT4_default_authorize,
2783 RPCRT4_default_secure_packet,
2784 rpcrt4_conn_np_impersonate_client,
2785 rpcrt4_conn_np_revert_to_self,
2786 RPCRT4_default_inquire_auth_client,
2788 { "ncalrpc",
2789 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
2790 rpcrt4_conn_np_alloc,
2791 rpcrt4_ncalrpc_open,
2792 rpcrt4_ncalrpc_handoff,
2793 rpcrt4_conn_np_read,
2794 rpcrt4_conn_np_write,
2795 rpcrt4_conn_np_close,
2796 rpcrt4_conn_np_cancel_call,
2797 rpcrt4_conn_np_wait_for_incoming_data,
2798 rpcrt4_ncalrpc_get_top_of_tower,
2799 rpcrt4_ncalrpc_parse_top_of_tower,
2800 NULL,
2801 rpcrt4_ncalrpc_is_authorized,
2802 rpcrt4_ncalrpc_authorize,
2803 rpcrt4_ncalrpc_secure_packet,
2804 rpcrt4_conn_np_impersonate_client,
2805 rpcrt4_conn_np_revert_to_self,
2806 rpcrt4_ncalrpc_inquire_auth_client,
2808 { "ncacn_ip_tcp",
2809 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
2810 rpcrt4_conn_tcp_alloc,
2811 rpcrt4_ncacn_ip_tcp_open,
2812 rpcrt4_conn_tcp_handoff,
2813 rpcrt4_conn_tcp_read,
2814 rpcrt4_conn_tcp_write,
2815 rpcrt4_conn_tcp_close,
2816 rpcrt4_conn_tcp_cancel_call,
2817 rpcrt4_conn_tcp_wait_for_incoming_data,
2818 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
2819 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
2820 NULL,
2821 RPCRT4_default_is_authorized,
2822 RPCRT4_default_authorize,
2823 RPCRT4_default_secure_packet,
2824 RPCRT4_default_impersonate_client,
2825 RPCRT4_default_revert_to_self,
2826 RPCRT4_default_inquire_auth_client,
2828 { "ncacn_http",
2829 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
2830 rpcrt4_ncacn_http_alloc,
2831 rpcrt4_ncacn_http_open,
2832 rpcrt4_ncacn_http_handoff,
2833 rpcrt4_ncacn_http_read,
2834 rpcrt4_ncacn_http_write,
2835 rpcrt4_ncacn_http_close,
2836 rpcrt4_ncacn_http_cancel_call,
2837 rpcrt4_ncacn_http_wait_for_incoming_data,
2838 rpcrt4_ncacn_http_get_top_of_tower,
2839 rpcrt4_ncacn_http_parse_top_of_tower,
2840 rpcrt4_ncacn_http_receive_fragment,
2841 RPCRT4_default_is_authorized,
2842 RPCRT4_default_authorize,
2843 RPCRT4_default_secure_packet,
2844 RPCRT4_default_impersonate_client,
2845 RPCRT4_default_revert_to_self,
2846 RPCRT4_default_inquire_auth_client,
2851 static const struct protseq_ops protseq_list[] =
2854 "ncacn_np",
2855 rpcrt4_protseq_np_alloc,
2856 rpcrt4_protseq_np_signal_state_changed,
2857 rpcrt4_protseq_np_get_wait_array,
2858 rpcrt4_protseq_np_free_wait_array,
2859 rpcrt4_protseq_np_wait_for_new_connection,
2860 rpcrt4_protseq_ncacn_np_open_endpoint,
2863 "ncalrpc",
2864 rpcrt4_protseq_np_alloc,
2865 rpcrt4_protseq_np_signal_state_changed,
2866 rpcrt4_protseq_np_get_wait_array,
2867 rpcrt4_protseq_np_free_wait_array,
2868 rpcrt4_protseq_np_wait_for_new_connection,
2869 rpcrt4_protseq_ncalrpc_open_endpoint,
2872 "ncacn_ip_tcp",
2873 rpcrt4_protseq_sock_alloc,
2874 rpcrt4_protseq_sock_signal_state_changed,
2875 rpcrt4_protseq_sock_get_wait_array,
2876 rpcrt4_protseq_sock_free_wait_array,
2877 rpcrt4_protseq_sock_wait_for_new_connection,
2878 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
2882 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
2884 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
2886 unsigned int i;
2887 for(i=0; i<ARRAYSIZE(protseq_list); i++)
2888 if (!strcmp(protseq_list[i].name, protseq))
2889 return &protseq_list[i];
2890 return NULL;
2893 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
2895 unsigned int i;
2896 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
2897 if (!strcmp(conn_protseq_list[i].name, protseq))
2898 return &conn_protseq_list[i];
2899 return NULL;
2902 /**** interface to rest of code ****/
2904 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
2906 TRACE("(Connection == ^%p)\n", Connection);
2908 assert(!Connection->server);
2909 return Connection->ops->open_connection_client(Connection);
2912 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
2914 TRACE("(Connection == ^%p)\n", Connection);
2915 if (SecIsValidHandle(&Connection->ctx))
2917 DeleteSecurityContext(&Connection->ctx);
2918 SecInvalidateHandle(&Connection->ctx);
2920 rpcrt4_conn_close(Connection);
2921 return RPC_S_OK;
2924 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
2925 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
2926 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
2928 static LONG next_id;
2929 const struct connection_ops *ops;
2930 RpcConnection* NewConnection;
2932 ops = rpcrt4_get_conn_protseq_ops(Protseq);
2933 if (!ops)
2935 FIXME("not supported for protseq %s\n", Protseq);
2936 return RPC_S_PROTSEQ_NOT_SUPPORTED;
2939 NewConnection = ops->alloc();
2940 NewConnection->Next = NULL;
2941 NewConnection->server_binding = NULL;
2942 NewConnection->server = server;
2943 NewConnection->ops = ops;
2944 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
2945 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
2946 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
2947 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
2948 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
2949 NewConnection->NextCallId = 1;
2951 SecInvalidateHandle(&NewConnection->ctx);
2952 memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
2953 NewConnection->attr = 0;
2954 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
2955 NewConnection->AuthInfo = AuthInfo;
2956 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
2957 NewConnection->encryption_auth_len = 0;
2958 NewConnection->signature_auth_len = 0;
2959 if (QOS) RpcQualityOfService_AddRef(QOS);
2960 NewConnection->QOS = QOS;
2962 list_init(&NewConnection->conn_pool_entry);
2963 NewConnection->async_state = NULL;
2965 TRACE("connection: %p\n", NewConnection);
2966 *Connection = NewConnection;
2968 return RPC_S_OK;
2971 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
2973 RPC_STATUS err;
2975 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
2976 rpcrt4_conn_get_name(OldConnection),
2977 OldConnection->NetworkAddr,
2978 OldConnection->Endpoint, NULL,
2979 OldConnection->AuthInfo, OldConnection->QOS);
2980 if (err == RPC_S_OK)
2981 rpcrt4_conn_handoff(OldConnection, *Connection);
2982 return err;
2985 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
2987 TRACE("connection: %p\n", Connection);
2989 RPCRT4_CloseConnection(Connection);
2990 RPCRT4_strfree(Connection->Endpoint);
2991 RPCRT4_strfree(Connection->NetworkAddr);
2992 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
2993 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
2994 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
2996 /* server-only */
2997 if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
2999 HeapFree(GetProcessHeap(), 0, Connection);
3000 return RPC_S_OK;
3003 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3004 size_t *tower_size,
3005 const char *protseq,
3006 const char *networkaddr,
3007 const char *endpoint)
3009 twr_empty_floor_t *protocol_floor;
3010 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3012 *tower_size = 0;
3014 if (!protseq_ops)
3015 return RPC_S_INVALID_RPC_PROTSEQ;
3017 if (!tower_data)
3019 *tower_size = sizeof(*protocol_floor);
3020 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3021 return RPC_S_OK;
3024 protocol_floor = (twr_empty_floor_t *)tower_data;
3025 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3026 protocol_floor->protid = protseq_ops->epm_protocols[0];
3027 protocol_floor->count_rhs = 0;
3029 tower_data += sizeof(*protocol_floor);
3031 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3032 if (!*tower_size)
3033 return EPT_S_NOT_REGISTERED;
3035 *tower_size += sizeof(*protocol_floor);
3037 return RPC_S_OK;
3040 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3041 size_t tower_size,
3042 char **protseq,
3043 char **networkaddr,
3044 char **endpoint)
3046 const twr_empty_floor_t *protocol_floor;
3047 const twr_empty_floor_t *floor4;
3048 const struct connection_ops *protseq_ops = NULL;
3049 RPC_STATUS status;
3050 unsigned int i;
3052 if (tower_size < sizeof(*protocol_floor))
3053 return EPT_S_NOT_REGISTERED;
3055 protocol_floor = (const twr_empty_floor_t *)tower_data;
3056 tower_data += sizeof(*protocol_floor);
3057 tower_size -= sizeof(*protocol_floor);
3058 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3059 (protocol_floor->count_rhs > tower_size))
3060 return EPT_S_NOT_REGISTERED;
3061 tower_data += protocol_floor->count_rhs;
3062 tower_size -= protocol_floor->count_rhs;
3064 floor4 = (const twr_empty_floor_t *)tower_data;
3065 if ((tower_size < sizeof(*floor4)) ||
3066 (floor4->count_lhs != sizeof(floor4->protid)))
3067 return EPT_S_NOT_REGISTERED;
3069 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
3070 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3071 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3073 protseq_ops = &conn_protseq_list[i];
3074 break;
3077 if (!protseq_ops)
3078 return EPT_S_NOT_REGISTERED;
3080 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3082 if ((status == RPC_S_OK) && protseq)
3084 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3085 strcpy(*protseq, protseq_ops->name);
3088 return status;
3091 /***********************************************************************
3092 * RpcNetworkIsProtseqValidW (RPCRT4.@)
3094 * Checks if the given protocol sequence is known by the RPC system.
3095 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3098 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3100 char ps[0x10];
3102 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3103 ps, sizeof ps, NULL, NULL);
3104 if (rpcrt4_get_conn_protseq_ops(ps))
3105 return RPC_S_OK;
3107 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3109 return RPC_S_INVALID_RPC_PROTSEQ;
3112 /***********************************************************************
3113 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3115 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3117 UNICODE_STRING protseqW;
3119 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3121 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3122 RtlFreeUnicodeString(&protseqW);
3123 return ret;
3125 return RPC_S_OUT_OF_MEMORY;