ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rpc_transport.c
Go to the documentation of this file.
00001 /*
00002  * RPC transport layer
00003  *
00004  * Copyright 2001 Ove Kåven, TransGaming Technologies
00005  * Copyright 2003 Mike Hearn
00006  * Copyright 2004 Filip Navara
00007  * Copyright 2006 Mike McCormack
00008  * Copyright 2006 Damjan Jovanovic
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00023  *
00024  */
00025 
00026 #include "config.h"
00027 
00028 #include <stdarg.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <assert.h>
00032 #include <stdlib.h>
00033 #include <sys/types.h>
00034 
00035 #if defined(__MINGW32__) || defined (_MSC_VER)
00036 # include <ws2tcpip.h>
00037 # ifndef EADDRINUSE
00038 #  define EADDRINUSE WSAEADDRINUSE
00039 # endif
00040 # ifndef EAGAIN
00041 #  define EAGAIN WSAEWOULDBLOCK
00042 # endif
00043 # undef errno
00044 # define errno WSAGetLastError()
00045 #else
00046 # include <errno.h>
00047 # ifdef HAVE_UNISTD_H
00048 #  include <unistd.h>
00049 # endif
00050 # include <fcntl.h>
00051 # ifdef HAVE_SYS_SOCKET_H
00052 #  include <sys/socket.h>
00053 # endif
00054 # ifdef HAVE_NETINET_IN_H
00055 #  include <netinet/in.h>
00056 # endif
00057 # ifdef HAVE_NETINET_TCP_H
00058 #  include <netinet/tcp.h>
00059 # endif
00060 # ifdef HAVE_ARPA_INET_H
00061 #  include <arpa/inet.h>
00062 # endif
00063 # ifdef HAVE_NETDB_H
00064 #  include <netdb.h>
00065 # endif
00066 # ifdef HAVE_SYS_POLL_H
00067 #  include <sys/poll.h>
00068 # endif
00069 # ifdef HAVE_SYS_FILIO_H
00070 #  include <sys/filio.h>
00071 # endif
00072 # ifdef HAVE_SYS_IOCTL_H
00073 #  include <sys/ioctl.h>
00074 # endif
00075 # define closesocket close
00076 # define ioctlsocket ioctl
00077 #endif /* defined(__MINGW32__) || defined (_MSC_VER) */
00078 
00079 #include "windef.h"
00080 #include "winbase.h"
00081 #include "winnls.h"
00082 #include "winerror.h"
00083 #include "wininet.h"
00084 #include "winternl.h"
00085 #include "wine/unicode.h"
00086 
00087 #include "rpc.h"
00088 #include "rpcndr.h"
00089 
00090 #include "wine/debug.h"
00091 
00092 #include "rpc_binding.h"
00093 #include "rpc_assoc.h"
00094 #include "rpc_message.h"
00095 #include "rpc_server.h"
00096 #include "epm_towers.h"
00097 
00098 #ifndef SOL_TCP
00099 # define SOL_TCP IPPROTO_TCP
00100 #endif
00101 
00102 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
00103 
00104 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
00105 
00106 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection);
00107 
00108 /**** ncacn_np support ****/
00109 
00110 typedef struct _RpcConnection_np
00111 {
00112   RpcConnection common;
00113   HANDLE pipe;
00114   OVERLAPPED ovl;
00115   BOOL listening;
00116 } RpcConnection_np;
00117 
00118 static RpcConnection *rpcrt4_conn_np_alloc(void)
00119 {
00120   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
00121   if (npc)
00122   {
00123     npc->pipe = NULL;
00124     memset(&npc->ovl, 0, sizeof(npc->ovl));
00125     npc->listening = FALSE;
00126   }
00127   return &npc->common;
00128 }
00129 
00130 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
00131 {
00132   if (npc->listening)
00133     return RPC_S_OK;
00134 
00135   npc->listening = TRUE;
00136   for (;;)
00137   {
00138       if (ConnectNamedPipe(npc->pipe, &npc->ovl))
00139           return RPC_S_OK;
00140 
00141       switch(GetLastError())
00142       {
00143       case ERROR_PIPE_CONNECTED:
00144           SetEvent(npc->ovl.hEvent);
00145           return RPC_S_OK;
00146       case ERROR_IO_PENDING:
00147           /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
00148           return RPC_S_OK;
00149       case ERROR_NO_DATA_DETECTED:
00150           /* client has disconnected, retry */
00151           DisconnectNamedPipe( npc->pipe );
00152           break;
00153       default:
00154           npc->listening = FALSE;
00155           WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
00156           return RPC_S_OUT_OF_RESOURCES;
00157       }
00158   }
00159 }
00160 
00161 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
00162 {
00163   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00164   TRACE("listening on %s\n", pname);
00165 
00166   npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
00167                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
00168                                PIPE_UNLIMITED_INSTANCES,
00169                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
00170   if (npc->pipe == INVALID_HANDLE_VALUE) {
00171     WARN("CreateNamedPipe failed with error %d\n", GetLastError());
00172     if (GetLastError() == ERROR_FILE_EXISTS)
00173       return RPC_S_DUPLICATE_ENDPOINT;
00174     else
00175       return RPC_S_CANT_CREATE_ENDPOINT;
00176   }
00177 
00178   memset(&npc->ovl, 0, sizeof(npc->ovl));
00179   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00180 
00181   /* Note: we don't call ConnectNamedPipe here because it must be done in the
00182    * server thread as the thread must be alertable */
00183   return RPC_S_OK;
00184 }
00185 
00186 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
00187 {
00188   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00189   HANDLE pipe;
00190   DWORD err, dwMode;
00191 
00192   TRACE("connecting to %s\n", pname);
00193 
00194   while (TRUE) {
00195     DWORD dwFlags = 0;
00196     if (Connection->QOS)
00197     {
00198         dwFlags = SECURITY_SQOS_PRESENT;
00199         switch (Connection->QOS->qos->ImpersonationType)
00200         {
00201             case RPC_C_IMP_LEVEL_DEFAULT:
00202                 /* FIXME: what to do here? */
00203                 break;
00204             case RPC_C_IMP_LEVEL_ANONYMOUS:
00205                 dwFlags |= SECURITY_ANONYMOUS;
00206                 break;
00207             case RPC_C_IMP_LEVEL_IDENTIFY:
00208                 dwFlags |= SECURITY_IDENTIFICATION;
00209                 break;
00210             case RPC_C_IMP_LEVEL_IMPERSONATE:
00211                 dwFlags |= SECURITY_IMPERSONATION;
00212                 break;
00213             case RPC_C_IMP_LEVEL_DELEGATE:
00214                 dwFlags |= SECURITY_DELEGATION;
00215                 break;
00216         }
00217         if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
00218             dwFlags |= SECURITY_CONTEXT_TRACKING;
00219     }
00220     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
00221                        OPEN_EXISTING, dwFlags, 0);
00222     if (pipe != INVALID_HANDLE_VALUE) break;
00223     err = GetLastError();
00224     if (err == ERROR_PIPE_BUSY) {
00225       TRACE("connection failed, error=%x\n", err);
00226       return RPC_S_SERVER_TOO_BUSY;
00227     } else if (err == ERROR_BAD_NETPATH) {
00228       TRACE("connection failed, error=%x\n", err);
00229       return RPC_S_SERVER_UNAVAILABLE;
00230     }
00231     if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
00232       err = GetLastError();
00233       WARN("connection failed, error=%x\n", err);
00234       return RPC_S_SERVER_UNAVAILABLE;
00235     }
00236   }
00237 
00238   /* success */
00239   memset(&npc->ovl, 0, sizeof(npc->ovl));
00240   /* pipe is connected; change to message-read mode. */
00241   dwMode = PIPE_READMODE_MESSAGE;
00242   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
00243   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00244   npc->pipe = pipe;
00245 
00246   return RPC_S_OK;
00247 }
00248 
00249 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
00250 {
00251   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00252   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
00253   RPC_STATUS r;
00254   LPSTR pname;
00255 
00256   /* already connected? */
00257   if (npc->pipe)
00258     return RPC_S_OK;
00259 
00260   /* protseq=ncalrpc: supposed to use NT LPC ports,
00261    * but we'll implement it with named pipes for now */
00262   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
00263   strcat(strcpy(pname, prefix), Connection->Endpoint);
00264   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
00265   I_RpcFree(pname);
00266 
00267   return r;
00268 }
00269 
00270 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
00271 {
00272   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
00273   RPC_STATUS r;
00274   LPSTR pname;
00275   RpcConnection *Connection;
00276   char generated_endpoint[22];
00277 
00278   if (!endpoint)
00279   {
00280     static LONG lrpc_nameless_id;
00281     DWORD process_id = GetCurrentProcessId();
00282     ULONG id = InterlockedIncrement(&lrpc_nameless_id);
00283     snprintf(generated_endpoint, sizeof(generated_endpoint),
00284              "LRPC%08x.%08x", process_id, id);
00285     endpoint = generated_endpoint;
00286   }
00287 
00288   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
00289                               endpoint, NULL, NULL, NULL);
00290   if (r != RPC_S_OK)
00291       return r;
00292 
00293   /* protseq=ncalrpc: supposed to use NT LPC ports,
00294    * but we'll implement it with named pipes for now */
00295   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
00296   strcat(strcpy(pname, prefix), Connection->Endpoint);
00297   r = rpcrt4_conn_create_pipe(Connection, pname);
00298   I_RpcFree(pname);
00299 
00300   EnterCriticalSection(&protseq->cs);
00301   Connection->Next = protseq->conn;
00302   protseq->conn = Connection;
00303   LeaveCriticalSection(&protseq->cs);
00304 
00305   return r;
00306 }
00307 
00308 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
00309 {
00310   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00311   static const char prefix[] = "\\\\";
00312   static const char local[] =".";
00313   RPC_STATUS r;
00314   LPSTR pname;
00315   INT size;
00316 
00317   /* already connected? */
00318   if (npc->pipe)
00319     return RPC_S_OK;
00320 
00321   /* protseq=ncacn_np: named pipes */
00322   size = strlen(prefix);
00323   if (Connection->NetworkAddr == NULL || strlen(Connection->NetworkAddr) == 0)
00324     size += strlen(local);
00325   else
00326     size += strlen(Connection->NetworkAddr);
00327   size += strlen(Connection->Endpoint) + 1;
00328 
00329   pname = I_RpcAllocate(size);
00330   strcpy(pname, prefix);
00331   if (Connection->NetworkAddr == NULL || strlen(Connection->NetworkAddr) == 0)
00332     strcat(pname, local);
00333   else
00334     strcat(pname, Connection->NetworkAddr);
00335   strcat(pname, Connection->Endpoint);
00336   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
00337   I_RpcFree(pname);
00338 
00339   return r;
00340 }
00341 
00342 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
00343 {
00344   static const char prefix[] = "\\\\.";
00345   RPC_STATUS r;
00346   LPSTR pname;
00347   RpcConnection *Connection;
00348   char generated_endpoint[21];
00349 
00350   if (!endpoint)
00351   {
00352     static LONG np_nameless_id;
00353     DWORD process_id = GetCurrentProcessId();
00354     ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
00355     snprintf(generated_endpoint, sizeof(generated_endpoint),
00356              "\\\\pipe\\\\%08x.%03x", process_id, id);
00357     endpoint = generated_endpoint;
00358   }
00359 
00360   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
00361                               endpoint, NULL, NULL, NULL);
00362   if (r != RPC_S_OK)
00363     return r;
00364 
00365   /* protseq=ncacn_np: named pipes */
00366   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
00367   strcat(strcpy(pname, prefix), Connection->Endpoint);
00368   r = rpcrt4_conn_create_pipe(Connection, pname);
00369   I_RpcFree(pname);
00370 
00371   EnterCriticalSection(&protseq->cs);
00372   Connection->Next = protseq->conn;
00373   protseq->conn = Connection;
00374   LeaveCriticalSection(&protseq->cs);
00375 
00376   return r;
00377 }
00378 
00379 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
00380 {    
00381   /* because of the way named pipes work, we'll transfer the connected pipe
00382    * to the child, then reopen the server binding to continue listening */
00383 
00384   new_npc->pipe = old_npc->pipe;
00385   new_npc->ovl = old_npc->ovl;
00386   old_npc->pipe = 0;
00387   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
00388   old_npc->listening = FALSE;
00389 }
00390 
00391 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
00392 {
00393   RPC_STATUS status;
00394   LPSTR pname;
00395   static const char prefix[] = "\\\\.";
00396 
00397   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
00398 
00399   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
00400   strcat(strcpy(pname, prefix), old_conn->Endpoint);
00401   status = rpcrt4_conn_create_pipe(old_conn, pname);
00402   I_RpcFree(pname);
00403 
00404   return status;
00405 }
00406 
00407 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
00408 {
00409   RPC_STATUS status;
00410   LPSTR pname;
00411   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
00412 
00413   TRACE("%s\n", old_conn->Endpoint);
00414 
00415   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
00416 
00417   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
00418   strcat(strcpy(pname, prefix), old_conn->Endpoint);
00419   status = rpcrt4_conn_create_pipe(old_conn, pname);
00420   I_RpcFree(pname);
00421     
00422   return status;
00423 }
00424 
00425 static int rpcrt4_conn_np_read(RpcConnection *Connection,
00426                         void *buffer, unsigned int count)
00427 {
00428   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00429   char *buf = buffer;
00430   BOOL ret = TRUE;
00431   unsigned int bytes_left = count;
00432   OVERLAPPED ovl;
00433   
00434   ZeroMemory(&ovl, sizeof(ovl));
00435   ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00436 
00437   while (bytes_left)
00438   {
00439     DWORD bytes_read;
00440     ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, &ovl);
00441     if ((!ret || !bytes_read) && (GetLastError() != ERROR_IO_PENDING))
00442         break;
00443     ret = GetOverlappedResult(npc->pipe, &ovl, &bytes_read, TRUE);
00444     if (!ret && (GetLastError() != ERROR_MORE_DATA))
00445         break;
00446     bytes_left -= bytes_read;
00447     buf += bytes_read;
00448   }
00449   CloseHandle(ovl.hEvent);
00450   return ret ? count : -1;
00451 }
00452 
00453 static int rpcrt4_conn_np_write(RpcConnection *Connection,
00454                              const void *buffer, unsigned int count)
00455 {
00456   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00457   const char *buf = buffer;
00458   BOOL ret = TRUE;
00459   unsigned int bytes_left = count;
00460   OVERLAPPED ovl;
00461   
00462   ZeroMemory(&ovl, sizeof(ovl));
00463   ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
00464 
00465   while (bytes_left)
00466   {
00467     DWORD bytes_written;
00468     ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, &ovl);
00469     if ((!ret || !bytes_written) && (GetLastError() != ERROR_IO_PENDING))
00470         break;
00471 
00472     ret = GetOverlappedResult(npc->pipe, &ovl, &bytes_written, TRUE);
00473     if (!ret && (GetLastError() != ERROR_MORE_DATA))
00474         break;
00475     bytes_left -= bytes_written;
00476     buf += bytes_written;
00477   }
00478   CloseHandle(ovl.hEvent);
00479   return ret ? count : -1;
00480 }
00481 
00482 static int rpcrt4_conn_np_close(RpcConnection *Connection)
00483 {
00484   RpcConnection_np *npc = (RpcConnection_np *) Connection;
00485   if (npc->pipe) {
00486     FlushFileBuffers(npc->pipe);
00487     CloseHandle(npc->pipe);
00488     npc->pipe = 0;
00489   }
00490   if (npc->ovl.hEvent) {
00491     CloseHandle(npc->ovl.hEvent);
00492     npc->ovl.hEvent = 0;
00493   }
00494   return 0;
00495 }
00496 
00497 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
00498 {
00499     /* FIXME: implement when named pipe writes use overlapped I/O */
00500 }
00501 
00502 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
00503 {
00504     /* FIXME: implement when named pipe writes use overlapped I/O */
00505     return -1;
00506 }
00507 
00508 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
00509                                                const char *networkaddr,
00510                                                const char *endpoint)
00511 {
00512     twr_empty_floor_t *smb_floor;
00513     twr_empty_floor_t *nb_floor;
00514     size_t size;
00515     size_t networkaddr_size;
00516     size_t endpoint_size;
00517 
00518     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
00519 
00520     networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
00521     endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
00522     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
00523 
00524     if (!tower_data)
00525         return size;
00526 
00527     smb_floor = (twr_empty_floor_t *)tower_data;
00528 
00529     tower_data += sizeof(*smb_floor);
00530 
00531     smb_floor->count_lhs = sizeof(smb_floor->protid);
00532     smb_floor->protid = EPM_PROTOCOL_SMB;
00533     smb_floor->count_rhs = endpoint_size;
00534 
00535     if (endpoint)
00536         memcpy(tower_data, endpoint, endpoint_size);
00537     else
00538         tower_data[0] = 0;
00539     tower_data += endpoint_size;
00540 
00541     nb_floor = (twr_empty_floor_t *)tower_data;
00542 
00543     tower_data += sizeof(*nb_floor);
00544 
00545     nb_floor->count_lhs = sizeof(nb_floor->protid);
00546     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
00547     nb_floor->count_rhs = networkaddr_size;
00548 
00549     if (networkaddr)
00550         memcpy(tower_data, networkaddr, networkaddr_size);
00551     else
00552         tower_data[0] = 0;
00553 
00554     return size;
00555 }
00556 
00557 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
00558                                                      size_t tower_size,
00559                                                      char **networkaddr,
00560                                                      char **endpoint)
00561 {
00562     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
00563     const twr_empty_floor_t *nb_floor;
00564 
00565     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
00566 
00567     if (tower_size < sizeof(*smb_floor))
00568         return EPT_S_NOT_REGISTERED;
00569 
00570     tower_data += sizeof(*smb_floor);
00571     tower_size -= sizeof(*smb_floor);
00572 
00573     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
00574         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
00575         (smb_floor->count_rhs > tower_size) ||
00576         (tower_data[smb_floor->count_rhs - 1] != '\0'))
00577         return EPT_S_NOT_REGISTERED;
00578 
00579     if (endpoint)
00580     {
00581         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
00582         if (!*endpoint)
00583             return RPC_S_OUT_OF_RESOURCES;
00584         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
00585     }
00586     tower_data += smb_floor->count_rhs;
00587     tower_size -= smb_floor->count_rhs;
00588 
00589     if (tower_size < sizeof(*nb_floor))
00590         return EPT_S_NOT_REGISTERED;
00591 
00592     nb_floor = (const twr_empty_floor_t *)tower_data;
00593 
00594     tower_data += sizeof(*nb_floor);
00595     tower_size -= sizeof(*nb_floor);
00596 
00597     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
00598         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
00599         (nb_floor->count_rhs > tower_size) ||
00600         (tower_data[nb_floor->count_rhs - 1] != '\0'))
00601         return EPT_S_NOT_REGISTERED;
00602 
00603     if (networkaddr)
00604     {
00605         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
00606         if (!*networkaddr)
00607         {
00608             if (endpoint)
00609             {
00610                 I_RpcFree(*endpoint);
00611                 *endpoint = NULL;
00612             }
00613             return RPC_S_OUT_OF_RESOURCES;
00614         }
00615         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
00616     }
00617 
00618     return RPC_S_OK;
00619 }
00620 
00621 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
00622 {
00623     RpcConnection_np *npc = (RpcConnection_np *)conn;
00624     BOOL ret;
00625 
00626     TRACE("(%p)\n", conn);
00627 
00628     if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
00629         return RPCRT4_default_impersonate_client(conn);
00630 
00631     ret = ImpersonateNamedPipeClient(npc->pipe);
00632     if (!ret)
00633     {
00634         DWORD error = GetLastError();
00635         WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
00636         switch (error)
00637         {
00638         case ERROR_CANNOT_IMPERSONATE:
00639             return RPC_S_NO_CONTEXT_AVAILABLE;
00640         }
00641     }
00642     return RPC_S_OK;
00643 }
00644 
00645 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
00646 {
00647     BOOL ret;
00648 
00649     TRACE("(%p)\n", conn);
00650 
00651     if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
00652         return RPCRT4_default_revert_to_self(conn);
00653 
00654     ret = RevertToSelf();
00655     if (!ret)
00656     {
00657         WARN("RevertToSelf failed with error %u\n", GetLastError());
00658         return RPC_S_NO_CONTEXT_AVAILABLE;
00659     }
00660     return RPC_S_OK;
00661 }
00662 
00663 typedef struct _RpcServerProtseq_np
00664 {
00665     RpcServerProtseq common;
00666     HANDLE mgr_event;
00667 } RpcServerProtseq_np;
00668 
00669 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
00670 {
00671     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
00672     if (ps)
00673         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
00674     return &ps->common;
00675 }
00676 
00677 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
00678 {
00679     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
00680     SetEvent(npps->mgr_event);
00681 }
00682 
00683 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
00684 {
00685     HANDLE *objs = prev_array;
00686     RpcConnection_np *conn;
00687     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
00688     
00689     EnterCriticalSection(&protseq->cs);
00690     
00691     /* open and count connections */
00692     *count = 1;
00693     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
00694     while (conn) {
00695         rpcrt4_conn_listen_pipe(conn);
00696         if (conn->ovl.hEvent)
00697             (*count)++;
00698         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
00699     }
00700     
00701     /* make array of connections */
00702     if (objs)
00703         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
00704     else
00705         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
00706     if (!objs)
00707     {
00708         ERR("couldn't allocate objs\n");
00709         LeaveCriticalSection(&protseq->cs);
00710         return NULL;
00711     }
00712     
00713     objs[0] = npps->mgr_event;
00714     *count = 1;
00715     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
00716     while (conn) {
00717         if ((objs[*count] = conn->ovl.hEvent))
00718             (*count)++;
00719         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
00720     }
00721     LeaveCriticalSection(&protseq->cs);
00722     return objs;
00723 }
00724 
00725 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
00726 {
00727     HeapFree(GetProcessHeap(), 0, array);
00728 }
00729 
00730 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
00731 {
00732     HANDLE b_handle;
00733     HANDLE *objs = wait_array;
00734     DWORD res;
00735     RpcConnection *cconn;
00736     RpcConnection_np *conn;
00737     
00738     if (!objs)
00739         return -1;
00740 
00741     do
00742     {
00743         /* an alertable wait isn't strictly necessary, but due to our
00744          * overlapped I/O implementation in Wine we need to free some memory
00745          * by the file user APC being called, even if no completion routine was
00746          * specified at the time of starting the async operation */
00747         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
00748     } while (res == WAIT_IO_COMPLETION);
00749 
00750     if (res == WAIT_OBJECT_0)
00751         return 0;
00752     else if (res == WAIT_FAILED)
00753     {
00754         ERR("wait failed with error %d\n", GetLastError());
00755         return -1;
00756     }
00757     else
00758     {
00759         b_handle = objs[res - WAIT_OBJECT_0];
00760         /* find which connection got a RPC */
00761         EnterCriticalSection(&protseq->cs);
00762         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
00763         while (conn) {
00764             if (b_handle == conn->ovl.hEvent) break;
00765             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
00766         }
00767         cconn = NULL;
00768         if (conn)
00769             RPCRT4_SpawnConnection(&cconn, &conn->common);
00770         else
00771             ERR("failed to locate connection for handle %p\n", b_handle);
00772         LeaveCriticalSection(&protseq->cs);
00773         if (cconn)
00774         {
00775             RPCRT4_new_client(cconn);
00776             return 1;
00777         }
00778         else return -1;
00779     }
00780 }
00781 
00782 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
00783                                               const char *networkaddr,
00784                                               const char *endpoint)
00785 {
00786     twr_empty_floor_t *pipe_floor;
00787     size_t size;
00788     size_t endpoint_size;
00789 
00790     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
00791 
00792     endpoint_size = strlen(endpoint) + 1;
00793     size = sizeof(*pipe_floor) + endpoint_size;
00794 
00795     if (!tower_data)
00796         return size;
00797 
00798     pipe_floor = (twr_empty_floor_t *)tower_data;
00799 
00800     tower_data += sizeof(*pipe_floor);
00801 
00802     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
00803     pipe_floor->protid = EPM_PROTOCOL_PIPE;
00804     pipe_floor->count_rhs = endpoint_size;
00805 
00806     memcpy(tower_data, endpoint, endpoint_size);
00807 
00808     return size;
00809 }
00810 
00811 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
00812                                                     size_t tower_size,
00813                                                     char **networkaddr,
00814                                                     char **endpoint)
00815 {
00816     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
00817 
00818     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
00819 
00820     if (tower_size < sizeof(*pipe_floor))
00821         return EPT_S_NOT_REGISTERED;
00822 
00823     tower_data += sizeof(*pipe_floor);
00824     tower_size -= sizeof(*pipe_floor);
00825 
00826     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
00827         (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
00828         (pipe_floor->count_rhs > tower_size) ||
00829         (tower_data[pipe_floor->count_rhs - 1] != '\0'))
00830         return EPT_S_NOT_REGISTERED;
00831 
00832     if (networkaddr)
00833         *networkaddr = NULL;
00834 
00835     if (endpoint)
00836     {
00837         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
00838         if (!*endpoint)
00839             return RPC_S_OUT_OF_RESOURCES;
00840         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
00841     }
00842 
00843     return RPC_S_OK;
00844 }
00845 
00846 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
00847 {
00848     return FALSE;
00849 }
00850 
00851 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
00852                                            unsigned char *in_buffer,
00853                                            unsigned int in_size,
00854                                            unsigned char *out_buffer,
00855                                            unsigned int *out_size)
00856 {
00857     /* since this protocol is local to the machine there is no need to
00858      * authenticate the caller */
00859     *out_size = 0;
00860     return RPC_S_OK;
00861 }
00862 
00863 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
00864     enum secure_packet_direction dir,
00865     RpcPktHdr *hdr, unsigned int hdr_size,
00866     unsigned char *stub_data, unsigned int stub_data_size,
00867     RpcAuthVerifier *auth_hdr,
00868     unsigned char *auth_value, unsigned int auth_value_size)
00869 {
00870     /* since this protocol is local to the machine there is no need to secure
00871      * the packet */
00872     return RPC_S_OK;
00873 }
00874 
00875 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
00876     RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
00877     ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
00878 {
00879     TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
00880           server_princ_name, authn_level, authn_svc, authz_svc, flags);
00881 
00882     if (privs)
00883     {
00884         FIXME("privs not implemented\n");
00885         *privs = NULL;
00886     }
00887     if (server_princ_name)
00888     {
00889         FIXME("server_princ_name not implemented\n");
00890         *server_princ_name = NULL;
00891     }
00892     if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
00893     if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
00894     if (authz_svc)
00895     {
00896         FIXME("authorization service not implemented\n");
00897         *authz_svc = RPC_C_AUTHZ_NONE;
00898     }
00899     if (flags)
00900         FIXME("flags 0x%x not implemented\n", flags);
00901 
00902     return RPC_S_OK;
00903 }
00904 
00905 /**** ncacn_ip_tcp support ****/
00906 
00907 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
00908                                              const char *networkaddr,
00909                                              unsigned char tcp_protid,
00910                                              const char *endpoint)
00911 {
00912     twr_tcp_floor_t *tcp_floor;
00913     twr_ipv4_floor_t *ipv4_floor;
00914     struct addrinfo *ai;
00915     struct addrinfo hints;
00916     int ret;
00917     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
00918 
00919     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
00920 
00921     if (!tower_data)
00922         return size;
00923 
00924     tcp_floor = (twr_tcp_floor_t *)tower_data;
00925     tower_data += sizeof(*tcp_floor);
00926 
00927     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
00928 
00929     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
00930     tcp_floor->protid = tcp_protid;
00931     tcp_floor->count_rhs = sizeof(tcp_floor->port);
00932 
00933     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
00934     ipv4_floor->protid = EPM_PROTOCOL_IP;
00935     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
00936 
00937     hints.ai_flags          = AI_NUMERICHOST;
00938     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
00939     hints.ai_family         = PF_INET;
00940     hints.ai_socktype       = SOCK_STREAM;
00941     hints.ai_protocol       = IPPROTO_TCP;
00942     hints.ai_addrlen        = 0;
00943     hints.ai_addr           = NULL;
00944     hints.ai_canonname      = NULL;
00945     hints.ai_next           = NULL;
00946 
00947     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
00948     if (ret)
00949     {
00950         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
00951         if (ret)
00952         {
00953             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
00954             return 0;
00955         }
00956     }
00957 
00958     if (ai->ai_family == PF_INET)
00959     {
00960         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
00961         tcp_floor->port = sin->sin_port;
00962         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
00963     }
00964     else
00965     {
00966         ERR("unexpected protocol family %d\n", ai->ai_family);
00967         return 0;
00968     }
00969 
00970     freeaddrinfo(ai);
00971 
00972     return size;
00973 }
00974 
00975 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
00976                                                    size_t tower_size,
00977                                                    char **networkaddr,
00978                                                    unsigned char tcp_protid,
00979                                                    char **endpoint)
00980 {
00981     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
00982     const twr_ipv4_floor_t *ipv4_floor;
00983     struct in_addr in_addr;
00984 
00985     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
00986 
00987     if (tower_size < sizeof(*tcp_floor))
00988         return EPT_S_NOT_REGISTERED;
00989 
00990     tower_data += sizeof(*tcp_floor);
00991     tower_size -= sizeof(*tcp_floor);
00992 
00993     if (tower_size < sizeof(*ipv4_floor))
00994         return EPT_S_NOT_REGISTERED;
00995 
00996     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
00997 
00998     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
00999         (tcp_floor->protid != tcp_protid) ||
01000         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
01001         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
01002         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
01003         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
01004         return EPT_S_NOT_REGISTERED;
01005 
01006     if (endpoint)
01007     {
01008         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
01009         if (!*endpoint)
01010             return RPC_S_OUT_OF_RESOURCES;
01011         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
01012     }
01013 
01014     if (networkaddr)
01015     {
01016         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
01017         if (!*networkaddr)
01018         {
01019             if (endpoint)
01020             {
01021                 I_RpcFree(*endpoint);
01022                 *endpoint = NULL;
01023             }
01024             return RPC_S_OUT_OF_RESOURCES;
01025         }
01026         in_addr.s_addr = ipv4_floor->ipv4addr;
01027         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
01028         {
01029             ERR("inet_ntop: %s\n", strerror(errno));
01030             I_RpcFree(*networkaddr);
01031             *networkaddr = NULL;
01032             if (endpoint)
01033             {
01034                 I_RpcFree(*endpoint);
01035                 *endpoint = NULL;
01036             }
01037             return EPT_S_NOT_REGISTERED;
01038         }
01039     }
01040 
01041     return RPC_S_OK;
01042 }
01043 
01044 typedef struct _RpcConnection_tcp
01045 {
01046   RpcConnection common;
01047   int sock;
01048 #ifdef HAVE_SOCKETPAIR
01049   int cancel_fds[2];
01050 #else
01051   HANDLE sock_event;
01052   HANDLE cancel_event;
01053 #endif
01054 } RpcConnection_tcp;
01055 
01056 #ifdef HAVE_SOCKETPAIR
01057 
01058 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
01059 {
01060   if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
01061   {
01062     ERR("socketpair() failed: %s\n", strerror(errno));
01063     return FALSE;
01064   }
01065   return TRUE;
01066 }
01067 
01068 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
01069 {
01070   struct pollfd pfds[2];
01071   pfds[0].fd = tcpc->sock;
01072   pfds[0].events = POLLIN;
01073   pfds[1].fd = tcpc->cancel_fds[0];
01074   pfds[1].events = POLLIN;
01075   if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
01076   {
01077     ERR("poll() failed: %s\n", strerror(errno));
01078     return FALSE;
01079   }
01080   if (pfds[1].revents & POLLIN) /* canceled */
01081   {
01082     char dummy;
01083     read(pfds[1].fd, &dummy, sizeof(dummy));
01084     return FALSE;
01085   }
01086   return TRUE;
01087 }
01088 
01089 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
01090 {
01091   struct pollfd pfd;
01092   pfd.fd = tcpc->sock;
01093   pfd.events = POLLOUT;
01094   if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
01095   {
01096     ERR("poll() failed: %s\n", strerror(errno));
01097     return FALSE;
01098   }
01099   return TRUE;
01100 }
01101 
01102 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
01103 {
01104   char dummy = 1;
01105 
01106   write(tcpc->cancel_fds[1], &dummy, 1);
01107 }
01108 
01109 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
01110 {
01111   close(tcpc->cancel_fds[0]);
01112   close(tcpc->cancel_fds[1]);
01113 }
01114 
01115 #else /* HAVE_SOCKETPAIR */
01116 
01117 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
01118 {
01119   static BOOL wsa_inited;
01120   if (!wsa_inited)
01121   {
01122     WSADATA wsadata;
01123     WSAStartup(MAKEWORD(2, 2), &wsadata);
01124     /* Note: WSAStartup can be called more than once so we don't bother with
01125      * making accesses to wsa_inited thread-safe */
01126     wsa_inited = TRUE;
01127   }
01128   tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01129   tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01130   if (!tcpc->sock_event || !tcpc->cancel_event)
01131   {
01132     ERR("event creation failed\n");
01133     if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
01134     return FALSE;
01135   }
01136   return TRUE;
01137 }
01138 
01139 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
01140 {
01141   HANDLE wait_handles[2];
01142   DWORD res;
01143   if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
01144   {
01145     ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
01146     return FALSE;
01147   }
01148   wait_handles[0] = tcpc->sock_event;
01149   wait_handles[1] = tcpc->cancel_event;
01150   res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
01151   switch (res)
01152   {
01153   case WAIT_OBJECT_0:
01154     return TRUE;
01155   case WAIT_OBJECT_0 + 1:
01156     return FALSE;
01157   default:
01158     ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
01159     return FALSE;
01160   }
01161 }
01162 
01163 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
01164 {
01165   DWORD res;
01166   if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
01167   {
01168     ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
01169     return FALSE;
01170   }
01171   res = WaitForSingleObject(tcpc->sock_event, INFINITE);
01172   switch (res)
01173   {
01174   case WAIT_OBJECT_0:
01175     return TRUE;
01176   default:
01177     ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
01178     return FALSE;
01179   }
01180 }
01181 
01182 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
01183 {
01184   SetEvent(tcpc->cancel_event);
01185 }
01186 
01187 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
01188 {
01189   CloseHandle(tcpc->sock_event);
01190   CloseHandle(tcpc->cancel_event);
01191 }
01192 
01193 #endif
01194 
01195 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
01196 {
01197   RpcConnection_tcp *tcpc;
01198   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
01199   if (tcpc == NULL)
01200     return NULL;
01201   tcpc->sock = -1;
01202   if (!rpcrt4_sock_wait_init(tcpc))
01203   {
01204     HeapFree(GetProcessHeap(), 0, tcpc);
01205     return NULL;
01206   }
01207   return &tcpc->common;
01208 }
01209 
01210 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
01211 {
01212   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01213   int sock;
01214   int ret;
01215   struct addrinfo *ai;
01216   struct addrinfo *ai_cur;
01217   struct addrinfo hints;
01218 
01219   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
01220 
01221   if (tcpc->sock != -1)
01222     return RPC_S_OK;
01223 
01224   hints.ai_flags          = 0;
01225   hints.ai_family         = PF_UNSPEC;
01226   hints.ai_socktype       = SOCK_STREAM;
01227   hints.ai_protocol       = IPPROTO_TCP;
01228   hints.ai_addrlen        = 0;
01229   hints.ai_addr           = NULL;
01230   hints.ai_canonname      = NULL;
01231   hints.ai_next           = NULL;
01232 
01233   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
01234   if (ret)
01235   {
01236     ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
01237       Connection->Endpoint, gai_strerror(ret));
01238     return RPC_S_SERVER_UNAVAILABLE;
01239   }
01240 
01241   for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
01242   {
01243     int val;
01244     u_long nonblocking;
01245 
01246     if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
01247     {
01248       TRACE("skipping non-IP/IPv6 address family\n");
01249       continue;
01250     }
01251 
01252     if (TRACE_ON(rpc))
01253     {
01254       char host[256];
01255       char service[256];
01256       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
01257         host, sizeof(host), service, sizeof(service),
01258         NI_NUMERICHOST | NI_NUMERICSERV);
01259       TRACE("trying %s:%s\n", host, service);
01260     }
01261 
01262     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
01263     if (sock == -1)
01264     {
01265       WARN("socket() failed: %s\n", strerror(errno));
01266       continue;
01267     }
01268 
01269     if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
01270     {
01271       WARN("connect() failed: %s\n", strerror(errno));
01272       closesocket(sock);
01273       continue;
01274     }
01275 
01276     /* RPC depends on having minimal latency so disable the Nagle algorithm */
01277     val = 1;
01278     setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
01279     nonblocking = 1;
01280     ioctlsocket(sock, FIONBIO, &nonblocking);
01281 
01282     tcpc->sock = sock;
01283 
01284     freeaddrinfo(ai);
01285     TRACE("connected\n");
01286     return RPC_S_OK;
01287   }
01288 
01289   freeaddrinfo(ai);
01290   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
01291   return RPC_S_SERVER_UNAVAILABLE;
01292 }
01293 
01294 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
01295 {
01296     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
01297     int sock;
01298     int ret;
01299     struct addrinfo *ai;
01300     struct addrinfo *ai_cur;
01301     struct addrinfo hints;
01302     RpcConnection *first_connection = NULL;
01303 
01304     TRACE("(%p, %s)\n", protseq, endpoint);
01305 
01306     hints.ai_flags          = AI_PASSIVE /* for non-localhost addresses */;
01307     hints.ai_family         = PF_UNSPEC;
01308     hints.ai_socktype       = SOCK_STREAM;
01309     hints.ai_protocol       = IPPROTO_TCP;
01310     hints.ai_addrlen        = 0;
01311     hints.ai_addr           = NULL;
01312     hints.ai_canonname      = NULL;
01313     hints.ai_next           = NULL;
01314 
01315     ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
01316     if (ret)
01317     {
01318         ERR("getaddrinfo for port %s failed: %s\n", endpoint,
01319             gai_strerror(ret));
01320         if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
01321             return RPC_S_INVALID_ENDPOINT_FORMAT;
01322         return RPC_S_CANT_CREATE_ENDPOINT;
01323     }
01324 
01325     for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
01326     {
01327         RpcConnection_tcp *tcpc;
01328         RPC_STATUS create_status;
01329         struct sockaddr_storage sa;
01330         socklen_t sa_len;
01331         char service[NI_MAXSERV];
01332         u_long nonblocking;
01333 
01334         if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
01335         {
01336             TRACE("skipping non-IP/IPv6 address family\n");
01337             continue;
01338         }
01339 
01340         if (TRACE_ON(rpc))
01341         {
01342             char host[256];
01343             getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
01344                         host, sizeof(host), service, sizeof(service),
01345                         NI_NUMERICHOST | NI_NUMERICSERV);
01346             TRACE("trying %s:%s\n", host, service);
01347         }
01348 
01349         sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
01350         if (sock == -1)
01351         {
01352             WARN("socket() failed: %s\n", strerror(errno));
01353             status = RPC_S_CANT_CREATE_ENDPOINT;
01354             continue;
01355         }
01356 
01357         ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
01358         if (ret < 0)
01359         {
01360             WARN("bind failed: %s\n", strerror(errno));
01361             closesocket(sock);
01362             if (errno == EADDRINUSE)
01363               status = RPC_S_DUPLICATE_ENDPOINT;
01364             else
01365               status = RPC_S_CANT_CREATE_ENDPOINT;
01366             continue;
01367         }
01368 
01369         sa_len = sizeof(sa);
01370         if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
01371         {
01372             WARN("getsockname() failed: %s\n", strerror(errno));
01373             status = RPC_S_CANT_CREATE_ENDPOINT;
01374             continue;
01375         }
01376 
01377         ret = getnameinfo((struct sockaddr *)&sa, sa_len,
01378                           NULL, 0, service, sizeof(service),
01379                           NI_NUMERICSERV);
01380         if (ret)
01381         {
01382             WARN("getnameinfo failed: %s\n", gai_strerror(ret));
01383             status = RPC_S_CANT_CREATE_ENDPOINT;
01384             continue;
01385         }
01386 
01387         create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
01388                                                 protseq->Protseq, NULL,
01389                                                 service, NULL, NULL, NULL);
01390         if (create_status != RPC_S_OK)
01391         {
01392             closesocket(sock);
01393             status = create_status;
01394             continue;
01395         }
01396 
01397         tcpc->sock = sock;
01398         ret = listen(sock, protseq->MaxCalls);
01399         if (ret < 0)
01400         {
01401             WARN("listen failed: %s\n", strerror(errno));
01402             RPCRT4_DestroyConnection(&tcpc->common);
01403             status = RPC_S_OUT_OF_RESOURCES;
01404             continue;
01405         }
01406         /* need a non-blocking socket, otherwise accept() has a potential
01407          * race-condition (poll() says it is readable, connection drops,
01408          * and accept() blocks until the next connection comes...)
01409          */
01410         nonblocking = 1;
01411         ret = ioctlsocket(sock, FIONBIO, &nonblocking);
01412         if (ret < 0)
01413         {
01414             WARN("couldn't make socket non-blocking, error %d\n", ret);
01415             RPCRT4_DestroyConnection(&tcpc->common);
01416             status = RPC_S_OUT_OF_RESOURCES;
01417             continue;
01418         }
01419 
01420         tcpc->common.Next = first_connection;
01421         first_connection = &tcpc->common;
01422 
01423         /* since IPv4 and IPv6 share the same port space, we only need one
01424          * successful bind to listen for both */
01425         break;
01426     }
01427 
01428     freeaddrinfo(ai);
01429 
01430     /* if at least one connection was created for an endpoint then
01431      * return success */
01432     if (first_connection)
01433     {
01434         RpcConnection *conn;
01435 
01436         /* find last element in list */
01437         for (conn = first_connection; conn->Next; conn = conn->Next)
01438             ;
01439 
01440         EnterCriticalSection(&protseq->cs);
01441         conn->Next = protseq->conn;
01442         protseq->conn = first_connection;
01443         LeaveCriticalSection(&protseq->cs);
01444         
01445         TRACE("listening on %s\n", endpoint);
01446         return RPC_S_OK;
01447     }
01448 
01449     ERR("couldn't listen on port %s\n", endpoint);
01450     return status;
01451 }
01452 
01453 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
01454 {
01455   int ret;
01456   struct sockaddr_in address;
01457   socklen_t addrsize;
01458   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
01459   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
01460   u_long nonblocking;
01461 
01462   addrsize = sizeof(address);
01463   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
01464   if (ret < 0)
01465   {
01466     ERR("Failed to accept a TCP connection: error %d\n", ret);
01467     return RPC_S_OUT_OF_RESOURCES;
01468   }
01469   nonblocking = 1;
01470   ioctlsocket(ret, FIONBIO, &nonblocking);
01471   client->sock = ret;
01472   TRACE("Accepted a new TCP connection\n");
01473   return RPC_S_OK;
01474 }
01475 
01476 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
01477                                 void *buffer, unsigned int count)
01478 {
01479   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01480   int bytes_read = 0;
01481   while (bytes_read != count)
01482   {
01483     int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
01484     if (!r)
01485       return -1;
01486     else if (r > 0)
01487       bytes_read += r;
01488     else if (errno != EAGAIN)
01489     {
01490       WARN("recv() failed: %s\n", strerror(errno));
01491       return -1;
01492     }
01493     else
01494     {
01495       if (!rpcrt4_sock_wait_for_recv(tcpc))
01496         return -1;
01497     }
01498   }
01499   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
01500   return bytes_read;
01501 }
01502 
01503 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
01504                                  const void *buffer, unsigned int count)
01505 {
01506   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01507   int bytes_written = 0;
01508   while (bytes_written != count)
01509   {
01510     int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
01511     if (r >= 0)
01512       bytes_written += r;
01513     else if (errno != EAGAIN)
01514       return -1;
01515     else
01516     {
01517       if (!rpcrt4_sock_wait_for_send(tcpc))
01518         return -1;
01519     }
01520   }
01521   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
01522   return bytes_written;
01523 }
01524 
01525 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
01526 {
01527   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01528 
01529   TRACE("%d\n", tcpc->sock);
01530 
01531   if (tcpc->sock != -1)
01532     closesocket(tcpc->sock);
01533   tcpc->sock = -1;
01534   rpcrt4_sock_wait_destroy(tcpc);
01535   return 0;
01536 }
01537 
01538 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
01539 {
01540     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01541     TRACE("%p\n", Connection);
01542     rpcrt4_sock_wait_cancel(tcpc);
01543 }
01544 
01545 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
01546 {
01547     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
01548 
01549     TRACE("%p\n", Connection);
01550 
01551     if (!rpcrt4_sock_wait_for_recv(tcpc))
01552         return -1;
01553     return 0;
01554 }
01555 
01556 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
01557                                                    const char *networkaddr,
01558                                                    const char *endpoint)
01559 {
01560     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
01561                                           EPM_PROTOCOL_TCP, endpoint);
01562 }
01563 
01564 #ifdef HAVE_SOCKETPAIR
01565 
01566 typedef struct _RpcServerProtseq_sock
01567 {
01568     RpcServerProtseq common;
01569     int mgr_event_rcv;
01570     int mgr_event_snd;
01571 } RpcServerProtseq_sock;
01572 
01573 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
01574 {
01575     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
01576     if (ps)
01577     {
01578         int fds[2];
01579         if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
01580         {
01581             fcntl(fds[0], F_SETFL, O_NONBLOCK);
01582             fcntl(fds[1], F_SETFL, O_NONBLOCK);
01583             ps->mgr_event_rcv = fds[0];
01584             ps->mgr_event_snd = fds[1];
01585         }
01586         else
01587         {
01588             ERR("socketpair failed with error %s\n", strerror(errno));
01589             HeapFree(GetProcessHeap(), 0, ps);
01590             return NULL;
01591         }
01592     }
01593     return &ps->common;
01594 }
01595 
01596 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
01597 {
01598     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
01599     char dummy = 1;
01600     write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
01601 }
01602 
01603 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
01604 {
01605     struct pollfd *poll_info = prev_array;
01606     RpcConnection_tcp *conn;
01607     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
01608 
01609     EnterCriticalSection(&protseq->cs);
01610     
01611     /* open and count connections */
01612     *count = 1;
01613     conn = (RpcConnection_tcp *)protseq->conn;
01614     while (conn) {
01615         if (conn->sock != -1)
01616             (*count)++;
01617         conn = (RpcConnection_tcp *)conn->common.Next;
01618     }
01619     
01620     /* make array of connections */
01621     if (poll_info)
01622         poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
01623     else
01624         poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
01625     if (!poll_info)
01626     {
01627         ERR("couldn't allocate poll_info\n");
01628         LeaveCriticalSection(&protseq->cs);
01629         return NULL;
01630     }
01631 
01632     poll_info[0].fd = sockps->mgr_event_rcv;
01633     poll_info[0].events = POLLIN;
01634     *count = 1;
01635     conn =  CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
01636     while (conn) {
01637         if (conn->sock != -1)
01638         {
01639             poll_info[*count].fd = conn->sock;
01640             poll_info[*count].events = POLLIN;
01641             (*count)++;
01642         }
01643         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
01644     }
01645     LeaveCriticalSection(&protseq->cs);
01646     return poll_info;
01647 }
01648 
01649 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
01650 {
01651     HeapFree(GetProcessHeap(), 0, array);
01652 }
01653 
01654 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
01655 {
01656     struct pollfd *poll_info = wait_array;
01657     int ret;
01658     unsigned int i;
01659     RpcConnection *cconn;
01660     RpcConnection_tcp *conn;
01661     
01662     if (!poll_info)
01663         return -1;
01664     
01665     ret = poll(poll_info, count, -1);
01666     if (ret < 0)
01667     {
01668         ERR("poll failed with error %d\n", ret);
01669         return -1;
01670     }
01671 
01672     for (i = 0; i < count; i++)
01673         if (poll_info[i].revents & POLLIN)
01674         {
01675             /* RPC server event */
01676             if (i == 0)
01677             {
01678                 char dummy;
01679                 read(poll_info[0].fd, &dummy, sizeof(dummy));
01680                 return 0;
01681             }
01682 
01683             /* find which connection got a RPC */
01684             EnterCriticalSection(&protseq->cs);
01685             conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
01686             while (conn) {
01687                 if (poll_info[i].fd == conn->sock) break;
01688                 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
01689             }
01690             cconn = NULL;
01691             if (conn)
01692                 RPCRT4_SpawnConnection(&cconn, &conn->common);
01693             else
01694                 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
01695             LeaveCriticalSection(&protseq->cs);
01696             if (cconn)
01697                 RPCRT4_new_client(cconn);
01698             else
01699                 return -1;
01700         }
01701 
01702     return 1;
01703 }
01704 
01705 #else /* HAVE_SOCKETPAIR */
01706 
01707 typedef struct _RpcServerProtseq_sock
01708 {
01709     RpcServerProtseq common;
01710     HANDLE mgr_event;
01711 } RpcServerProtseq_sock;
01712 
01713 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
01714 {
01715     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
01716     if (ps)
01717     {
01718         static BOOL wsa_inited;
01719         if (!wsa_inited)
01720         {
01721             WSADATA wsadata;
01722             WSAStartup(MAKEWORD(2, 2), &wsadata);
01723             /* Note: WSAStartup can be called more than once so we don't bother with
01724              * making accesses to wsa_inited thread-safe */
01725             wsa_inited = TRUE;
01726         }
01727         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01728     }
01729     return &ps->common;
01730 }
01731 
01732 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
01733 {
01734     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
01735     SetEvent(sockps->mgr_event);
01736 }
01737 
01738 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
01739 {
01740     HANDLE *objs = prev_array;
01741     RpcConnection_tcp *conn;
01742     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
01743 
01744     EnterCriticalSection(&protseq->cs);
01745 
01746     /* open and count connections */
01747     *count = 1;
01748     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
01749     while (conn)
01750     {
01751         if (conn->sock != -1)
01752             (*count)++;
01753         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
01754     }
01755 
01756     /* make array of connections */
01757     if (objs)
01758         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
01759     else
01760         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
01761     if (!objs)
01762     {
01763         ERR("couldn't allocate objs\n");
01764         LeaveCriticalSection(&protseq->cs);
01765         return NULL;
01766     }
01767 
01768     objs[0] = sockps->mgr_event;
01769     *count = 1;
01770     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
01771     while (conn)
01772     {
01773         if (conn->sock != -1)
01774         {
01775             int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
01776             if (res == SOCKET_ERROR)
01777                 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
01778             else
01779             {
01780                 objs[*count] = conn->sock_event;
01781                 (*count)++;
01782             }
01783         }
01784         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
01785     }
01786     LeaveCriticalSection(&protseq->cs);
01787     return objs;
01788 }
01789 
01790 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
01791 {
01792     HeapFree(GetProcessHeap(), 0, array);
01793 }
01794 
01795 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
01796 {
01797     HANDLE b_handle;
01798     HANDLE *objs = wait_array;
01799     DWORD res;
01800     RpcConnection *cconn;
01801     RpcConnection_tcp *conn;
01802 
01803     if (!objs)
01804         return -1;
01805 
01806     do
01807     {
01808         /* an alertable wait isn't strictly necessary, but due to our
01809          * overlapped I/O implementation in Wine we need to free some memory
01810          * by the file user APC being called, even if no completion routine was
01811          * specified at the time of starting the async operation */
01812         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
01813     } while (res == WAIT_IO_COMPLETION);
01814 
01815     if (res == WAIT_OBJECT_0)
01816         return 0;
01817     else if (res == WAIT_FAILED)
01818     {
01819         ERR("wait failed with error %d\n", GetLastError());
01820         return -1;
01821     }
01822     else
01823     {
01824         b_handle = objs[res - WAIT_OBJECT_0];
01825         /* find which connection got a RPC */
01826         EnterCriticalSection(&protseq->cs);
01827         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
01828         while (conn)
01829         {
01830             if (b_handle == conn->sock_event) break;
01831             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
01832         }
01833         cconn = NULL;
01834         if (conn)
01835             RPCRT4_SpawnConnection(&cconn, &conn->common);
01836         else
01837             ERR("failed to locate connection for handle %p\n", b_handle);
01838         LeaveCriticalSection(&protseq->cs);
01839         if (cconn)
01840         {
01841             RPCRT4_new_client(cconn);
01842             return 1;
01843         }
01844         else return -1;
01845     }
01846 }
01847 
01848 #endif  /* HAVE_SOCKETPAIR */
01849 
01850 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
01851                                                          size_t tower_size,
01852                                                          char **networkaddr,
01853                                                          char **endpoint)
01854 {
01855     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
01856                                             networkaddr, EPM_PROTOCOL_TCP,
01857                                             endpoint);
01858 }
01859 
01860 /**** ncacn_http support ****/
01861 
01862 /* 60 seconds is the period native uses */
01863 #define HTTP_IDLE_TIME 60000
01864 
01865 /* reference counted to avoid a race between a cancelled call's connection
01866  * being destroyed and the asynchronous InternetReadFileEx call being
01867  * completed */
01868 typedef struct _RpcHttpAsyncData
01869 {
01870     LONG refs;
01871     HANDLE completion_event;
01872     INTERNET_BUFFERSA inet_buffers;
01873     void *destination_buffer; /* the address that inet_buffers.lpvBuffer will be
01874                                * copied into when the call completes */
01875     CRITICAL_SECTION cs;
01876 } RpcHttpAsyncData;
01877 
01878 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
01879 {
01880     return InterlockedIncrement(&data->refs);
01881 }
01882 
01883 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
01884 {
01885     ULONG refs = InterlockedDecrement(&data->refs);
01886     if (!refs)
01887     {
01888         TRACE("destroying async data %p\n", data);
01889         CloseHandle(data->completion_event);
01890         HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
01891         DeleteCriticalSection(&data->cs);
01892         HeapFree(GetProcessHeap(), 0, data);
01893     }
01894     return refs;
01895 }
01896 
01897 typedef struct _RpcConnection_http
01898 {
01899     RpcConnection common;
01900     HINTERNET app_info;
01901     HINTERNET session;
01902     HINTERNET in_request;
01903     HINTERNET out_request;
01904     HANDLE timer_cancelled;
01905     HANDLE cancel_event;
01906     DWORD last_sent_time;
01907     ULONG bytes_received;
01908     ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
01909     ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
01910     UUID connection_uuid;
01911     UUID in_pipe_uuid;
01912     UUID out_pipe_uuid;
01913     RpcHttpAsyncData *async_data;
01914 } RpcConnection_http;
01915 
01916 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
01917 {
01918     RpcConnection_http *httpc;
01919     httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
01920     if (!httpc) return NULL;
01921     httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
01922     if (!httpc->async_data)
01923     {
01924         HeapFree(GetProcessHeap(), 0, httpc);
01925         return NULL;
01926     }
01927     TRACE("async data = %p\n", httpc->async_data);
01928     httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01929     httpc->async_data->refs = 1;
01930     httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
01931     httpc->async_data->inet_buffers.lpvBuffer = NULL;
01932     httpc->async_data->destination_buffer = NULL;
01933     InitializeCriticalSection(&httpc->async_data->cs);
01934     return &httpc->common;
01935 }
01936 
01937 typedef struct _HttpTimerThreadData
01938 {
01939     PVOID timer_param;
01940     DWORD *last_sent_time;
01941     HANDLE timer_cancelled;
01942 } HttpTimerThreadData;
01943 
01944 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
01945 {
01946     HINTERNET in_request = param;
01947     RpcPktHdr *idle_pkt;
01948 
01949     idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
01950                                       0, 0);
01951     if (idle_pkt)
01952     {
01953         DWORD bytes_written;
01954         InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
01955         RPCRT4_FreeHeader(idle_pkt);
01956     }
01957 }
01958 
01959 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
01960 {
01961     DWORD cur_time = GetTickCount();
01962     DWORD cached_last_sent_time = *last_sent_time;
01963     return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
01964 }
01965 
01966 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
01967 {
01968     HttpTimerThreadData *data_in = param;
01969     HttpTimerThreadData data;
01970     DWORD timeout;
01971 
01972     data = *data_in;
01973     HeapFree(GetProcessHeap(), 0, data_in);
01974 
01975     for (timeout = HTTP_IDLE_TIME;
01976          WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
01977          timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
01978     {
01979         /* are we too soon after last send? */
01980         if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time)
01981             continue;
01982         rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
01983     }
01984 
01985     CloseHandle(data.timer_cancelled);
01986     return 0;
01987 }
01988 
01989 static VOID WINAPI rpcrt4_http_internet_callback(
01990      HINTERNET hInternet,
01991      DWORD_PTR dwContext,
01992      DWORD dwInternetStatus,
01993      LPVOID lpvStatusInformation,
01994      DWORD dwStatusInformationLength)
01995 {
01996     RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
01997 
01998     switch (dwInternetStatus)
01999     {
02000     case INTERNET_STATUS_REQUEST_COMPLETE:
02001         TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
02002         if (async_data)
02003         {
02004             if (async_data->inet_buffers.lpvBuffer)
02005             {
02006                 EnterCriticalSection(&async_data->cs);
02007                 if (async_data->destination_buffer)
02008                 {
02009                     memcpy(async_data->destination_buffer,
02010                            async_data->inet_buffers.lpvBuffer,
02011                            async_data->inet_buffers.dwBufferLength);
02012                     async_data->destination_buffer = NULL;
02013                 }
02014                 LeaveCriticalSection(&async_data->cs);
02015             }
02016             HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
02017             async_data->inet_buffers.lpvBuffer = NULL;
02018             SetEvent(async_data->completion_event);
02019             RpcHttpAsyncData_Release(async_data);
02020         }
02021         break;
02022     }
02023 }
02024 
02025 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
02026 {
02027     BOOL ret;
02028     DWORD status_code;
02029     DWORD size;
02030     DWORD index;
02031     WCHAR buf[32];
02032     WCHAR *status_text = buf;
02033     TRACE("\n");
02034 
02035     index = 0;
02036     size = sizeof(status_code);
02037     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
02038     if (!ret)
02039         return GetLastError();
02040     if (status_code < 400)
02041         return RPC_S_OK;
02042     index = 0;
02043     size = sizeof(buf);
02044     ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
02045     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
02046     {
02047         status_text = HeapAlloc(GetProcessHeap(), 0, size);
02048         ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
02049     }
02050 
02051     ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
02052     if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
02053 
02054     if (status_code == HTTP_STATUS_DENIED)
02055         return ERROR_ACCESS_DENIED;
02056     return RPC_S_SERVER_UNAVAILABLE;
02057 }
02058 
02059 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
02060 {
02061     static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
02062     LPWSTR proxy = NULL;
02063     LPWSTR user = NULL;
02064     LPWSTR password = NULL;
02065     LPWSTR servername = NULL;
02066     const WCHAR *option;
02067     INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */
02068 
02069     if (httpc->common.QOS &&
02070         (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
02071     {
02072         const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
02073         if (http_cred->TransportCredentials)
02074         {
02075             WCHAR *p;
02076             const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
02077             ULONG len = cred->DomainLength + 1 + cred->UserLength;
02078             user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
02079             if (!user)
02080                 return RPC_S_OUT_OF_RESOURCES;
02081             p = user;
02082             if (cred->DomainLength)
02083             {
02084                 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
02085                 p += cred->DomainLength;
02086                 *p = '\\';
02087                 p++;
02088             }
02089             memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
02090             p[cred->UserLength] = 0;
02091 
02092             password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
02093         }
02094     }
02095 
02096     for (option = httpc->common.NetworkOptions; option;
02097          option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
02098     {
02099         static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
02100         static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
02101 
02102         if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1))
02103         {
02104             const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1;
02105             const WCHAR *value_end;
02106             const WCHAR *p;
02107 
02108             value_end = strchrW(option, ',');
02109             if (!value_end)
02110                 value_end = value_start + strlenW(value_start);
02111             for (p = value_start; p < value_end; p++)
02112                 if (*p == ':')
02113                 {
02114                     port = atoiW(p+1);
02115                     value_end = p;
02116                     break;
02117                 }
02118             TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
02119             servername = RPCRT4_strndupW(value_start, value_end-value_start);
02120         }
02121         else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1))
02122         {
02123             const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1;
02124             const WCHAR *value_end;
02125 
02126             value_end = strchrW(option, ',');
02127             if (!value_end)
02128                 value_end = value_start + strlenW(value_start);
02129             TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
02130             proxy = RPCRT4_strndupW(value_start, value_end-value_start);
02131         }
02132         else
02133             FIXME("unhandled option %s\n", debugstr_w(option));
02134     }
02135 
02136     httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
02137                                     NULL, NULL, INTERNET_FLAG_ASYNC);
02138     if (!httpc->app_info)
02139     {
02140         HeapFree(GetProcessHeap(), 0, password);
02141         HeapFree(GetProcessHeap(), 0, user);
02142         ERR("InternetOpenW failed with error %d\n", GetLastError());
02143         return RPC_S_SERVER_UNAVAILABLE;
02144     }
02145     InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
02146 
02147     /* if no RpcProxy option specified, set the HTTP server address to the
02148      * RPC server address */
02149     if (!servername)
02150     {
02151         servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
02152         if (!servername)
02153         {
02154             HeapFree(GetProcessHeap(), 0, password);
02155             HeapFree(GetProcessHeap(), 0, user);
02156             return RPC_S_OUT_OF_RESOURCES;
02157         }
02158         MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
02159     }
02160 
02161     httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
02162                                       INTERNET_SERVICE_HTTP, 0, 0);
02163 
02164     HeapFree(GetProcessHeap(), 0, password);
02165     HeapFree(GetProcessHeap(), 0, user);
02166     HeapFree(GetProcessHeap(), 0, servername);
02167 
02168     if (!httpc->session)
02169     {
02170         ERR("InternetConnectW failed with error %d\n", GetLastError());
02171         return RPC_S_SERVER_UNAVAILABLE;
02172     }
02173 
02174     return RPC_S_OK;
02175 }
02176 
02177 /* prepare the in pipe for use by RPC packets */
02178 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data,
02179                                               const UUID *connection_uuid,
02180                                               const UUID *in_pipe_uuid,
02181                                               const UUID *association_uuid)
02182 {
02183     BYTE packet[44];
02184     BOOL ret;
02185     RPC_STATUS status;
02186     RpcPktHdr *hdr;
02187     INTERNET_BUFFERSW buffers_in;
02188     DWORD bytes_read, bytes_written;
02189 
02190     /* prepare in pipe */
02191     ResetEvent(async_data->completion_event);
02192     RpcHttpAsyncData_AddRef(async_data);
02193     ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0);
02194     if (!ret)
02195     {
02196         if (GetLastError() == ERROR_IO_PENDING)
02197             WaitForSingleObject(async_data->completion_event, INFINITE);
02198         else
02199         {
02200             RpcHttpAsyncData_Release(async_data);
02201             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
02202             return RPC_S_SERVER_UNAVAILABLE;
02203         }
02204     }
02205     status = rpcrt4_http_check_response(in_request);
02206     if (status != RPC_S_OK) return status;
02207 
02208     InternetReadFile(in_request, packet, 20, &bytes_read);
02209     /* FIXME: do something with retrieved data */
02210 
02211     memset(&buffers_in, 0, sizeof(buffers_in));
02212     buffers_in.dwStructSize = sizeof(buffers_in);
02213     /* FIXME: get this from the registry */
02214     buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
02215     ResetEvent(async_data->completion_event);
02216     RpcHttpAsyncData_AddRef(async_data);
02217     ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
02218     if (!ret)
02219     {
02220         if (GetLastError() == ERROR_IO_PENDING)
02221             WaitForSingleObject(async_data->completion_event, INFINITE);
02222         else
02223         {
02224             RpcHttpAsyncData_Release(async_data);
02225             ERR("HttpSendRequestExW failed with error %d\n", GetLastError());
02226             return RPC_S_SERVER_UNAVAILABLE;
02227         }
02228     }
02229 
02230     TRACE("sending HTTP connect header to server\n");
02231     hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid, association_uuid);
02232     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
02233     ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
02234     RPCRT4_FreeHeader(hdr);
02235     if (!ret)
02236     {
02237         ERR("InternetWriteFile failed with error %d\n", GetLastError());
02238         return RPC_S_SERVER_UNAVAILABLE;
02239     }
02240 
02241     return RPC_S_OK;
02242 }
02243 
02244 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data)
02245 {
02246     BOOL ret;
02247     DWORD bytes_read;
02248     unsigned short data_len;
02249 
02250     ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read);
02251     if (!ret)
02252         return RPC_S_SERVER_UNAVAILABLE;
02253     if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
02254     {
02255         ERR("wrong packet type received %d or wrong frag_len %d\n",
02256             hdr->common.ptype, hdr->common.frag_len);
02257         return RPC_S_PROTOCOL_ERROR;
02258     }
02259 
02260     ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read);
02261     if (!ret)
02262         return RPC_S_SERVER_UNAVAILABLE;
02263 
02264     data_len = hdr->common.frag_len - sizeof(hdr->http);
02265     if (data_len)
02266     {
02267         *data = HeapAlloc(GetProcessHeap(), 0, data_len);
02268         if (!*data)
02269             return RPC_S_OUT_OF_RESOURCES;
02270         ret = InternetReadFile(request, *data, data_len, &bytes_read);
02271         if (!ret)
02272         {
02273             HeapFree(GetProcessHeap(), 0, *data);
02274             return RPC_S_SERVER_UNAVAILABLE;
02275         }
02276     }
02277     else
02278         *data = NULL;
02279 
02280     if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
02281     {
02282         ERR("invalid http packet\n");
02283         return RPC_S_PROTOCOL_ERROR;
02284     }
02285 
02286     return RPC_S_OK;
02287 }
02288 
02289 /* prepare the out pipe for use by RPC packets */
02290 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request,
02291                                                RpcHttpAsyncData *async_data,
02292                                                const UUID *connection_uuid,
02293                                                const UUID *out_pipe_uuid,
02294                                                ULONG *flow_control_increment)
02295 {
02296     BYTE packet[20];
02297     BOOL ret;
02298     RPC_STATUS status;
02299     RpcPktHdr *hdr;
02300     DWORD bytes_read;
02301     BYTE *data_from_server;
02302     RpcPktHdr pkt_from_server;
02303     ULONG field1, field3;
02304 
02305     ResetEvent(async_data->completion_event);
02306     RpcHttpAsyncData_AddRef(async_data);
02307     ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0);
02308     if (!ret)
02309     {
02310         if (GetLastError() == ERROR_IO_PENDING)
02311             WaitForSingleObject(async_data->completion_event, INFINITE);
02312         else
02313         {
02314             RpcHttpAsyncData_Release(async_data);
02315             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
02316             return RPC_S_SERVER_UNAVAILABLE;
02317         }
02318     }
02319     status = rpcrt4_http_check_response(out_request);
02320     if (status != RPC_S_OK) return status;
02321 
02322     InternetReadFile(out_request, packet, 20, &bytes_read);
02323     /* FIXME: do something with retrieved data */
02324 
02325     hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid, NULL);
02326     if (!hdr) return RPC_S_OUT_OF_RESOURCES;
02327     ResetEvent(async_data->completion_event);
02328     RpcHttpAsyncData_AddRef(async_data);
02329     ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
02330     if (!ret)
02331     {
02332         if (GetLastError() == ERROR_IO_PENDING)
02333             WaitForSingleObject(async_data->completion_event, INFINITE);
02334         else
02335         {
02336             RpcHttpAsyncData_Release(async_data);
02337             ERR("HttpSendRequestW failed with error %d\n", GetLastError());
02338             RPCRT4_FreeHeader(hdr);
02339             return RPC_S_SERVER_UNAVAILABLE;
02340         }
02341     }
02342     RPCRT4_FreeHeader(hdr);
02343     status = rpcrt4_http_check_response(out_request);
02344     if (status != RPC_S_OK) return status;
02345 
02346     status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
02347                                           &data_from_server);
02348     if (status != RPC_S_OK) return status;
02349     status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
02350                                             &field1);
02351     HeapFree(GetProcessHeap(), 0, data_from_server);
02352     if (status != RPC_S_OK) return status;
02353     TRACE("received (%d) from first prepare header\n", field1);
02354 
02355     status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server,
02356                                           &data_from_server);
02357     if (status != RPC_S_OK) return status;
02358     status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
02359                                             &field1, flow_control_increment,
02360                                             &field3);
02361     HeapFree(GetProcessHeap(), 0, data_from_server);
02362     if (status != RPC_S_OK) return status;
02363     TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
02364 
02365     return RPC_S_OK;
02366 }
02367 
02368 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
02369 {
02370     RpcConnection_http *httpc = (RpcConnection_http *)Connection;
02371     static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
02372     static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
02373     static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
02374     static const WCHAR wszColon[] = {':',0};
02375     static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
02376     LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
02377     WCHAR *url;
02378     RPC_STATUS status;
02379     BOOL secure;
02380     HttpTimerThreadData *timer_data;
02381     HANDLE thread;
02382 
02383     TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
02384 
02385     if (Connection->server)
02386     {
02387         ERR("ncacn_http servers not supported yet\n");
02388         return RPC_S_SERVER_UNAVAILABLE;
02389     }
02390 
02391     if (httpc->in_request)
02392         return RPC_S_OK;
02393 
02394     httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
02395 
02396     status = UuidCreate(&httpc->connection_uuid);
02397     status = UuidCreate(&httpc->in_pipe_uuid);
02398     status = UuidCreate(&httpc->out_pipe_uuid);
02399 
02400     status = rpcrt4_http_internet_connect(httpc);
02401     if (status != RPC_S_OK)
02402         return status;
02403 
02404     url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
02405     if (!url)
02406         return RPC_S_OUT_OF_MEMORY;
02407     memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
02408     MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1);
02409     strcatW(url, wszColon);
02410     MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
02411 
02412     secure = httpc->common.QOS &&
02413              (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
02414              (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
02415 
02416     httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL,
02417                                          wszAcceptTypes,
02418                                          (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
02419                                          (DWORD_PTR)httpc->async_data);
02420     if (!httpc->in_request)
02421     {
02422         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
02423         return RPC_S_SERVER_UNAVAILABLE;
02424     }
02425     httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL,
02426                                           wszAcceptTypes,
02427                                           (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE,
02428                                           (DWORD_PTR)httpc->async_data);
02429     if (!httpc->out_request)
02430     {
02431         ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
02432         return RPC_S_SERVER_UNAVAILABLE;
02433     }
02434 
02435     status = rpcrt4_http_prepare_in_pipe(httpc->in_request,
02436                                          httpc->async_data,
02437                                          &httpc->connection_uuid,
02438                                          &httpc->in_pipe_uuid,
02439                                          &Connection->assoc->http_uuid);
02440     if (status != RPC_S_OK)
02441         return status;
02442 
02443     status = rpcrt4_http_prepare_out_pipe(httpc->out_request,
02444                                           httpc->async_data,
02445                                           &httpc->connection_uuid,
02446                                           &httpc->out_pipe_uuid,
02447                                           &httpc->flow_control_increment);
02448     if (status != RPC_S_OK)
02449         return status;
02450 
02451     httpc->flow_control_mark = httpc->flow_control_increment / 2;
02452     httpc->last_sent_time = GetTickCount();
02453     httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
02454 
02455     timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
02456     if (!timer_data)
02457         return ERROR_OUTOFMEMORY;
02458     timer_data->timer_param = httpc->in_request;
02459     timer_data->last_sent_time = &httpc->last_sent_time;
02460     timer_data->timer_cancelled = httpc->timer_cancelled;
02461     /* FIXME: should use CreateTimerQueueTimer when implemented */
02462     thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
02463     if (!thread)
02464     {
02465         HeapFree(GetProcessHeap(), 0, timer_data);
02466         return GetLastError();
02467     }
02468     CloseHandle(thread);
02469 
02470     return RPC_S_OK;
02471 }
02472 
02473 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
02474 {
02475     assert(0);
02476     return RPC_S_SERVER_UNAVAILABLE;
02477 }
02478 
02479 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
02480                                 void *buffer, unsigned int count)
02481 {
02482   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02483   char *buf = buffer;
02484   BOOL ret = TRUE;
02485   unsigned int bytes_left = count;
02486 
02487   ResetEvent(httpc->async_data->completion_event);
02488   while (bytes_left)
02489   {
02490     RpcHttpAsyncData_AddRef(httpc->async_data);
02491     httpc->async_data->inet_buffers.dwBufferLength = bytes_left;
02492     httpc->async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, bytes_left);
02493     httpc->async_data->destination_buffer = buf;
02494     ret = InternetReadFileExA(httpc->out_request, &httpc->async_data->inet_buffers, IRF_ASYNC, 0);
02495     if (ret)
02496     {
02497         /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
02498          * async ref now */
02499         RpcHttpAsyncData_Release(httpc->async_data);
02500         memcpy(buf, httpc->async_data->inet_buffers.lpvBuffer,
02501                httpc->async_data->inet_buffers.dwBufferLength);
02502         HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
02503         httpc->async_data->inet_buffers.lpvBuffer = NULL;
02504         httpc->async_data->destination_buffer = NULL;
02505     }
02506     else
02507     {
02508         if (GetLastError() == ERROR_IO_PENDING)
02509         {
02510             HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
02511             DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
02512             if (result == WAIT_OBJECT_0)
02513                 ret = TRUE;
02514             else
02515             {
02516                 TRACE("call cancelled\n");
02517                 EnterCriticalSection(&httpc->async_data->cs);
02518                 httpc->async_data->destination_buffer = NULL;
02519                 LeaveCriticalSection(&httpc->async_data->cs);
02520                 break;
02521             }
02522         }
02523         else
02524         {
02525             HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer);
02526             httpc->async_data->inet_buffers.lpvBuffer = NULL;
02527             httpc->async_data->destination_buffer = NULL;
02528             RpcHttpAsyncData_Release(httpc->async_data);
02529             break;
02530         }
02531     }
02532     if (!httpc->async_data->inet_buffers.dwBufferLength)
02533         break;
02534     bytes_left -= httpc->async_data->inet_buffers.dwBufferLength;
02535     buf += httpc->async_data->inet_buffers.dwBufferLength;
02536   }
02537   TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE");
02538   return ret ? count : -1;
02539 }
02540 
02541 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
02542 {
02543   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02544   RPC_STATUS status;
02545   DWORD hdr_length;
02546   LONG dwRead;
02547   RpcPktCommonHdr common_hdr;
02548 
02549   *Header = NULL;
02550 
02551   TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
02552 
02553 again:
02554   /* read packet common header */
02555   dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
02556   if (dwRead != sizeof(common_hdr)) {
02557     WARN("Short read of header, %d bytes\n", dwRead);
02558     status = RPC_S_PROTOCOL_ERROR;
02559     goto fail;
02560   }
02561   if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
02562       !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
02563   {
02564     FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
02565     status = RPC_S_PROTOCOL_ERROR;
02566     goto fail;
02567   }
02568 
02569   status = RPCRT4_ValidateCommonHeader(&common_hdr);
02570   if (status != RPC_S_OK) goto fail;
02571 
02572   hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
02573   if (hdr_length == 0) {
02574     WARN("header length == 0\n");
02575     status = RPC_S_PROTOCOL_ERROR;
02576     goto fail;
02577   }
02578 
02579   *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
02580   if (!*Header)
02581   {
02582     status = RPC_S_OUT_OF_RESOURCES;
02583     goto fail;
02584   }
02585   memcpy(*Header, &common_hdr, sizeof(common_hdr));
02586 
02587   /* read the rest of packet header */
02588   dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
02589   if (dwRead != hdr_length - sizeof(common_hdr)) {
02590     WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
02591     status = RPC_S_PROTOCOL_ERROR;
02592     goto fail;
02593   }
02594 
02595   if (common_hdr.frag_len - hdr_length)
02596   {
02597     *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
02598     if (!*Payload)
02599     {
02600       status = RPC_S_OUT_OF_RESOURCES;
02601       goto fail;
02602     }
02603 
02604     dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
02605     if (dwRead != common_hdr.frag_len - hdr_length)
02606     {
02607       WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
02608       status = RPC_S_PROTOCOL_ERROR;
02609       goto fail;
02610     }
02611   }
02612   else
02613     *Payload = NULL;
02614 
02615   if ((*Header)->common.ptype == PKT_HTTP)
02616   {
02617     if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
02618     {
02619       ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
02620       status = RPC_S_PROTOCOL_ERROR;
02621       goto fail;
02622     }
02623     if ((*Header)->http.flags == 0x0001)
02624     {
02625       TRACE("http idle packet, waiting for real packet\n");
02626       if ((*Header)->http.num_data_items != 0)
02627       {
02628         ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
02629         status = RPC_S_PROTOCOL_ERROR;
02630         goto fail;
02631       }
02632     }
02633     else if ((*Header)->http.flags == 0x0002)
02634     {
02635       ULONG bytes_transmitted;
02636       ULONG flow_control_increment;
02637       UUID pipe_uuid;
02638       status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
02639                                                  Connection->server,
02640                                                  &bytes_transmitted,
02641                                                  &flow_control_increment,
02642                                                  &pipe_uuid);
02643       if (status != RPC_S_OK)
02644         goto fail;
02645       TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
02646             bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
02647       /* FIXME: do something with parsed data */
02648     }
02649     else
02650     {
02651       FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
02652       status = RPC_S_PROTOCOL_ERROR;
02653       goto fail;
02654     }
02655     RPCRT4_FreeHeader(*Header);
02656     *Header = NULL;
02657     HeapFree(GetProcessHeap(), 0, *Payload);
02658     *Payload = NULL;
02659     goto again;
02660   }
02661 
02662   /* success */
02663   status = RPC_S_OK;
02664 
02665   httpc->bytes_received += common_hdr.frag_len;
02666 
02667   TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
02668 
02669   if (httpc->bytes_received > httpc->flow_control_mark)
02670   {
02671     RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
02672                                                        httpc->bytes_received,
02673                                                        httpc->flow_control_increment,
02674                                                        &httpc->out_pipe_uuid);
02675     if (hdr)
02676     {
02677       DWORD bytes_written;
02678       BOOL ret2;
02679       TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
02680       ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
02681       RPCRT4_FreeHeader(hdr);
02682       if (ret2)
02683         httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
02684     }
02685   }
02686 
02687 fail:
02688   if (status != RPC_S_OK) {
02689     RPCRT4_FreeHeader(*Header);
02690     *Header = NULL;
02691     HeapFree(GetProcessHeap(), 0, *Payload);
02692     *Payload = NULL;
02693   }
02694   return status;
02695 }
02696 
02697 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
02698                                  const void *buffer, unsigned int count)
02699 {
02700   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02701   DWORD bytes_written;
02702   BOOL ret;
02703 
02704   httpc->last_sent_time = ~0U; /* disable idle packet sending */
02705   ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
02706   httpc->last_sent_time = GetTickCount();
02707   TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
02708   return ret ? bytes_written : -1;
02709 }
02710 
02711 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
02712 {
02713   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02714 
02715   TRACE("\n");
02716 
02717   SetEvent(httpc->timer_cancelled);
02718   if (httpc->in_request)
02719     InternetCloseHandle(httpc->in_request);
02720   httpc->in_request = NULL;
02721   if (httpc->out_request)
02722     InternetCloseHandle(httpc->out_request);
02723   httpc->out_request = NULL;
02724   if (httpc->app_info)
02725     InternetCloseHandle(httpc->app_info);
02726   httpc->app_info = NULL;
02727   if (httpc->session)
02728     InternetCloseHandle(httpc->session);
02729   httpc->session = NULL;
02730   RpcHttpAsyncData_Release(httpc->async_data);
02731   if (httpc->cancel_event)
02732     CloseHandle(httpc->cancel_event);
02733 
02734   return 0;
02735 }
02736 
02737 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
02738 {
02739   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02740 
02741   SetEvent(httpc->cancel_event);
02742 }
02743 
02744 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
02745 {
02746   BOOL ret;
02747   RpcConnection_http *httpc = (RpcConnection_http *) Connection;
02748 
02749   RpcHttpAsyncData_AddRef(httpc->async_data);
02750   ret = InternetQueryDataAvailable(httpc->out_request,
02751     &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
02752   if (ret)
02753   {
02754       /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our
02755        * async ref now */
02756       RpcHttpAsyncData_Release(httpc->async_data);
02757   }
02758   else
02759   {
02760     if (GetLastError() == ERROR_IO_PENDING)
02761     {
02762       HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event };
02763       DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
02764       if (result != WAIT_OBJECT_0)
02765       {
02766         TRACE("call cancelled\n");
02767         return -1;
02768       }
02769     }
02770     else
02771     {
02772       RpcHttpAsyncData_Release(httpc->async_data);
02773       return -1;
02774     }
02775   }
02776 
02777   /* success */
02778   return 0;
02779 }
02780 
02781 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
02782                                                  const char *networkaddr,
02783                                                  const char *endpoint)
02784 {
02785     return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
02786                                           EPM_PROTOCOL_HTTP, endpoint);
02787 }
02788 
02789 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
02790                                                        size_t tower_size,
02791                                                        char **networkaddr,
02792                                                        char **endpoint)
02793 {
02794     return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
02795                                             networkaddr, EPM_PROTOCOL_HTTP,
02796                                             endpoint);
02797 }
02798 
02799 static const struct connection_ops conn_protseq_list[] = {
02800   { "ncacn_np",
02801     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
02802     rpcrt4_conn_np_alloc,
02803     rpcrt4_ncacn_np_open,
02804     rpcrt4_ncacn_np_handoff,
02805     rpcrt4_conn_np_read,
02806     rpcrt4_conn_np_write,
02807     rpcrt4_conn_np_close,
02808     rpcrt4_conn_np_cancel_call,
02809     rpcrt4_conn_np_wait_for_incoming_data,
02810     rpcrt4_ncacn_np_get_top_of_tower,
02811     rpcrt4_ncacn_np_parse_top_of_tower,
02812     NULL,
02813     RPCRT4_default_is_authorized,
02814     RPCRT4_default_authorize,
02815     RPCRT4_default_secure_packet,
02816     rpcrt4_conn_np_impersonate_client,
02817     rpcrt4_conn_np_revert_to_self,
02818     RPCRT4_default_inquire_auth_client,
02819   },
02820   { "ncalrpc",
02821     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
02822     rpcrt4_conn_np_alloc,
02823     rpcrt4_ncalrpc_open,
02824     rpcrt4_ncalrpc_handoff,
02825     rpcrt4_conn_np_read,
02826     rpcrt4_conn_np_write,
02827     rpcrt4_conn_np_close,
02828     rpcrt4_conn_np_cancel_call,
02829     rpcrt4_conn_np_wait_for_incoming_data,
02830     rpcrt4_ncalrpc_get_top_of_tower,
02831     rpcrt4_ncalrpc_parse_top_of_tower,
02832     NULL,
02833     rpcrt4_ncalrpc_is_authorized,
02834     rpcrt4_ncalrpc_authorize,
02835     rpcrt4_ncalrpc_secure_packet,
02836     rpcrt4_conn_np_impersonate_client,
02837     rpcrt4_conn_np_revert_to_self,
02838     rpcrt4_ncalrpc_inquire_auth_client,
02839   },
02840   { "ncacn_ip_tcp",
02841     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
02842     rpcrt4_conn_tcp_alloc,
02843     rpcrt4_ncacn_ip_tcp_open,
02844     rpcrt4_conn_tcp_handoff,
02845     rpcrt4_conn_tcp_read,
02846     rpcrt4_conn_tcp_write,
02847     rpcrt4_conn_tcp_close,
02848     rpcrt4_conn_tcp_cancel_call,
02849     rpcrt4_conn_tcp_wait_for_incoming_data,
02850     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
02851     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
02852     NULL,
02853     RPCRT4_default_is_authorized,
02854     RPCRT4_default_authorize,
02855     RPCRT4_default_secure_packet,
02856     RPCRT4_default_impersonate_client,
02857     RPCRT4_default_revert_to_self,
02858     RPCRT4_default_inquire_auth_client,
02859   },
02860   { "ncacn_http",
02861     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
02862     rpcrt4_ncacn_http_alloc,
02863     rpcrt4_ncacn_http_open,
02864     rpcrt4_ncacn_http_handoff,
02865     rpcrt4_ncacn_http_read,
02866     rpcrt4_ncacn_http_write,
02867     rpcrt4_ncacn_http_close,
02868     rpcrt4_ncacn_http_cancel_call,
02869     rpcrt4_ncacn_http_wait_for_incoming_data,
02870     rpcrt4_ncacn_http_get_top_of_tower,
02871     rpcrt4_ncacn_http_parse_top_of_tower,
02872     rpcrt4_ncacn_http_receive_fragment,
02873     RPCRT4_default_is_authorized,
02874     RPCRT4_default_authorize,
02875     RPCRT4_default_secure_packet,
02876     RPCRT4_default_impersonate_client,
02877     RPCRT4_default_revert_to_self,
02878     RPCRT4_default_inquire_auth_client,
02879   },
02880 };
02881 
02882 
02883 static const struct protseq_ops protseq_list[] =
02884 {
02885     {
02886         "ncacn_np",
02887         rpcrt4_protseq_np_alloc,
02888         rpcrt4_protseq_np_signal_state_changed,
02889         rpcrt4_protseq_np_get_wait_array,
02890         rpcrt4_protseq_np_free_wait_array,
02891         rpcrt4_protseq_np_wait_for_new_connection,
02892         rpcrt4_protseq_ncacn_np_open_endpoint,
02893     },
02894     {
02895         "ncalrpc",
02896         rpcrt4_protseq_np_alloc,
02897         rpcrt4_protseq_np_signal_state_changed,
02898         rpcrt4_protseq_np_get_wait_array,
02899         rpcrt4_protseq_np_free_wait_array,
02900         rpcrt4_protseq_np_wait_for_new_connection,
02901         rpcrt4_protseq_ncalrpc_open_endpoint,
02902     },
02903     {
02904         "ncacn_ip_tcp",
02905         rpcrt4_protseq_sock_alloc,
02906         rpcrt4_protseq_sock_signal_state_changed,
02907         rpcrt4_protseq_sock_get_wait_array,
02908         rpcrt4_protseq_sock_free_wait_array,
02909         rpcrt4_protseq_sock_wait_for_new_connection,
02910         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
02911     },
02912 };
02913 
02914 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
02915 
02916 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
02917 {
02918   unsigned int i;
02919   for(i=0; i<ARRAYSIZE(protseq_list); i++)
02920     if (!strcmp(protseq_list[i].name, protseq))
02921       return &protseq_list[i];
02922   return NULL;
02923 }
02924 
02925 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
02926 {
02927     unsigned int i;
02928     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
02929         if (!strcmp(conn_protseq_list[i].name, protseq))
02930             return &conn_protseq_list[i];
02931     return NULL;
02932 }
02933 
02934 /**** interface to rest of code ****/
02935 
02936 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
02937 {
02938   TRACE("(Connection == ^%p)\n", Connection);
02939 
02940   assert(!Connection->server);
02941   return Connection->ops->open_connection_client(Connection);
02942 }
02943 
02944 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
02945 {
02946   TRACE("(Connection == ^%p)\n", Connection);
02947   if (SecIsValidHandle(&Connection->ctx))
02948   {
02949     DeleteSecurityContext(&Connection->ctx);
02950     SecInvalidateHandle(&Connection->ctx);
02951   }
02952   rpcrt4_conn_close(Connection);
02953   return RPC_S_OK;
02954 }
02955 
02956 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
02957     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
02958     LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
02959 {
02960   static LONG next_id;
02961   const struct connection_ops *ops;
02962   RpcConnection* NewConnection;
02963 
02964   ops = rpcrt4_get_conn_protseq_ops(Protseq);
02965   if (!ops)
02966   {
02967     FIXME("not supported for protseq %s\n", Protseq);
02968     return RPC_S_PROTSEQ_NOT_SUPPORTED;
02969   }
02970 
02971   NewConnection = ops->alloc();
02972   NewConnection->Next = NULL;
02973   NewConnection->server_binding = NULL;
02974   NewConnection->server = server;
02975   NewConnection->ops = ops;
02976   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
02977   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
02978   NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
02979   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
02980   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
02981   NewConnection->NextCallId = 1;
02982 
02983   SecInvalidateHandle(&NewConnection->ctx);
02984   memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
02985   NewConnection->attr = 0;
02986   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
02987   NewConnection->AuthInfo = AuthInfo;
02988   NewConnection->auth_context_id = InterlockedIncrement( &next_id );
02989   NewConnection->encryption_auth_len = 0;
02990   NewConnection->signature_auth_len = 0;
02991   if (QOS) RpcQualityOfService_AddRef(QOS);
02992   NewConnection->QOS = QOS;
02993 
02994   list_init(&NewConnection->conn_pool_entry);
02995   NewConnection->async_state = NULL;
02996 
02997   TRACE("connection: %p\n", NewConnection);
02998   *Connection = NewConnection;
02999 
03000   return RPC_S_OK;
03001 }
03002 
03003 static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
03004 {
03005   RPC_STATUS err;
03006 
03007   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
03008                                 rpcrt4_conn_get_name(OldConnection),
03009                                 OldConnection->NetworkAddr,
03010                                 OldConnection->Endpoint, NULL,
03011                                 OldConnection->AuthInfo, OldConnection->QOS);
03012   if (err == RPC_S_OK)
03013     rpcrt4_conn_handoff(OldConnection, *Connection);
03014   return err;
03015 }
03016 
03017 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
03018 {
03019   TRACE("connection: %p\n", Connection);
03020 
03021   RPCRT4_CloseConnection(Connection);
03022   RPCRT4_strfree(Connection->Endpoint);
03023   RPCRT4_strfree(Connection->NetworkAddr);
03024   HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
03025   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
03026   if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
03027 
03028   /* server-only */
03029   if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
03030 
03031   HeapFree(GetProcessHeap(), 0, Connection);
03032   return RPC_S_OK;
03033 }
03034 
03035 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
03036                                       size_t *tower_size,
03037                                       const char *protseq,
03038                                       const char *networkaddr,
03039                                       const char *endpoint)
03040 {
03041     twr_empty_floor_t *protocol_floor;
03042     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
03043 
03044     *tower_size = 0;
03045 
03046     if (!protseq_ops)
03047         return RPC_S_INVALID_RPC_PROTSEQ;
03048 
03049     if (!tower_data)
03050     {
03051         *tower_size = sizeof(*protocol_floor);
03052         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
03053         return RPC_S_OK;
03054     }
03055 
03056     protocol_floor = (twr_empty_floor_t *)tower_data;
03057     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
03058     protocol_floor->protid = protseq_ops->epm_protocols[0];
03059     protocol_floor->count_rhs = 0;
03060 
03061     tower_data += sizeof(*protocol_floor);
03062 
03063     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
03064     if (!*tower_size)
03065         return EPT_S_NOT_REGISTERED;
03066 
03067     *tower_size += sizeof(*protocol_floor);
03068 
03069     return RPC_S_OK;
03070 }
03071 
03072 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
03073                                         size_t tower_size,
03074                                         char **protseq,
03075                                         char **networkaddr,
03076                                         char **endpoint)
03077 {
03078     const twr_empty_floor_t *protocol_floor;
03079     const twr_empty_floor_t *floor4;
03080     const struct connection_ops *protseq_ops = NULL;
03081     RPC_STATUS status;
03082     unsigned int i;
03083 
03084     if (tower_size < sizeof(*protocol_floor))
03085         return EPT_S_NOT_REGISTERED;
03086 
03087     protocol_floor = (const twr_empty_floor_t *)tower_data;
03088     tower_data += sizeof(*protocol_floor);
03089     tower_size -= sizeof(*protocol_floor);
03090     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
03091         (protocol_floor->count_rhs > tower_size))
03092         return EPT_S_NOT_REGISTERED;
03093     tower_data += protocol_floor->count_rhs;
03094     tower_size -= protocol_floor->count_rhs;
03095 
03096     floor4 = (const twr_empty_floor_t *)tower_data;
03097     if ((tower_size < sizeof(*floor4)) ||
03098         (floor4->count_lhs != sizeof(floor4->protid)))
03099         return EPT_S_NOT_REGISTERED;
03100 
03101     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
03102         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
03103             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
03104         {
03105             protseq_ops = &conn_protseq_list[i];
03106             break;
03107         }
03108 
03109     if (!protseq_ops)
03110         return EPT_S_NOT_REGISTERED;
03111 
03112     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
03113 
03114     if ((status == RPC_S_OK) && protseq)
03115     {
03116         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
03117         strcpy(*protseq, protseq_ops->name);
03118     }
03119 
03120     return status;
03121 }
03122 
03123 /***********************************************************************
03124  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
03125  *
03126  * Checks if the given protocol sequence is known by the RPC system.
03127  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
03128  *
03129  */
03130 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
03131 {
03132   char ps[0x10];
03133 
03134   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
03135                       ps, sizeof ps, NULL, NULL);
03136   if (rpcrt4_get_conn_protseq_ops(ps))
03137     return RPC_S_OK;
03138 
03139   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
03140 
03141   return RPC_S_INVALID_RPC_PROTSEQ;
03142 }
03143 
03144 /***********************************************************************
03145  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
03146  */
03147 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
03148 {
03149   UNICODE_STRING protseqW;
03150 
03151   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
03152   {
03153     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
03154     RtlFreeUnicodeString(&protseqW);
03155     return ret;
03156   }
03157   return RPC_S_OUT_OF_MEMORY;
03158 }
03159 
03160 /***********************************************************************
03161  *             RpcProtseqVectorFreeA (RPCRT4.@)
03162  */
03163 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
03164 {
03165   TRACE("(%p)\n", protseqs);
03166 
03167   if (*protseqs)
03168   {
03169     int i;
03170     for (i = 0; i < (*protseqs)->Count; i++)
03171       HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
03172     HeapFree(GetProcessHeap(), 0, *protseqs);
03173     *protseqs = NULL;
03174   }
03175   return RPC_S_OK;
03176 }
03177 
03178 /***********************************************************************
03179  *             RpcProtseqVectorFreeW (RPCRT4.@)
03180  */
03181 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
03182 {
03183   TRACE("(%p)\n", protseqs);
03184 
03185   if (*protseqs)
03186   {
03187     int i;
03188     for (i = 0; i < (*protseqs)->Count; i++)
03189       HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
03190     HeapFree(GetProcessHeap(), 0, *protseqs);
03191     *protseqs = NULL;
03192   }
03193   return RPC_S_OK;
03194 }
03195 
03196 /***********************************************************************
03197  *             RpcNetworkInqProtseqsW (RPCRT4.@)
03198  */
03199 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
03200 {
03201   RPC_PROTSEQ_VECTORW *pvector;
03202   int i = 0;
03203   RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
03204 
03205   TRACE("(%p)\n", protseqs);
03206 
03207   *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAYSIZE(protseq_list)));
03208   if (!*protseqs)
03209     goto end;
03210   pvector = *protseqs;
03211   pvector->Count = 0;
03212   for (i = 0; i < ARRAYSIZE(protseq_list); i++)
03213   {
03214     pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
03215     if (pvector->Protseq[i] == NULL)
03216       goto end;
03217     MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
03218       (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
03219     pvector->Count++;
03220   }
03221   status = RPC_S_OK;
03222 
03223 end:
03224   if (status != RPC_S_OK)
03225     RpcProtseqVectorFreeW(protseqs);
03226   return status;
03227 }
03228 
03229 /***********************************************************************
03230  *             RpcNetworkInqProtseqsA (RPCRT4.@)
03231  */
03232 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
03233 {
03234   RPC_PROTSEQ_VECTORA *pvector;
03235   int i = 0;
03236   RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
03237 
03238   TRACE("(%p)\n", protseqs);
03239 
03240   *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAYSIZE(protseq_list)));
03241   if (!*protseqs)
03242     goto end;
03243   pvector = *protseqs;
03244   pvector->Count = 0;
03245   for (i = 0; i < ARRAYSIZE(protseq_list); i++)
03246   {
03247     pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
03248     if (pvector->Protseq[i] == NULL)
03249       goto end;
03250     strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
03251     pvector->Count++;
03252   }
03253   status = RPC_S_OK;
03254 
03255 end:
03256   if (status != RPC_S_OK)
03257     RpcProtseqVectorFreeA(protseqs);
03258   return status;
03259 }

Generated on Sun May 27 2012 04:26:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.