dddc5135c9dfbc66d465d5998f9f0cae5880cb1a
[reactos.git] / reactos / dll / win32 / 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 <stdlib.h>
33 #include <sys/types.h>
34
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) */
78
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"
86
87 #include "rpc.h"
88 #include "rpcndr.h"
89
90 #include "wine/debug.h"
91
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"
97
98 #ifndef SOL_TCP
99 # define SOL_TCP IPPROTO_TCP
100 #endif
101
102 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
103
104 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
105
106 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
107
108 /**** ncacn_np support ****/
109
110 typedef struct _RpcConnection_np
111 {
112 RpcConnection common;
113 HANDLE pipe;
114 OVERLAPPED ovl[2];
115 BOOL listening;
116 } RpcConnection_np;
117
118 static RpcConnection *rpcrt4_conn_np_alloc(void)
119 {
120 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
121 if (npc)
122 {
123 npc->pipe = NULL;
124 memset(&npc->ovl, 0, sizeof(npc->ovl));
125 npc->listening = FALSE;
126 }
127 return &npc->common;
128 }
129
130 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
131 {
132 if (npc->listening)
133 return RPC_S_OK;
134
135 npc->listening = TRUE;
136 for (;;)
137 {
138 if (ConnectNamedPipe(npc->pipe, &npc->ovl[0]))
139 return RPC_S_OK;
140
141 switch(GetLastError())
142 {
143 case ERROR_PIPE_CONNECTED:
144 SetEvent(npc->ovl[0].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;
157 }
158 }
159 }
160
161 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
162 {
163 RpcConnection_np *npc = (RpcConnection_np *) Connection;
164 TRACE("listening on %s\n", pname);
165
166 npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
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;
176 }
177
178 memset(&npc->ovl, 0, sizeof(npc->ovl));
179 npc->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
180 npc->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
181
182 /* Note: we don't call ConnectNamedPipe here because it must be done in the
183 * server thread as the thread must be alertable */
184 return RPC_S_OK;
185 }
186
187 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
188 {
189 RpcConnection_np *npc = (RpcConnection_np *) Connection;
190 HANDLE pipe;
191 DWORD err, dwMode;
192
193 TRACE("connecting to %s\n", pname);
194
195 while (TRUE) {
196 DWORD dwFlags = 0;
197 if (Connection->QOS)
198 {
199 dwFlags = SECURITY_SQOS_PRESENT;
200 switch (Connection->QOS->qos->ImpersonationType)
201 {
202 case RPC_C_IMP_LEVEL_DEFAULT:
203 /* FIXME: what to do here? */
204 break;
205 case RPC_C_IMP_LEVEL_ANONYMOUS:
206 dwFlags |= SECURITY_ANONYMOUS;
207 break;
208 case RPC_C_IMP_LEVEL_IDENTIFY:
209 dwFlags |= SECURITY_IDENTIFICATION;
210 break;
211 case RPC_C_IMP_LEVEL_IMPERSONATE:
212 dwFlags |= SECURITY_IMPERSONATION;
213 break;
214 case RPC_C_IMP_LEVEL_DELEGATE:
215 dwFlags |= SECURITY_DELEGATION;
216 break;
217 }
218 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
219 dwFlags |= SECURITY_CONTEXT_TRACKING;
220 }
221 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
222 OPEN_EXISTING, dwFlags, 0);
223 if (pipe != INVALID_HANDLE_VALUE) break;
224 err = GetLastError();
225 if (err == ERROR_PIPE_BUSY) {
226 TRACE("connection failed, error=%x\n", err);
227 return RPC_S_SERVER_TOO_BUSY;
228 }
229 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
230 err = GetLastError();
231 WARN("connection failed, error=%x\n", err);
232 return RPC_S_SERVER_UNAVAILABLE;
233 }
234 }
235
236 /* success */
237 memset(&npc->ovl, 0, sizeof(npc->ovl));
238 /* pipe is connected; change to message-read mode. */
239 dwMode = PIPE_READMODE_MESSAGE;
240 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
241 npc->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
242 npc->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
243 npc->pipe = pipe;
244
245 return RPC_S_OK;
246 }
247
248 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
249 {
250 RpcConnection_np *npc = (RpcConnection_np *) Connection;
251 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
252 RPC_STATUS r;
253 LPSTR pname;
254
255 /* already connected? */
256 if (npc->pipe)
257 return RPC_S_OK;
258
259 /* protseq=ncalrpc: supposed to use NT LPC ports,
260 * but we'll implement it with named pipes for now */
261 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
262 strcat(strcpy(pname, prefix), Connection->Endpoint);
263 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
264 I_RpcFree(pname);
265
266 return r;
267 }
268
269 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
270 {
271 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
272 RPC_STATUS r;
273 LPSTR pname;
274 RpcConnection *Connection;
275 char generated_endpoint[22];
276
277 if (!endpoint)
278 {
279 static LONG lrpc_nameless_id;
280 DWORD process_id = GetCurrentProcessId();
281 ULONG id = InterlockedIncrement(&lrpc_nameless_id);
282 snprintf(generated_endpoint, sizeof(generated_endpoint),
283 "LRPC%08x.%08x", process_id, id);
284 endpoint = generated_endpoint;
285 }
286
287 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
288 endpoint, NULL, NULL, NULL);
289 if (r != RPC_S_OK)
290 return r;
291
292 /* protseq=ncalrpc: supposed to use NT LPC ports,
293 * but we'll implement it with named pipes for now */
294 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
295 strcat(strcpy(pname, prefix), Connection->Endpoint);
296 r = rpcrt4_conn_create_pipe(Connection, pname);
297 I_RpcFree(pname);
298
299 EnterCriticalSection(&protseq->cs);
300 Connection->Next = protseq->conn;
301 protseq->conn = Connection;
302 LeaveCriticalSection(&protseq->cs);
303
304 return r;
305 }
306
307 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
308 {
309 RpcConnection_np *npc = (RpcConnection_np *) Connection;
310 static const char prefix[] = "\\\\.";
311 RPC_STATUS r;
312 LPSTR pname;
313
314 /* already connected? */
315 if (npc->pipe)
316 return RPC_S_OK;
317
318 /* protseq=ncacn_np: named pipes */
319 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
320 strcat(strcpy(pname, prefix), Connection->Endpoint);
321 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
322 I_RpcFree(pname);
323
324 return r;
325 }
326
327 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
328 {
329 static const char prefix[] = "\\\\.";
330 RPC_STATUS r;
331 LPSTR pname;
332 RpcConnection *Connection;
333 char generated_endpoint[21];
334
335 if (!endpoint)
336 {
337 static LONG np_nameless_id;
338 DWORD process_id = GetCurrentProcessId();
339 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
340 snprintf(generated_endpoint, sizeof(generated_endpoint),
341 "\\\\pipe\\\\%08x.%03x", process_id, id);
342 endpoint = generated_endpoint;
343 }
344
345 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
346 endpoint, NULL, NULL, NULL);
347 if (r != RPC_S_OK)
348 return r;
349
350 /* protseq=ncacn_np: named pipes */
351 pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
352 strcat(strcpy(pname, prefix), Connection->Endpoint);
353 r = rpcrt4_conn_create_pipe(Connection, pname);
354 I_RpcFree(pname);
355
356 EnterCriticalSection(&protseq->cs);
357 Connection->Next = protseq->conn;
358 protseq->conn = Connection;
359 LeaveCriticalSection(&protseq->cs);
360
361 return r;
362 }
363
364 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
365 {
366 /* because of the way named pipes work, we'll transfer the connected pipe
367 * to the child, then reopen the server binding to continue listening */
368
369 new_npc->pipe = old_npc->pipe;
370 new_npc->ovl[0] = old_npc->ovl[0];
371 new_npc->ovl[1] = old_npc->ovl[1];
372 old_npc->pipe = 0;
373 memset(&old_npc->ovl[0], 0, sizeof(old_npc->ovl));
374 old_npc->listening = FALSE;
375 }
376
377 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
378 {
379 RPC_STATUS status;
380 LPSTR pname;
381 static const char prefix[] = "\\\\.";
382
383 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
384
385 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
386 strcat(strcpy(pname, prefix), old_conn->Endpoint);
387 status = rpcrt4_conn_create_pipe(old_conn, pname);
388 I_RpcFree(pname);
389
390 return status;
391 }
392
393 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
394 {
395 RPC_STATUS status;
396 LPSTR pname;
397 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
398
399 TRACE("%s\n", old_conn->Endpoint);
400
401 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
402
403 pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
404 strcat(strcpy(pname, prefix), old_conn->Endpoint);
405 status = rpcrt4_conn_create_pipe(old_conn, pname);
406 I_RpcFree(pname);
407
408 return status;
409 }
410
411 static int rpcrt4_conn_np_read(RpcConnection *Connection,
412 void *buffer, unsigned int count)
413 {
414 RpcConnection_np *npc = (RpcConnection_np *) Connection;
415 char *buf = buffer;
416 BOOL ret = TRUE;
417 unsigned int bytes_left = count;
418
419 while (bytes_left)
420 {
421 DWORD bytes_read;
422 ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, &npc->ovl[0]);
423 if ((!ret || !bytes_read) && (GetLastError() != ERROR_IO_PENDING))
424 break;
425 ret = GetOverlappedResult(npc->pipe, &npc->ovl[0], &bytes_read, TRUE);
426 if (!ret && GetLastError() == ERROR_MORE_DATA)
427 ret = TRUE;
428 if (!ret || !bytes_read)
429 break;
430 bytes_left -= bytes_read;
431 buf += bytes_read;
432 }
433 return ret ? count : -1;
434 }
435
436 static int rpcrt4_conn_np_write(RpcConnection *Connection,
437 const void *buffer, unsigned int count)
438 {
439 RpcConnection_np *npc = (RpcConnection_np *) Connection;
440 const char *buf = buffer;
441 BOOL ret = TRUE;
442 unsigned int bytes_left = count;
443
444 while (bytes_left)
445 {
446 DWORD bytes_written;
447 ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, &npc->ovl[1]);
448 if ((!ret || !bytes_written) && (GetLastError() != ERROR_IO_PENDING))
449 break;
450 ret = GetOverlappedResult(npc->pipe, &npc->ovl[1], &bytes_written, TRUE);
451 if (!ret && GetLastError() == ERROR_MORE_DATA)
452 ret = TRUE;
453 if (!ret || !bytes_written)
454 break;
455 bytes_left -= bytes_written;
456 buf += bytes_written;
457 }
458 return ret ? count : -1;
459 }
460
461 static int rpcrt4_conn_np_close(RpcConnection *Connection)
462 {
463 RpcConnection_np *npc = (RpcConnection_np *) Connection;
464 if (npc->pipe) {
465 FlushFileBuffers(npc->pipe);
466 CloseHandle(npc->pipe);
467 npc->pipe = 0;
468 }
469 if (npc->ovl[0].hEvent) {
470 CloseHandle(npc->ovl[0].hEvent);
471 npc->ovl[0].hEvent = 0;
472 }
473 if (npc->ovl[1].hEvent) {
474 CloseHandle(npc->ovl[1].hEvent);
475 npc->ovl[1].hEvent = 0;
476 }
477 return 0;
478 }
479
480 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
481 {
482 /* FIXME: implement when named pipe writes use overlapped I/O */
483 }
484
485 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
486 {
487 /* FIXME: implement when named pipe writes use overlapped I/O */
488 return -1;
489 }
490
491 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
492 const char *networkaddr,
493 const char *endpoint)
494 {
495 twr_empty_floor_t *smb_floor;
496 twr_empty_floor_t *nb_floor;
497 size_t size;
498 size_t networkaddr_size;
499 size_t endpoint_size;
500
501 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
502
503 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
504 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
505 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
506
507 if (!tower_data)
508 return size;
509
510 smb_floor = (twr_empty_floor_t *)tower_data;
511
512 tower_data += sizeof(*smb_floor);
513
514 smb_floor->count_lhs = sizeof(smb_floor->protid);
515 smb_floor->protid = EPM_PROTOCOL_SMB;
516 smb_floor->count_rhs = endpoint_size;
517
518 if (endpoint)
519 memcpy(tower_data, endpoint, endpoint_size);
520 else
521 tower_data[0] = 0;
522 tower_data += endpoint_size;
523
524 nb_floor = (twr_empty_floor_t *)tower_data;
525
526 tower_data += sizeof(*nb_floor);
527
528 nb_floor->count_lhs = sizeof(nb_floor->protid);
529 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
530 nb_floor->count_rhs = networkaddr_size;
531
532 if (networkaddr)
533 memcpy(tower_data, networkaddr, networkaddr_size);
534 else
535 tower_data[0] = 0;
536
537 return size;
538 }
539
540 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
541 size_t tower_size,
542 char **networkaddr,
543 char **endpoint)
544 {
545 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
546 const twr_empty_floor_t *nb_floor;
547
548 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
549
550 if (tower_size < sizeof(*smb_floor))
551 return EPT_S_NOT_REGISTERED;
552
553 tower_data += sizeof(*smb_floor);
554 tower_size -= sizeof(*smb_floor);
555
556 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
557 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
558 (smb_floor->count_rhs > tower_size) ||
559 (tower_data[smb_floor->count_rhs - 1] != '\0'))
560 return EPT_S_NOT_REGISTERED;
561
562 if (endpoint)
563 {
564 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
565 if (!*endpoint)
566 return RPC_S_OUT_OF_RESOURCES;
567 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
568 }
569 tower_data += smb_floor->count_rhs;
570 tower_size -= smb_floor->count_rhs;
571
572 if (tower_size < sizeof(*nb_floor))
573 return EPT_S_NOT_REGISTERED;
574
575 nb_floor = (const twr_empty_floor_t *)tower_data;
576
577 tower_data += sizeof(*nb_floor);
578 tower_size -= sizeof(*nb_floor);
579
580 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
581 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
582 (nb_floor->count_rhs > tower_size) ||
583 (tower_data[nb_floor->count_rhs - 1] != '\0'))
584 return EPT_S_NOT_REGISTERED;
585
586 if (networkaddr)
587 {
588 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
589 if (!*networkaddr)
590 {
591 if (endpoint)
592 {
593 I_RpcFree(*endpoint);
594 *endpoint = NULL;
595 }
596 return RPC_S_OUT_OF_RESOURCES;
597 }
598 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
599 }
600
601 return RPC_S_OK;
602 }
603
604 typedef struct _RpcServerProtseq_np
605 {
606 RpcServerProtseq common;
607 HANDLE mgr_event;
608 } RpcServerProtseq_np;
609
610 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
611 {
612 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
613 if (ps)
614 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
615 return &ps->common;
616 }
617
618 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
619 {
620 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
621 SetEvent(npps->mgr_event);
622 }
623
624 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
625 {
626 HANDLE *objs = prev_array;
627 RpcConnection_np *conn;
628 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
629
630 EnterCriticalSection(&protseq->cs);
631
632 /* open and count connections */
633 *count = 1;
634 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
635 while (conn) {
636 rpcrt4_conn_listen_pipe(conn);
637 if (conn->ovl[0].hEvent)
638 (*count)++;
639 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
640 }
641
642 /* make array of connections */
643 if (objs)
644 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
645 else
646 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
647 if (!objs)
648 {
649 ERR("couldn't allocate objs\n");
650 LeaveCriticalSection(&protseq->cs);
651 return NULL;
652 }
653
654 objs[0] = npps->mgr_event;
655 *count = 1;
656 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
657 while (conn) {
658 if ((objs[*count] = conn->ovl[0].hEvent))
659 (*count)++;
660 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
661 }
662 LeaveCriticalSection(&protseq->cs);
663 return objs;
664 }
665
666 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
667 {
668 HeapFree(GetProcessHeap(), 0, array);
669 }
670
671 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
672 {
673 HANDLE b_handle;
674 HANDLE *objs = wait_array;
675 DWORD res;
676 RpcConnection *cconn;
677 RpcConnection_np *conn;
678
679 if (!objs)
680 return -1;
681
682 do
683 {
684 /* an alertable wait isn't strictly necessary, but due to our
685 * overlapped I/O implementation in Wine we need to free some memory
686 * by the file user APC being called, even if no completion routine was
687 * specified at the time of starting the async operation */
688 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
689 } while (res == WAIT_IO_COMPLETION);
690
691 if (res == WAIT_OBJECT_0)
692 return 0;
693 else if (res == WAIT_FAILED)
694 {
695 ERR("wait failed with error %d\n", GetLastError());
696 return -1;
697 }
698 else
699 {
700 b_handle = objs[res - WAIT_OBJECT_0];
701 /* find which connection got a RPC */
702 EnterCriticalSection(&protseq->cs);
703 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
704 while (conn) {
705 if (b_handle == conn->ovl[0].hEvent) break;
706 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
707 }
708 cconn = NULL;
709 if (conn)
710 RPCRT4_SpawnConnection(&cconn, &conn->common);
711 else
712 ERR("failed to locate connection for handle %p\n", b_handle);
713 LeaveCriticalSection(&protseq->cs);
714 if (cconn)
715 {
716 RPCRT4_new_client(cconn);
717 return 1;
718 }
719 else return -1;
720 }
721 }
722
723 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
724 const char *networkaddr,
725 const char *endpoint)
726 {
727 twr_empty_floor_t *pipe_floor;
728 size_t size;
729 size_t endpoint_size;
730
731 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
732
733 endpoint_size = strlen(endpoint) + 1;
734 size = sizeof(*pipe_floor) + endpoint_size;
735
736 if (!tower_data)
737 return size;
738
739 pipe_floor = (twr_empty_floor_t *)tower_data;
740
741 tower_data += sizeof(*pipe_floor);
742
743 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
744 pipe_floor->protid = EPM_PROTOCOL_PIPE;
745 pipe_floor->count_rhs = endpoint_size;
746
747 memcpy(tower_data, endpoint, endpoint_size);
748
749 return size;
750 }
751
752 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
753 size_t tower_size,
754 char **networkaddr,
755 char **endpoint)
756 {
757 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
758
759 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
760
761 if (tower_size < sizeof(*pipe_floor))
762 return EPT_S_NOT_REGISTERED;
763
764 tower_data += sizeof(*pipe_floor);
765 tower_size -= sizeof(*pipe_floor);
766
767 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
768 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
769 (pipe_floor->count_rhs > tower_size) ||
770 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
771 return EPT_S_NOT_REGISTERED;
772
773 if (networkaddr)
774 *networkaddr = NULL;
775
776 if (endpoint)
777 {
778 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
779 if (!*endpoint)
780 return RPC_S_OUT_OF_RESOURCES;
781 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
782 }
783
784 return RPC_S_OK;
785 }
786
787 /**** ncacn_ip_tcp support ****/
788
789 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
790 const char *networkaddr,
791 unsigned char tcp_protid,
792 const char *endpoint)
793 {
794 twr_tcp_floor_t *tcp_floor;
795 twr_ipv4_floor_t *ipv4_floor;
796 struct addrinfo *ai;
797 struct addrinfo hints;
798 int ret;
799 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
800
801 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
802
803 if (!tower_data)
804 return size;
805
806 tcp_floor = (twr_tcp_floor_t *)tower_data;
807 tower_data += sizeof(*tcp_floor);
808
809 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
810
811 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
812 tcp_floor->protid = tcp_protid;
813 tcp_floor->count_rhs = sizeof(tcp_floor->port);
814
815 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
816 ipv4_floor->protid = EPM_PROTOCOL_IP;
817 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
818
819 hints.ai_flags = AI_NUMERICHOST;
820 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
821 hints.ai_family = PF_INET;
822 hints.ai_socktype = SOCK_STREAM;
823 hints.ai_protocol = IPPROTO_TCP;
824 hints.ai_addrlen = 0;
825 hints.ai_addr = NULL;
826 hints.ai_canonname = NULL;
827 hints.ai_next = NULL;
828
829 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
830 if (ret)
831 {
832 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
833 if (ret)
834 {
835 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
836 return 0;
837 }
838 }
839
840 if (ai->ai_family == PF_INET)
841 {
842 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
843 tcp_floor->port = sin->sin_port;
844 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
845 }
846 else
847 {
848 ERR("unexpected protocol family %d\n", ai->ai_family);
849 return 0;
850 }
851
852 freeaddrinfo(ai);
853
854 return size;
855 }
856
857 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
858 size_t tower_size,
859 char **networkaddr,
860 unsigned char tcp_protid,
861 char **endpoint)
862 {
863 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
864 const twr_ipv4_floor_t *ipv4_floor;
865 struct in_addr in_addr;
866
867 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
868
869 if (tower_size < sizeof(*tcp_floor))
870 return EPT_S_NOT_REGISTERED;
871
872 tower_data += sizeof(*tcp_floor);
873 tower_size -= sizeof(*tcp_floor);
874
875 if (tower_size < sizeof(*ipv4_floor))
876 return EPT_S_NOT_REGISTERED;
877
878 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
879
880 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
881 (tcp_floor->protid != tcp_protid) ||
882 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
883 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
884 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
885 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
886 return EPT_S_NOT_REGISTERED;
887
888 if (endpoint)
889 {
890 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
891 if (!*endpoint)
892 return RPC_S_OUT_OF_RESOURCES;
893 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
894 }
895
896 if (networkaddr)
897 {
898 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
899 if (!*networkaddr)
900 {
901 if (endpoint)
902 {
903 I_RpcFree(*endpoint);
904 *endpoint = NULL;
905 }
906 return RPC_S_OUT_OF_RESOURCES;
907 }
908 in_addr.s_addr = ipv4_floor->ipv4addr;
909 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
910 {
911 ERR("inet_ntop: %s\n", strerror(errno));
912 I_RpcFree(*networkaddr);
913 *networkaddr = NULL;
914 if (endpoint)
915 {
916 I_RpcFree(*endpoint);
917 *endpoint = NULL;
918 }
919 return EPT_S_NOT_REGISTERED;
920 }
921 }
922
923 return RPC_S_OK;
924 }
925
926 typedef struct _RpcConnection_tcp
927 {
928 RpcConnection common;
929 int sock;
930 #ifdef HAVE_SOCKETPAIR
931 int cancel_fds[2];
932 #else
933 HANDLE sock_event;
934 HANDLE cancel_event;
935 #endif
936 } RpcConnection_tcp;
937
938 #ifdef HAVE_SOCKETPAIR
939
940 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
941 {
942 if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
943 {
944 ERR("socketpair() failed: %s\n", strerror(errno));
945 return FALSE;
946 }
947 return TRUE;
948 }
949
950 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
951 {
952 struct pollfd pfds[2];
953 pfds[0].fd = tcpc->sock;
954 pfds[0].events = POLLIN;
955 pfds[1].fd = tcpc->cancel_fds[0];
956 pfds[1].events = POLLIN;
957 if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
958 {
959 ERR("poll() failed: %s\n", strerror(errno));
960 return FALSE;
961 }
962 if (pfds[1].revents & POLLIN) /* canceled */
963 {
964 char dummy;
965 read(pfds[1].fd, &dummy, sizeof(dummy));
966 return FALSE;
967 }
968 return TRUE;
969 }
970
971 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
972 {
973 struct pollfd pfd;
974 pfd.fd = tcpc->sock;
975 pfd.events = POLLOUT;
976 if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
977 {
978 ERR("poll() failed: %s\n", strerror(errno));
979 return FALSE;
980 }
981 return TRUE;
982 }
983
984 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
985 {
986 char dummy = 1;
987
988 write(tcpc->cancel_fds[1], &dummy, 1);
989 }
990
991 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
992 {
993 close(tcpc->cancel_fds[0]);
994 close(tcpc->cancel_fds[1]);
995 }
996
997 #else /* HAVE_SOCKETPAIR */
998
999 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1000 {
1001 static BOOL wsa_inited;
1002 if (!wsa_inited)
1003 {
1004 WSADATA wsadata;
1005 WSAStartup(MAKEWORD(2, 2), &wsadata);
1006 /* Note: WSAStartup can be called more than once so we don't bother with
1007 * making accesses to wsa_inited thread-safe */
1008 wsa_inited = TRUE;
1009 }
1010 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1011 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1012 if (!tcpc->sock_event || !tcpc->cancel_event)
1013 {
1014 ERR("event creation failed\n");
1015 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1016 return FALSE;
1017 }
1018 return TRUE;
1019 }
1020
1021 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1022 {
1023 HANDLE wait_handles[2];
1024 DWORD res;
1025 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1026 {
1027 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1028 return FALSE;
1029 }
1030 wait_handles[0] = tcpc->sock_event;
1031 wait_handles[1] = tcpc->cancel_event;
1032 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1033 switch (res)
1034 {
1035 case WAIT_OBJECT_0:
1036 return TRUE;
1037 case WAIT_OBJECT_0 + 1:
1038 return FALSE;
1039 default:
1040 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1041 return FALSE;
1042 }
1043 }
1044
1045 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1046 {
1047 DWORD res;
1048 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1049 {
1050 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1051 return FALSE;
1052 }
1053 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1054 switch (res)
1055 {
1056 case WAIT_OBJECT_0:
1057 return TRUE;
1058 default:
1059 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1060 return FALSE;
1061 }
1062 }
1063
1064 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
1065 {
1066 SetEvent(tcpc->cancel_event);
1067 }
1068
1069 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
1070 {
1071 CloseHandle(tcpc->sock_event);
1072 CloseHandle(tcpc->cancel_event);
1073 }
1074
1075 #endif
1076
1077 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1078 {
1079 RpcConnection_tcp *tcpc;
1080 tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
1081 if (tcpc == NULL)
1082 return NULL;
1083 tcpc->sock = -1;
1084 if (!rpcrt4_sock_wait_init(tcpc))
1085 {
1086 HeapFree(GetProcessHeap(), 0, tcpc);
1087 return NULL;
1088 }
1089 return &tcpc->common;
1090 }
1091
1092 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1093 {
1094 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1095 int sock;
1096 int ret;
1097 struct addrinfo *ai;
1098 struct addrinfo *ai_cur;
1099 struct addrinfo hints;
1100
1101 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1102
1103 if (tcpc->sock != -1)
1104 return RPC_S_OK;
1105
1106 hints.ai_flags = 0;
1107 hints.ai_family = PF_UNSPEC;
1108 hints.ai_socktype = SOCK_STREAM;
1109 hints.ai_protocol = IPPROTO_TCP;
1110 hints.ai_addrlen = 0;
1111 hints.ai_addr = NULL;
1112 hints.ai_canonname = NULL;
1113 hints.ai_next = NULL;
1114
1115 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1116 if (ret)
1117 {
1118 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1119 Connection->Endpoint, gai_strerror(ret));
1120 return RPC_S_SERVER_UNAVAILABLE;
1121 }
1122
1123 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1124 {
1125 int val;
1126 u_long nonblocking;
1127
1128 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1129 {
1130 TRACE("skipping non-IP/IPv6 address family\n");
1131 continue;
1132 }
1133
1134 if (TRACE_ON(rpc))
1135 {
1136 char host[256];
1137 char service[256];
1138 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1139 host, sizeof(host), service, sizeof(service),
1140 NI_NUMERICHOST | NI_NUMERICSERV);
1141 TRACE("trying %s:%s\n", host, service);
1142 }
1143
1144 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1145 if (sock == -1)
1146 {
1147 WARN("socket() failed: %s\n", strerror(errno));
1148 continue;
1149 }
1150
1151 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1152 {
1153 WARN("connect() failed: %s\n", strerror(errno));
1154 closesocket(sock);
1155 continue;
1156 }
1157
1158 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1159 val = 1;
1160 setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1161 nonblocking = 1;
1162 ioctlsocket(sock, FIONBIO, &nonblocking);
1163
1164 tcpc->sock = sock;
1165
1166 freeaddrinfo(ai);
1167 TRACE("connected\n");
1168 return RPC_S_OK;
1169 }
1170
1171 freeaddrinfo(ai);
1172 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1173 return RPC_S_SERVER_UNAVAILABLE;
1174 }
1175
1176 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1177 {
1178 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1179 int sock;
1180 int ret;
1181 struct addrinfo *ai;
1182 struct addrinfo *ai_cur;
1183 struct addrinfo hints;
1184 RpcConnection *first_connection = NULL;
1185
1186 TRACE("(%p, %s)\n", protseq, endpoint);
1187
1188 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1189 hints.ai_family = PF_UNSPEC;
1190 hints.ai_socktype = SOCK_STREAM;
1191 hints.ai_protocol = IPPROTO_TCP;
1192 hints.ai_addrlen = 0;
1193 hints.ai_addr = NULL;
1194 hints.ai_canonname = NULL;
1195 hints.ai_next = NULL;
1196
1197 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1198 if (ret)
1199 {
1200 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1201 gai_strerror(ret));
1202 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1203 return RPC_S_INVALID_ENDPOINT_FORMAT;
1204 return RPC_S_CANT_CREATE_ENDPOINT;
1205 }
1206
1207 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1208 {
1209 RpcConnection_tcp *tcpc;
1210 RPC_STATUS create_status;
1211 struct sockaddr_storage sa;
1212 socklen_t sa_len;
1213 char service[NI_MAXSERV];
1214 u_long nonblocking;
1215
1216 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1217 {
1218 TRACE("skipping non-IP/IPv6 address family\n");
1219 continue;
1220 }
1221
1222 if (TRACE_ON(rpc))
1223 {
1224 char host[256];
1225 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1226 host, sizeof(host), service, sizeof(service),
1227 NI_NUMERICHOST | NI_NUMERICSERV);
1228 TRACE("trying %s:%s\n", host, service);
1229 }
1230
1231 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1232 if (sock == -1)
1233 {
1234 WARN("socket() failed: %s\n", strerror(errno));
1235 status = RPC_S_CANT_CREATE_ENDPOINT;
1236 continue;
1237 }
1238
1239 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1240 if (ret < 0)
1241 {
1242 WARN("bind failed: %s\n", strerror(errno));
1243 closesocket(sock);
1244 if (errno == EADDRINUSE)
1245 status = RPC_S_DUPLICATE_ENDPOINT;
1246 else
1247 status = RPC_S_CANT_CREATE_ENDPOINT;
1248 continue;
1249 }
1250
1251 sa_len = sizeof(sa);
1252 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1253 {
1254 WARN("getsockname() failed: %s\n", strerror(errno));
1255 status = RPC_S_CANT_CREATE_ENDPOINT;
1256 continue;
1257 }
1258
1259 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1260 NULL, 0, service, sizeof(service),
1261 NI_NUMERICSERV);
1262 if (ret)
1263 {
1264 WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1265 status = RPC_S_CANT_CREATE_ENDPOINT;
1266 continue;
1267 }
1268
1269 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1270 protseq->Protseq, NULL,
1271 service, NULL, NULL, NULL);
1272 if (create_status != RPC_S_OK)
1273 {
1274 closesocket(sock);
1275 status = create_status;
1276 continue;
1277 }
1278
1279 tcpc->sock = sock;
1280 ret = listen(sock, protseq->MaxCalls);
1281 if (ret < 0)
1282 {
1283 WARN("listen failed: %s\n", strerror(errno));
1284 RPCRT4_DestroyConnection(&tcpc->common);
1285 status = RPC_S_OUT_OF_RESOURCES;
1286 continue;
1287 }
1288 /* need a non-blocking socket, otherwise accept() has a potential
1289 * race-condition (poll() says it is readable, connection drops,
1290 * and accept() blocks until the next connection comes...)
1291 */
1292 nonblocking = 1;
1293 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1294 if (ret < 0)
1295 {
1296 WARN("couldn't make socket non-blocking, error %d\n", ret);
1297 RPCRT4_DestroyConnection(&tcpc->common);
1298 status = RPC_S_OUT_OF_RESOURCES;
1299 continue;
1300 }
1301
1302 tcpc->common.Next = first_connection;
1303 first_connection = &tcpc->common;
1304
1305 /* since IPv4 and IPv6 share the same port space, we only need one
1306 * successful bind to listen for both */
1307 break;
1308 }
1309
1310 freeaddrinfo(ai);
1311
1312 /* if at least one connection was created for an endpoint then
1313 * return success */
1314 if (first_connection)
1315 {
1316 RpcConnection *conn;
1317
1318 /* find last element in list */
1319 for (conn = first_connection; conn->Next; conn = conn->Next)
1320 ;
1321
1322 EnterCriticalSection(&protseq->cs);
1323 conn->Next = protseq->conn;
1324 protseq->conn = first_connection;
1325 LeaveCriticalSection(&protseq->cs);
1326
1327 TRACE("listening on %s\n", endpoint);
1328 return RPC_S_OK;
1329 }
1330
1331 ERR("couldn't listen on port %s\n", endpoint);
1332 return status;
1333 }
1334
1335 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1336 {
1337 int ret;
1338 struct sockaddr_in address;
1339 socklen_t addrsize;
1340 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1341 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1342 u_long nonblocking;
1343
1344 addrsize = sizeof(address);
1345 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1346 if (ret < 0)
1347 {
1348 ERR("Failed to accept a TCP connection: error %d\n", ret);
1349 return RPC_S_OUT_OF_RESOURCES;
1350 }
1351 nonblocking = 1;
1352 ioctlsocket(ret, FIONBIO, &nonblocking);
1353 client->sock = ret;
1354 TRACE("Accepted a new TCP connection\n");
1355 return RPC_S_OK;
1356 }
1357
1358 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1359 void *buffer, unsigned int count)
1360 {
1361 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1362 int bytes_read = 0;
1363 do
1364 {
1365 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1366 if (!r)
1367 return -1;
1368 else if (r > 0)
1369 bytes_read += r;
1370 else if (errno != EAGAIN)
1371 {
1372 WARN("recv() failed: %s\n", strerror(errno));
1373 return -1;
1374 }
1375 else
1376 {
1377 if (!rpcrt4_sock_wait_for_recv(tcpc))
1378 return -1;
1379 }
1380 } while (bytes_read != count);
1381 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1382 return bytes_read;
1383 }
1384
1385 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1386 const void *buffer, unsigned int count)
1387 {
1388 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1389 int bytes_written = 0;
1390 do
1391 {
1392 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1393 if (r >= 0)
1394 bytes_written += r;
1395 else if (errno != EAGAIN)
1396 return -1;
1397 else
1398 {
1399 if (!rpcrt4_sock_wait_for_send(tcpc))
1400 return -1;
1401 }
1402 } while (bytes_written != count);
1403 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1404 return bytes_written;
1405 }
1406
1407 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1408 {
1409 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1410
1411 TRACE("%d\n", tcpc->sock);
1412
1413 if (tcpc->sock != -1)
1414 closesocket(tcpc->sock);
1415 tcpc->sock = -1;
1416 rpcrt4_sock_wait_destroy(tcpc);
1417 return 0;
1418 }
1419
1420 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1421 {
1422 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1423 TRACE("%p\n", Connection);
1424 rpcrt4_sock_wait_cancel(tcpc);
1425 }
1426
1427 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1428 {
1429 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1430
1431 TRACE("%p\n", Connection);
1432
1433 if (!rpcrt4_sock_wait_for_recv(tcpc))
1434 return -1;
1435 return 0;
1436 }
1437
1438 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1439 const char *networkaddr,
1440 const char *endpoint)
1441 {
1442 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1443 EPM_PROTOCOL_TCP, endpoint);
1444 }
1445
1446 #ifdef HAVE_SOCKETPAIR
1447
1448 typedef struct _RpcServerProtseq_sock
1449 {
1450 RpcServerProtseq common;
1451 int mgr_event_rcv;
1452 int mgr_event_snd;
1453 } RpcServerProtseq_sock;
1454
1455 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1456 {
1457 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1458 if (ps)
1459 {
1460 int fds[2];
1461 if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1462 {
1463 fcntl(fds[0], F_SETFL, O_NONBLOCK);
1464 fcntl(fds[1], F_SETFL, O_NONBLOCK);
1465 ps->mgr_event_rcv = fds[0];
1466 ps->mgr_event_snd = fds[1];
1467 }
1468 else
1469 {
1470 ERR("socketpair failed with error %s\n", strerror(errno));
1471 HeapFree(GetProcessHeap(), 0, ps);
1472 return NULL;
1473 }
1474 }
1475 return &ps->common;
1476 }
1477
1478 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1479 {
1480 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1481 char dummy = 1;
1482 write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1483 }
1484
1485 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1486 {
1487 struct pollfd *poll_info = prev_array;
1488 RpcConnection_tcp *conn;
1489 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1490
1491 EnterCriticalSection(&protseq->cs);
1492
1493 /* open and count connections */
1494 *count = 1;
1495 conn = (RpcConnection_tcp *)protseq->conn;
1496 while (conn) {
1497 if (conn->sock != -1)
1498 (*count)++;
1499 conn = (RpcConnection_tcp *)conn->common.Next;
1500 }
1501
1502 /* make array of connections */
1503 if (poll_info)
1504 poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1505 else
1506 poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1507 if (!poll_info)
1508 {
1509 ERR("couldn't allocate poll_info\n");
1510 LeaveCriticalSection(&protseq->cs);
1511 return NULL;
1512 }
1513
1514 poll_info[0].fd = sockps->mgr_event_rcv;
1515 poll_info[0].events = POLLIN;
1516 *count = 1;
1517 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1518 while (conn) {
1519 if (conn->sock != -1)
1520 {
1521 poll_info[*count].fd = conn->sock;
1522 poll_info[*count].events = POLLIN;
1523 (*count)++;
1524 }
1525 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1526 }
1527 LeaveCriticalSection(&protseq->cs);
1528 return poll_info;
1529 }
1530
1531 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1532 {
1533 HeapFree(GetProcessHeap(), 0, array);
1534 }
1535
1536 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1537 {
1538 struct pollfd *poll_info = wait_array;
1539 int ret;
1540 unsigned int i;
1541 RpcConnection *cconn;
1542 RpcConnection_tcp *conn;
1543
1544 if (!poll_info)
1545 return -1;
1546
1547 ret = poll(poll_info, count, -1);
1548 if (ret < 0)
1549 {
1550 ERR("poll failed with error %d\n", ret);
1551 return -1;
1552 }
1553
1554 for (i = 0; i < count; i++)
1555 if (poll_info[i].revents & POLLIN)
1556 {
1557 /* RPC server event */
1558 if (i == 0)
1559 {
1560 char dummy;
1561 read(poll_info[0].fd, &dummy, sizeof(dummy));
1562 return 0;
1563 }
1564
1565 /* find which connection got a RPC */
1566 EnterCriticalSection(&protseq->cs);
1567 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1568 while (conn) {
1569 if (poll_info[i].fd == conn->sock) break;
1570 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1571 }
1572 cconn = NULL;
1573 if (conn)
1574 RPCRT4_SpawnConnection(&cconn, &conn->common);
1575 else
1576 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1577 LeaveCriticalSection(&protseq->cs);
1578 if (cconn)
1579 RPCRT4_new_client(cconn);
1580 else
1581 return -1;
1582 }
1583
1584 return 1;
1585 }
1586
1587 #else /* HAVE_SOCKETPAIR */
1588
1589 typedef struct _RpcServerProtseq_sock
1590 {
1591 RpcServerProtseq common;
1592 HANDLE mgr_event;
1593 } RpcServerProtseq_sock;
1594
1595 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1596 {
1597 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1598 if (ps)
1599 {
1600 static BOOL wsa_inited;
1601 if (!wsa_inited)
1602 {
1603 WSADATA wsadata;
1604 WSAStartup(MAKEWORD(2, 2), &wsadata);
1605 /* Note: WSAStartup can be called more than once so we don't bother with
1606 * making accesses to wsa_inited thread-safe */
1607 wsa_inited = TRUE;
1608 }
1609 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1610 }
1611 return &ps->common;
1612 }
1613
1614 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1615 {
1616 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1617 SetEvent(sockps->mgr_event);
1618 }
1619
1620 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1621 {
1622 HANDLE *objs = prev_array;
1623 RpcConnection_tcp *conn;
1624 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1625
1626 EnterCriticalSection(&protseq->cs);
1627
1628 /* open and count connections */
1629 *count = 1;
1630 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1631 while (conn)
1632 {
1633 if (conn->sock != -1)
1634 (*count)++;
1635 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1636 }
1637
1638 /* make array of connections */
1639 if (objs)
1640 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1641 else
1642 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1643 if (!objs)
1644 {
1645 ERR("couldn't allocate objs\n");
1646 LeaveCriticalSection(&protseq->cs);
1647 return NULL;
1648 }
1649
1650 objs[0] = sockps->mgr_event;
1651 *count = 1;
1652 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1653 while (conn)
1654 {
1655 if (conn->sock != -1)
1656 {
1657 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1658 if (res == SOCKET_ERROR)
1659 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1660 else
1661 {
1662 objs[*count] = conn->sock_event;
1663 (*count)++;
1664 }
1665 }
1666 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1667 }
1668 LeaveCriticalSection(&protseq->cs);
1669 return objs;
1670 }
1671
1672 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1673 {
1674 HeapFree(GetProcessHeap(), 0, array);
1675 }
1676
1677 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1678 {
1679 HANDLE b_handle;
1680 HANDLE *objs = wait_array;
1681 DWORD res;
1682 RpcConnection *cconn;
1683 RpcConnection_tcp *conn;
1684
1685 if (!objs)
1686 return -1;
1687
1688 do
1689 {
1690 /* an alertable wait isn't strictly necessary, but due to our
1691 * overlapped I/O implementation in Wine we need to free some memory
1692 * by the file user APC being called, even if no completion routine was
1693 * specified at the time of starting the async operation */
1694 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1695 } while (res == WAIT_IO_COMPLETION);
1696
1697 if (res == WAIT_OBJECT_0)
1698 return 0;
1699 else if (res == WAIT_FAILED)
1700 {
1701 ERR("wait failed with error %d\n", GetLastError());
1702 return -1;
1703 }
1704 else
1705 {
1706 b_handle = objs[res - WAIT_OBJECT_0];
1707 /* find which connection got a RPC */
1708 EnterCriticalSection(&protseq->cs);
1709 conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1710 while (conn)
1711 {
1712 if (b_handle == conn->sock_event) break;
1713 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1714 }
1715 cconn = NULL;
1716 if (conn)
1717 RPCRT4_SpawnConnection(&cconn, &conn->common);
1718 else
1719 ERR("failed to locate connection for handle %p\n", b_handle);
1720 LeaveCriticalSection(&protseq->cs);
1721 if (cconn)
1722 {
1723 RPCRT4_new_client(cconn);
1724 return 1;
1725 }
1726 else return -1;
1727 }
1728 }
1729
1730 #endif /* HAVE_SOCKETPAIR */
1731
1732 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1733 size_t tower_size,
1734 char **networkaddr,
1735 char **endpoint)
1736 {
1737 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1738 networkaddr, EPM_PROTOCOL_TCP,
1739 endpoint);
1740 }
1741
1742 /**** ncacn_http support ****/
1743 #if 0
1744 /* 60 seconds is the period native uses */
1745 #define HTTP_IDLE_TIME 60000
1746
1747 /* reference counted to avoid a race between a cancelled call's connection
1748 * being destroyed and the asynchronous InternetReadFileEx call being
1749 * completed */
1750 typedef struct _RpcHttpAsyncData
1751 {
1752 LONG refs;
1753 HANDLE completion_event;
1754 INTERNET_BUFFERSA inet_buffers;
1755 void *destination_buffer; /* the address that inet_buffers.lpvBuffer will be
1756 * copied into when the call completes */
1757 CRITICAL_SECTION cs;
1758 } RpcHttpAsyncData;
1759
1760 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1761 {
1762 return InterlockedIncrement(&data->refs);
1763 }
1764
1765 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1766 {
1767 ULONG refs = InterlockedDecrement(&data->refs);
1768 if (!refs)
1769 {
1770 TRACE("destroying async data %p\n", data);
1771 CloseHandle(data->completion_event);
1772 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1773 DeleteCriticalSection(&data->cs);
1774 HeapFree(GetProcessHeap(), 0, data);
1775 }
1776 return refs;
1777 }
1778
1779 typedef struct _RpcConnection_http
1780 {
1781 RpcConnection common;
1782 HINTERNET app_info;
1783 HINTERNET session;
1784 HINTERNET in_request;
1785 HINTERNET out_request;
1786 HANDLE timer_cancelled;
1787 HANDLE cancel_event;
1788 DWORD last_sent_time;
1789 ULONG bytes_received;
1790 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1791 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1792 UUID connection_uuid;
1793 UUID in_pipe_uuid;
1794 UUID out_pipe_uuid;
1795 RpcHttpAsyncData *async_data;
1796 } RpcConnection_http;
1797
1798 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1799 {
1800 RpcConnection_http *httpc;
1801 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1802 if (!httpc) return NULL;
1803 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1804 if (!httpc->async_data)
1805 {
1806 HeapFree(GetProcessHeap(), 0, httpc);
1807 return NULL;
1808 }
1809 TRACE("async data = %p\n", httpc->async_data);
1810 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1811 httpc->async_data->refs = 1;
1812 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
1813 httpc->async_data->inet_buffers.lpvBuffer = NULL;
1814 httpc->async_data->destination_buffer = NULL;
1815 InitializeCriticalSection(&httpc->async_data->cs);
1816 return &httpc->common;
1817 }
1818
1819 typedef struct _HttpTimerThreadData
1820 {
1821 PVOID timer_param;
1822 DWORD *last_sent_time;
1823 HANDLE timer_cancelled;
1824 } HttpTimerThreadData;
1825
1826 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1827 {
1828 HINTERNET in_request = param;
1829 RpcPktHdr *idle_pkt;
1830
1831 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1832 0, 0);
1833 if (idle_pkt)
1834 {
1835 DWORD bytes_written;
1836 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1837 RPCRT4_FreeHeader(idle_pkt);
1838 }
1839 }
1840
1841 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1842 {
1843 DWORD cur_time = GetTickCount();
1844 DWORD cached_last_sent_time = *last_sent_time;
1845 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1846 }
1847
1848 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1849 {
1850 HttpTimerThreadData *data_in = param;
1851 HttpTimerThreadData data;
1852 DWORD timeout;
1853
1854 data = *data_in;
1855 HeapFree(GetProcessHeap(), 0, data_in);
1856
1857 for (timeout = HTTP_IDLE_TIME;
1858 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1859 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1860 {
1861 /* are we too soon after last send? */
1862 if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time)
1863 continue;
1864 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1865 }
1866
1867 CloseHandle(data.timer_cancelled);
1868 return 0;
1869 }
1870
1871 static VOID WINAPI rpcrt4_http_internet_callback(
1872 HINTERNET hInternet,
1873 DWORD_PTR dwContext,
1874 DWORD dwInternetStatus,
1875 LPVOID lpvStatusInformation,
1876 DWORD dwStatusInformationLength)
1877 {
1878 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1879
1880 switch (dwInternetStatus)
1881 {
1882 case INTERNET_STATUS_REQUEST_COMPLETE:
1883 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1884 if (async_data)
1885 {
1886 if (async_data->inet_buffers.lpvBuffer)
1887 {
1888 EnterCriticalSection(&async_data->cs);
1889 if (async_data->destination_buffer)
1890 {
1891 memcpy(async_data->destination_buffer,
1892 async_data->inet_buffers.lpvBuffer,
1893 async_data->inet_buffers.dwBufferLength);
1894 async_data->destination_buffer = NULL;
1895 }
1896 LeaveCriticalSection(&async_data->cs);
1897 }
1898 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
1899 async_data->inet_buffers.lpvBuffer = NULL;
1900 SetEvent(async_data->completion_event);
1901 RpcHttpAsyncData_Release(async_data);
1902 }
1903 break;
1904 }
1905 }
1906
1907 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1908 {
1909 BOOL ret;
1910 DWORD status_code;
1911 DWORD size;
1912 DWORD index;
1913 WCHAR buf[32];
1914 WCHAR *status_text = buf;
1915 TRACE("\n");
1916
1917 index = 0;
1918 size = sizeof(status_code);
1919 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1920 if (!ret)
1921 return GetLastError();
1922 if (status_code < 400)
1923 return RPC_S_OK;
1924 index = 0;
1925 size = sizeof(buf);
1926 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1927 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1928 {
1929 status_text = HeapAlloc(GetProcessHeap(), 0, size);
1930 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1931 }
1932
1933 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
1934 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
1935
1936 if (status_code == HTTP_STATUS_DENIED)
1937 return ERROR_ACCESS_DENIED;
1938 return RPC_S_SERVER_UNAVAILABLE;
1939 }
1940
1941 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
1942 {
1943 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
1944 LPWSTR proxy = NULL;
1945 LPWSTR user = NULL;
1946 LPWSTR password = NULL;
1947 LPWSTR servername = NULL;
1948 const WCHAR *option;
1949 INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */
1950
1951 if (httpc->common.QOS &&
1952 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1953 {
1954 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1955 if (http_cred->TransportCredentials)
1956 {
1957 WCHAR *p;
1958 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1959 ULONG len = cred->DomainLength + 1 + cred->UserLength;
1960 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1961 if (!user)
1962 return RPC_S_OUT_OF_RESOURCES;
1963 p = user;
1964 if (cred->DomainLength)
1965 {
1966 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1967 p += cred->DomainLength;
1968 *p = '\\';
1969 p++;
1970 }
1971 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1972 p[cred->UserLength] = 0;
1973
1974 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1975 }
1976 }
1977
1978 for (option = httpc->common.NetworkOptions; option;
1979 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
1980 {
1981 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
1982 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
1983
1984 if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
1985 {
1986 const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
1987 const WCHAR *value_end;
1988 const WCHAR *p;
1989
1990 value_end = strchrW(option, ',');
1991 if (!value_end)
1992 value_end = value_start + strlenW(value_start);
1993 for (p = value_start; p < value_end; p++)
1994 if (*p == ':')
1995 {
1996 port = atoiW(p+1);
1997 value_end = p;
1998 break;
1999 }
2000 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2001 servername = RPCRT4_strndupW(value_start, value_end-value_start);
2002 }
2003 else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
2004 {
2005 const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
2006 const WCHAR *value_end;
2007
2008 value_end = strchrW(option, ',');
2009 if (!value_end)
2010 value_end = value_start + strlenW(value_start);
2011 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
2012 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
2013 }
2014 else
2015 FIXME("unhandled option %s\n", debugstr_w(option));
2016 }
2017
2018 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
2019 NULL, NULL, INTERNET_FLAG_ASYNC);
2020 if (!httpc->app_info)
2021 {
2022 HeapFree(GetProcessHeap(), 0, password);
2023 HeapFree(GetProcessHeap(), 0, user);
2024 ERR("InternetOpenW failed with error %d\n", GetLastError());
2025 return RPC_S_SERVER_UNAVAILABLE;
2026 }
2027 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
2028
2029 /* if no RpcProxy option specified, set the HTTP server address to the
2030 * RPC server address */
2031 if (!servername)
2032 {
2033 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
2034 if (!servername)
2035 {
2036 HeapFree(GetProcessHeap(), 0, password);
2037 HeapFree(GetProcessHeap(), 0, user);
2038 return RPC_S_OUT_OF_RESOURCES;
2039 }
2040 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
2041 }
2042
2043 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
2044 INTERNET_SERVICE_HTTP, 0, 0);
2045
2046 HeapFree(GetProcessHeap(), 0, password);
2047 HeapFree(GetProcessHeap(), 0, user);
2048 HeapFree(GetProcessHeap(), 0, servername);
2049
2050 if (!httpc->session)
2051 {
2052 ERR("InternetConnectW failed with error %d\n", GetLastError());
2053 return RPC_S_SERVER_UNAVAILABLE;
2054 }
2055
2056 return RPC_S_OK;
2057 }
2058
2059 /* prepare the in pipe for use by RPC packets */
2060 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data,
2061 const UUID *connection_uuid,
2062 const UUID *in_pipe_uuid,
2063 const UUID *association_uuid)
2064 {
2065 BYTE packet[44];
2066 BOOL ret;
2067 RPC_STATUS status;
2068 RpcPktHdr *hdr;
2069 INTERNET_BUFFERSW buffers_in;
2070 DWORD bytes_read, bytes_written;
2071
2072 /* prepare in pipe */
2073 ResetEvent(async_data->completion_event);
2074 RpcHttpAsyncData_AddRef(async_data);
2075 ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0);
2076 if (!ret)
2077 {
2078 if (GetLastError() == ERROR_IO_PENDING)
2079 WaitForSingleObject(async_data->completion_event, INFINITE);
2080 else
2081 {
2082 RpcHttpAsyncData_Release(async_data);
2083 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2084 return RPC_S_SERVER_UNAVAILABLE;
2085 }
2086 }
2087 status = rpcrt4_http_check_response(in_request);
2088 if (status != RPC_S_OK) return status;
2089
2090 InternetReadFile(in_request, packet, 20, &bytes_read);
2091 /* FIXME: do something with retrieved data */
2092
2093 memset(&buffers_in, 0, sizeof(buffers_in));
2094 buffers_in.dwStructSize = sizeof(buffers_in);
2095 /* FIXME: get this from the registry */
2096 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2097 ResetEvent(async_data->completion_event);
2098 RpcHttpAsyncData_AddRef(async_data);
2099 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2100 if (!ret)
2101 {
2102 if (GetLastError() == ERROR_IO_PENDING)
2103 WaitForSingleObject(async_data->completion_event, INFINITE);
2104 else
2105 {
2106 RpcHttpAsyncData_Release(async_data);
2107 ERR("HttpSendRequestExW failed with error %d\n", GetLastError());
2108 return RPC_S_SERVER_UNAVAILABLE;
2109 }
2110 }
2111
2112 TRACE("sending HTTP connect header to server\n");
2113 hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2114 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2115 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2116 RPCRT4_FreeHeader(hdr);
2117 if (!ret)
2118 {
2119 ERR("InternetWriteFile failed with error %d\n", GetLastError());
2120 return RPC_S_SERVER_UNAVAILABLE;
2121 }
2122
2123 return RPC_S_OK;
2124 }
2125
2126 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data)
2127 {
2128 BOOL ret;
2129 DWORD bytes_read;
2130 unsigned short data_len;
2131
2132 ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read);
2133 if (!ret)
2134 return RPC_S_SERVER_UNAVAILABLE;
2135 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2136 {
2137 ERR("wrong packet type received %d or wrong frag_len %d\n",
2138 hdr->common.ptype, hdr->common.frag_len);
2139 return RPC_S_PROTOCOL_ERROR;
2140 }
2141
2142 ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read);
2143 if (!ret)
2144 return RPC_S_SERVER_UNAVAILABLE;
2145
2146 data_len = hdr->common.frag_len - sizeof(hdr->http);
2147 if (data_len)
2148 {
2149 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2150 if (!*data)
2151 return RPC_S_OUT_OF_RESOURCES;
2152 ret = InternetReadFile(request, *data, data_len, &bytes_read);
2153 if (!ret)
2154 {
2155 HeapFree(GetProcessHeap(), 0, *data);
2156 return RPC_S_SERVER_UNAVAILABLE;
2157 }
2158 }
2159 else
2160 *data = NULL;
2161
2162 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2163 {
2164 ERR("invalid http packet\n");
2165 return RPC_S_PROTOCOL_ERROR;
2166 }
2167
2168 return RPC_S_OK;
2169 }
2170
2171 /* prepare the out pipe for use by RPC packets */
2172 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
2173 RpcHttpAsyncData *async_data,
2174 const UUID *connection_uuid,
2175 const UUID *out_pipe_uuid,
2176 ULONG *flow_control_increment)
2177 {
2178 BYTE packet[20];
2179 BOOL ret;
2180 RPC_STATUS status;
2181 RpcPktHdr *hdr;
2182 DWORD bytes_read;
2183 BYTE *data_from_server;
2184 RpcPktHdr pkt_from_server;
2185 ULONG field1, field3;
2186
2187 ResetEvent(async_data->completion_event);
2188 RpcHttpAsyncData_AddRef(async_data);
2189 ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0);
2190 if (!ret)
2191 {
2192 if (GetLastError() == ERROR_IO_PENDING)
2193 WaitForSingleObject(async_data->completion_event, INFINITE);
2194 else
2195 {
2196 RpcHttpAsyncData_Release(async_data);
2197 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2198 return RPC_S_SERVER_UNAVAILABLE;
2199 }
2200 }
2201 status = rpcrt4_http_check_response(out_request);
2202 if (status != RPC_S_OK) return status;
2203
2204 InternetReadFile(out_request, packet, 20, &bytes_read);
2205 /* FIXME: do something with retrieved data */
2206
2207 hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid, NULL);
2208 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2209 ResetEvent(async_data->completion_event);
2210 RpcHttpAsyncData_AddRef(async_data);
2211 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2212 if (!ret)
2213 {
2214 if (GetLastError() == ERROR_IO_PENDING)
2215 WaitForSingleObject(async_data->completion_event, INFINITE);
2216 else
2217 {
2218 RpcHttpAsyncData_Release(async_data);
2219 ERR("HttpSendRequestW failed with error %d\n", GetLastError());
2220 RPCRT4_FreeHeader(hdr);
2221 return RPC_S_SERVER_UNAVAILABLE;
2222 }
2223 }
2224 RPCRT4_FreeHeader(hdr);
2225 status = rpcrt4_http_check_response(out_request);
2226 if (status != RPC_S_OK) return status;
2227
2228 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2229 &data_from_server);
2230 if (status != RPC_S_OK) return status;
2231 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2232 &field1);
2233 HeapFree(GetProcessHeap(), 0, data_from_server);
2234 if (status != RPC_S_OK) return status;
2235 TRACE("received (%d) from first prepare header\n", field1);
2236
2237 status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
2238 &data_from_server);
2239 if (status != RPC_S_OK) return status;
2240 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2241 &field1, flow_control_increment,
2242 &field3);
2243 HeapFree(GetProcessHeap(), 0, data_from_server);
2244 if (status != RPC_S_OK) return status;
2245 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2246
2247 return RPC_S_OK;
2248 }
2249
2250 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2251 {
2252 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2253 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2254 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2255 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2256 static const WCHAR wszColon[] = {':',0};
2257 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2258 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2259 WCHAR *url;
2260 RPC_STATUS status;
2261 BOOL secure;
2262 HttpTimerThreadData *timer_data;
2263 HANDLE thread;
2264
2265 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2266
2267 if (Connection->server)
2268 {
2269 ERR("ncacn_http servers not supported yet\n");
2270 return RPC_S_SERVER_UNAVAILABLE;
2271 }
2272
2273 if (httpc->in_request)
2274 return RPC_S_OK;
2275
2276 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2277
2278 status = UuidCreate(&httpc->connection_uuid);
2279 status = UuidCreate(&httpc->in_pipe_uuid);
2280 status = UuidCreate(&httpc->out_pipe_uuid);
2281
2282 status = rpcrt4_http_internet_connect(httpc);
2283 if (status != RPC_S_OK)
2284 return status;
2285
2286 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2287 if (!url)
2288 return RPC_S_OUT_OF_MEMORY;
2289 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2290 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
2291 strcatW(url, wszColon);
2292 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
2293
2294 secure = httpc->common.QOS &&
2295 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2296 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2297
2298 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL,
2299 wszAcceptTypes,
2300 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2301 (DWORD_PTR)httpc->async_data);
2302 if (!httpc->in_request)
2303 {
2304 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2305 return RPC_S_SERVER_UNAVAILABLE;
2306 }
2307 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL,
2308 wszAcceptTypes,
2309 (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
2310 (DWORD_PTR)httpc->async_data);
2311 if (!httpc->out_request)
2312 {
2313 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2314 return RPC_S_SERVER_UNAVAILABLE;
2315 }
2316
2317 status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
2318 httpc->async_data,
2319 &httpc->connection_uuid,
2320 &httpc->in_pipe_uuid,
2321 &Connection->assoc->http_uuid);
2322 if (status != RPC_S_OK)
2323 return status;
2324
2325 status = rpcrt4_http_prepare_out_pipe(httpc->out_request,
2326 httpc->async_data,
2327 &httpc->connection_uuid,
2328 &httpc->out_pipe_uuid,
2329 &httpc->flow_control_increment);
2330 if (status != RPC_S_OK)
2331 return status;
2332
2333 httpc->flow_control_mark = httpc->flow_control_increment / 2;
2334 httpc->last_sent_time = GetTickCount();
2335 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2336
2337 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2338 if (!timer_data)
2339 return ERROR_OUTOFMEMORY;
2340 timer_data->timer_param = httpc->in_request;
2341 timer_data->last_sent_time = &httpc->last_sent_time;
2342 timer_data->timer_cancelled = httpc->timer_cancelled;
2343 /* FIXME: should use CreateTimerQueueTimer when implemented */
2344 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2345 if (!thread)
2346 {
2347 HeapFree(GetProcessHeap(), 0, timer_data);
2348 return GetLastError();
2349 }
2350 CloseHandle(thread);
2351
2352 return RPC_S_OK;
2353 }
2354
2355 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2356 {
2357 assert(0);
2358 return RPC_S_SERVER_UNAVAILABLE;
2359 }
2360
2361 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2362 void *buffer, unsigned int count)
2363 {
2364 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2365 char *buf = buffer;
2366 BOOL ret = TRUE;
2367 unsigned int bytes_left = count;
2368
2369 ResetEvent(httpc->async_data->completion_event);
2370 while (bytes_left)
2371 {
2372 RpcHttpAsyncData_AddRef(httpc->async_data);
2373 httpc->async_data->inet_buffers.dwBufferLength = bytes_left;
2374 httpc->async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, bytes_left);
2375 httpc->async_data->destination_buffer = buf;
2376 ret = InternetReadFileExA(httpc->out_request, &httpc->async_data->inet_buffers, IRF_ASYNC, 0);
2377 if (ret)
2378 {
2379 /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2380 * async ref now */
2381 RpcHttpAsyncData_Release(httpc->async_data);
2382 memcpy(buf, httpc->async_data->inet_buffers.lpvBuffer,
2383 httpc->async_data->inet_buffers.dwBufferLength);
2384 HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2385 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2386 httpc->async_data->destination_buffer = NULL;
2387 }
2388 else
2389 {
2390 if (GetLastError() == ERROR_IO_PENDING)
2391 {
2392 HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2393 DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2394 if (result == WAIT_OBJECT_0)
2395 ret = TRUE;
2396 else
2397 {
2398 TRACE("call cancelled\n");
2399 EnterCriticalSection(&httpc->async_data->cs);
2400 httpc->async_data->destination_buffer = NULL;
2401 LeaveCriticalSection(&httpc->async_data->cs);
2402 break;
2403 }
2404 }
2405 else
2406 {
2407 HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
2408 httpc->async_data->inet_buffers.lpvBuffer = NULL;
2409 httpc->async_data->destination_buffer = NULL;
2410 RpcHttpAsyncData_Release(httpc->async_data);
2411 break;
2412 }
2413 }
2414 if (!httpc->async_data->inet_buffers.dwBufferLength)
2415 break;
2416 bytes_left -= httpc->async_data->inet_buffers.dwBufferLength;
2417 buf += httpc->async_data->inet_buffers.dwBufferLength;
2418 }
2419 TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE");
2420 return ret ? count : -1;
2421 }
2422
2423 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2424 {
2425 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2426 RPC_STATUS status;
2427 DWORD hdr_length;
2428 LONG dwRead;
2429 RpcPktCommonHdr common_hdr;
2430
2431 *Header = NULL;
2432
2433 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2434
2435 again:
2436 /* read packet common header */
2437 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2438 if (dwRead != sizeof(common_hdr)) {
2439 WARN("Short read of header, %d bytes\n", dwRead);
2440 status = RPC_S_PROTOCOL_ERROR;
2441 goto fail;
2442 }
2443 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2444 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2445 {
2446 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2447 status = RPC_S_PROTOCOL_ERROR;
2448 goto fail;
2449 }
2450
2451 status = RPCRT4_ValidateCommonHeader(&common_hdr);
2452 if (status != RPC_S_OK) goto fail;
2453
2454 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
2455 if (hdr_length == 0) {
2456 WARN("header length == 0\n");
2457 status = RPC_S_PROTOCOL_ERROR;
2458 goto fail;
2459 }
2460
2461 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
2462 if (!*Header)
2463 {
2464 status = RPC_S_OUT_OF_RESOURCES;
2465 goto fail;
2466 }
2467 memcpy(*Header, &common_hdr, sizeof(common_hdr));
2468
2469 /* read the rest of packet header */
2470 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
2471 if (dwRead != hdr_length - sizeof(common_hdr)) {
2472 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
2473 status = RPC_S_PROTOCOL_ERROR;
2474 goto fail;
2475 }
2476
2477 if (common_hdr.frag_len - hdr_length)
2478 {
2479 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
2480 if (!*Payload)
2481 {
2482 status = RPC_S_OUT_OF_RESOURCES;
2483 goto fail;
2484 }
2485
2486 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
2487 if (dwRead != common_hdr.frag_len - hdr_length)
2488 {
2489 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
2490 status = RPC_S_PROTOCOL_ERROR;
2491 goto fail;
2492 }
2493 }
2494 else
2495 *Payload = NULL;
2496
2497 if ((*Header)->common.ptype == PKT_HTTP)
2498 {
2499 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
2500 {
2501 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
2502 status = RPC_S_PROTOCOL_ERROR;
2503 goto fail;
2504 }
2505 if ((*Header)->http.flags == 0x0001)
2506 {
2507 TRACE("http idle packet, waiting for real packet\n");
2508 if ((*Header)->http.num_data_items != 0)
2509 {
2510 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
2511 status = RPC_S_PROTOCOL_ERROR;
2512 goto fail;
2513 }
2514 }
2515 else if ((*Header)->http.flags == 0x0002)
2516 {
2517 ULONG bytes_transmitted;
2518 ULONG flow_control_increment;
2519 UUID pipe_uuid;
2520 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
2521 Connection->server,
2522 &bytes_transmitted,
2523 &flow_control_increment,
2524 &pipe_uuid);
2525 if (status != RPC_S_OK)
2526 goto fail;
2527 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
2528 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
2529 /* FIXME: do something with parsed data */
2530 }
2531 else
2532 {
2533 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
2534 status = RPC_S_PROTOCOL_ERROR;
2535 goto fail;
2536 }
2537 RPCRT4_FreeHeader(*Header);
2538 *Header = NULL;
2539 HeapFree(GetProcessHeap(), 0, *Payload);
2540 *Payload = NULL;
2541 goto again;
2542 }
2543
2544 /* success */
2545 status = RPC_S_OK;
2546
2547 httpc->bytes_received += common_hdr.frag_len;
2548
2549 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
2550
2551 if (httpc->bytes_received > httpc->flow_control_mark)
2552 {
2553 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
2554 httpc->bytes_received,
2555 httpc->flow_control_increment,
2556 &httpc->out_pipe_uuid);
2557 if (hdr)
2558 {
2559 DWORD bytes_written;
2560 BOOL ret2;
2561 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
2562 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
2563 RPCRT4_FreeHeader(hdr);
2564 if (ret2)
2565 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
2566 }
2567 }
2568
2569 fail:
2570 if (status != RPC_S_OK) {
2571 RPCRT4_FreeHeader(*Header);
2572 *Header = NULL;
2573 HeapFree(GetProcessHeap(), 0, *Payload);
2574 *Payload = NULL;
2575 }
2576 return status;
2577 }
2578
2579 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
2580 const void *buffer, unsigned int count)
2581 {
2582 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2583 DWORD bytes_written;
2584 BOOL ret;
2585
2586 httpc->last_sent_time = ~0U; /* disable idle packet sending */
2587 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
2588 httpc->last_sent_time = GetTickCount();
2589 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
2590 return ret ? bytes_written : -1;
2591 }
2592
2593 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
2594 {
2595 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2596
2597 TRACE("\n");
2598
2599 SetEvent(httpc->timer_cancelled);
2600 if (httpc->in_request)
2601 InternetCloseHandle(httpc->in_request);
2602 httpc->in_request = NULL;
2603 if (httpc->out_request)
2604 InternetCloseHandle(httpc->out_request);
2605 httpc->out_request = NULL;
2606 if (httpc->app_info)
2607 InternetCloseHandle(httpc->app_info);
2608 httpc->app_info = NULL;
2609 if (httpc->session)
2610 InternetCloseHandle(httpc->session);
2611 httpc->session = NULL;
2612 RpcHttpAsyncData_Release(httpc->async_data);
2613 if (httpc->cancel_event)
2614 CloseHandle(httpc->cancel_event);
2615
2616 return 0;
2617 }
2618
2619 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
2620 {
2621 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2622
2623 SetEvent(httpc->cancel_event);
2624 }
2625
2626 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
2627 {
2628 BOOL ret;
2629 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2630
2631 RpcHttpAsyncData_AddRef(httpc->async_data);
2632 ret = InternetQueryDataAvailable(httpc->out_request,
2633 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
2634 if (ret)
2635 {
2636 /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
2637 * async ref now */
2638 RpcHttpAsyncData_Release(httpc->async_data);
2639 }
2640 else
2641 {
2642 if (GetLastError() == ERROR_IO_PENDING)
2643 {
2644 HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
2645 DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
2646 if (result != WAIT_OBJECT_0)
2647 {
2648 TRACE("call cancelled\n");
2649 return -1;
2650 }
2651 }
2652 else
2653 {
2654 RpcHttpAsyncData_Release(httpc->async_data);
2655 return -1;
2656 }
2657 }
2658
2659 /* success */
2660 return 0;
2661 }
2662
2663 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
2664 const char *networkaddr,
2665 const char *endpoint)
2666 {
2667 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
2668 EPM_PROTOCOL_HTTP, endpoint);
2669 }
2670
2671 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
2672 size_t tower_size,
2673 char **networkaddr,
2674 char **endpoint)
2675 {
2676 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
2677 networkaddr, EPM_PROTOCOL_HTTP,
2678 endpoint);
2679 }
2680 #endif
2681 static const struct connection_ops conn_protseq_list[] = {
2682 { "ncacn_np",
2683 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
2684 rpcrt4_conn_np_alloc,
2685 rpcrt4_ncacn_np_open,
2686 rpcrt4_ncacn_np_handoff,
2687 rpcrt4_conn_np_read,
2688 rpcrt4_conn_np_write,
2689 rpcrt4_conn_np_close,
2690 rpcrt4_conn_np_cancel_call,
2691 rpcrt4_conn_np_wait_for_incoming_data,
2692 rpcrt4_ncacn_np_get_top_of_tower,
2693 rpcrt4_ncacn_np_parse_top_of_tower,
2694 NULL,
2695 },
2696 { "ncalrpc",
2697 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
2698 rpcrt4_conn_np_alloc,
2699 rpcrt4_ncalrpc_open,
2700 rpcrt4_ncalrpc_handoff,
2701 rpcrt4_conn_np_read,
2702 rpcrt4_conn_np_write,
2703 rpcrt4_conn_np_close,
2704 rpcrt4_conn_np_cancel_call,
2705 rpcrt4_conn_np_wait_for_incoming_data,
2706 rpcrt4_ncalrpc_get_top_of_tower,
2707 rpcrt4_ncalrpc_parse_top_of_tower,
2708 NULL,
2709 },
2710 { "ncacn_ip_tcp",
2711 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
2712 rpcrt4_conn_tcp_alloc,
2713 rpcrt4_ncacn_ip_tcp_open,
2714 rpcrt4_conn_tcp_handoff,
2715 rpcrt4_conn_tcp_read,
2716 rpcrt4_conn_tcp_write,
2717 rpcrt4_conn_tcp_close,
2718 rpcrt4_conn_tcp_cancel_call,
2719 rpcrt4_conn_tcp_wait_for_incoming_data,
2720 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
2721 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
2722 NULL,
2723 },
2724 #if 0
2725 { "ncacn_http",
2726 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
2727 rpcrt4_ncacn_http_alloc,
2728 rpcrt4_ncacn_http_open,
2729 rpcrt4_ncacn_http_handoff,
2730 rpcrt4_ncacn_http_read,
2731 rpcrt4_ncacn_http_write,
2732 rpcrt4_ncacn_http_close,
2733 rpcrt4_ncacn_http_cancel_call,
2734 rpcrt4_ncacn_http_wait_for_incoming_data,
2735 rpcrt4_ncacn_http_get_top_of_tower,
2736 rpcrt4_ncacn_http_parse_top_of_tower,
2737 rpcrt4_ncacn_http_receive_fragment,
2738 },
2739 #endif
2740 };
2741
2742
2743 static const struct protseq_ops protseq_list[] =
2744 {
2745 {
2746 "ncacn_np",
2747 rpcrt4_protseq_np_alloc,
2748 rpcrt4_protseq_np_signal_state_changed,
2749 rpcrt4_protseq_np_get_wait_array,
2750 rpcrt4_protseq_np_free_wait_array,
2751 rpcrt4_protseq_np_wait_for_new_connection,
2752 rpcrt4_protseq_ncacn_np_open_endpoint,
2753 },
2754 {
2755 "ncalrpc",
2756 rpcrt4_protseq_np_alloc,
2757 rpcrt4_protseq_np_signal_state_changed,
2758 rpcrt4_protseq_np_get_wait_array,
2759 rpcrt4_protseq_np_free_wait_array,
2760 rpcrt4_protseq_np_wait_for_new_connection,
2761 rpcrt4_protseq_ncalrpc_open_endpoint,
2762 },
2763 {
2764 "ncacn_ip_tcp",
2765 rpcrt4_protseq_sock_alloc,
2766 rpcrt4_protseq_sock_signal_state_changed,
2767 rpcrt4_protseq_sock_get_wait_array,
2768 rpcrt4_protseq_sock_free_wait_array,
2769 rpcrt4_protseq_sock_wait_for_new_connection,
2770 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
2771 },
2772 };
2773
2774 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
2775
2776 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
2777 {
2778 unsigned int i;
2779 for(i=0; i<ARRAYSIZE(protseq_list); i++)
2780 if (!strcmp(protseq_list[i].name, protseq))
2781 return &protseq_list[i];
2782 return NULL;
2783 }
2784
2785 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
2786 {
2787 unsigned int i;
2788 for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
2789 if (!strcmp(conn_protseq_list[i].name, protseq))
2790 return &conn_protseq_list[i];
2791 return NULL;
2792 }
2793
2794 /**** interface to rest of code ****/
2795
2796 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
2797 {
2798 TRACE("(Connection == ^%p)\n", Connection);
2799
2800 assert(!Connection->server);
2801 return Connection->ops->open_connection_client(Connection);
2802 }
2803
2804 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
2805 {
2806 TRACE("(Connection == ^%p)\n", Connection);
2807 if (SecIsValidHandle(&Connection->ctx))
2808 {
2809 DeleteSecurityContext(&Connection->ctx);
2810 SecInvalidateHandle(&Connection->ctx);
2811 }
2812 rpcrt4_conn_close(Connection);
2813 return RPC_S_OK;
2814 }
2815
2816 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
2817 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
2818 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
2819 {
2820 static LONG next_id;
2821 const struct connection_ops *ops;
2822 RpcConnection* NewConnection;
2823
2824 ops = rpcrt4_get_conn_protseq_ops(Protseq);
2825 if (!ops)
2826 {
2827 FIXME("not supported for protseq %s\n", Protseq);
2828 return RPC_S_PROTSEQ_NOT_SUPPORTED;
2829 }
2830
2831 NewConnection = ops->alloc();
2832 NewConnection->Next = NULL;
2833 NewConnection->server_binding = NULL;
2834 NewConnection->server = server;
2835 NewConnection->ops = ops;
2836 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
2837 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
2838 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
2839 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
2840 memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
2841 NewConnection->NextCallId = 1;
2842
2843 SecInvalidateHandle(&NewConnection->ctx);
2844 memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
2845 NewConnection->attr = 0;
2846 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
2847 NewConnection->AuthInfo = AuthInfo;
2848 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
2849 NewConnection->encryption_auth_len = 0;
2850 NewConnection->signature_auth_len = 0;
2851 if (QOS) RpcQualityOfService_AddRef(QOS);
2852 NewConnection->QOS = QOS;
2853
2854 list_init(&NewConnection->conn_pool_entry);
2855 NewConnection->async_state = NULL;
2856
2857 TRACE("connection: %p\n", NewConnection);
2858 *Connection = NewConnection;
2859
2860 return RPC_S_OK;
2861 }
2862
2863 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
2864 {
2865 RPC_STATUS err;
2866
2867 err = RPCRT4_CreateConnection(Connection, OldConnection->server,
2868 rpcrt4_conn_get_name(OldConnection),
2869 OldConnection->NetworkAddr,
2870 OldConnection->Endpoint, NULL,
2871 OldConnection->AuthInfo, OldConnection->QOS);
2872 if (err == RPC_S_OK)
2873 rpcrt4_conn_handoff(OldConnection, *Connection);
2874 return err;
2875 }
2876
2877 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
2878 {
2879 TRACE("connection: %p\n", Connection);
2880
2881 RPCRT4_CloseConnection(Connection);
2882 RPCRT4_strfree(Connection->Endpoint);
2883 RPCRT4_strfree(Connection->NetworkAddr);
2884 HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
2885 if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
2886 if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
2887
2888 /* server-only */
2889 if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
2890
2891 HeapFree(GetProcessHeap(), 0, Connection);
2892 return RPC_S_OK;
2893 }
2894
2895 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
2896 size_t *tower_size,
2897 const char *protseq,
2898 const char *networkaddr,
2899 const char *endpoint)
2900 {
2901 twr_empty_floor_t *protocol_floor;
2902 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
2903
2904 *tower_size = 0;
2905
2906 if (!protseq_ops)
2907 return RPC_S_INVALID_RPC_PROTSEQ;
2908
2909 if (!tower_data)
2910 {
2911 *tower_size = sizeof(*protocol_floor);
2912 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
2913 return RPC_S_OK;
2914 }
2915
2916 protocol_floor = (twr_empty_floor_t *)tower_data;
2917 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
2918 protocol_floor->protid = protseq_ops->epm_protocols[0];
2919 protocol_floor->count_rhs = 0;
2920
2921 tower_data += sizeof(*protocol_floor);
2922
2923 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
2924 if (!*tower_size)
2925 return EPT_S_NOT_REGISTERED;
2926
2927 *tower_size += sizeof(*protocol_floor);
2928
2929 return RPC_S_OK;
2930 }
2931
2932 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
2933 size_t tower_size,
2934 char **protseq,
2935 char **networkaddr,
2936 char **endpoint)
2937 {
2938 const twr_empty_floor_t *protocol_floor;
2939 const twr_empty_floor_t *floor4;
2940 const struct connection_ops *protseq_ops = NULL;
2941 RPC_STATUS status;
2942 unsigned int i;
2943
2944 if (tower_size < sizeof(*protocol_floor))
2945 return EPT_S_NOT_REGISTERED;
2946
2947 protocol_floor = (const twr_empty_floor_t *)tower_data;
2948 tower_data += sizeof(*protocol_floor);
2949 tower_size -= sizeof(*protocol_floor);
2950 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
2951 (protocol_floor->count_rhs > tower_size))
2952 return EPT_S_NOT_REGISTERED;
2953 tower_data += protocol_floor->count_rhs;
2954 tower_size -= protocol_floor->count_rhs;
2955
2956 floor4 = (const twr_empty_floor_t *)tower_data;
2957 if ((tower_size < sizeof(*floor4)) ||
2958 (floor4->count_lhs != sizeof(floor4->protid)))
2959 return EPT_S_NOT_REGISTERED;
2960
2961 for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
2962 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
2963 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
2964 {
2965 protseq_ops = &conn_protseq_list[i];
2966 break;
2967 }
2968
2969 if (!protseq_ops)
2970 return EPT_S_NOT_REGISTERED;
2971
2972 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
2973
2974 if ((status == RPC_S_OK) && protseq)
2975 {
2976 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
2977 strcpy(*protseq, protseq_ops->name);
2978 }
2979
2980 return status;
2981 }
2982
2983 /***********************************************************************
2984 * RpcNetworkIsProtseqValidW (RPCRT4.@)
2985 *
2986 * Checks if the given protocol sequence is known by the RPC system.
2987 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
2988 *
2989 */
2990 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
2991 {
2992 char ps[0x10];
2993
2994 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
2995 ps, sizeof ps, NULL, NULL);
2996 if (rpcrt4_get_conn_protseq_ops(ps))
2997 return RPC_S_OK;
2998
2999 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3000
3001 return RPC_S_INVALID_RPC_PROTSEQ;
3002 }
3003
3004 /***********************************************************************
3005 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3006 */
3007 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3008 {
3009 UNICODE_STRING protseqW;
3010
3011 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3012 {
3013 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3014 RtlFreeUnicodeString(&protseqW);
3015 return ret;
3016 }
3017 return RPC_S_OUT_OF_MEMORY;
3018 }