rpc_message.c 6.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/*
 * RPC messages
 *
 * Copyright 2001-2002 Ove Kven, TransGaming Technologies
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * TODO:
 *  - figure out whether we *really* got this right
 *  - check for errors and throw exceptions
 *  - decide if OVERLAPPED_WORKS
 */

#include <stdio.h>
#include <string.h>

#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"

#include "rpc.h"
#include "rpcdcep.h"

#include "wine/debug.h"

#include "rpc_binding.h"
#include "rpc_defs.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

/***********************************************************************
 *           I_RpcGetBuffer [RPCRT4.@]
 */
RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
{
  void* buf;

51
  TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
52
  /* FIXME: pfnAllocate? */
53
  buf = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
54
  TRACE("Buffer=%p\n", buf);
55 56 57 58 59 60 61 62 63 64 65
  if (buf) pMsg->Buffer = buf;
  /* FIXME: which errors to return? */
  return buf ? S_OK : E_OUTOFMEMORY;
}

/***********************************************************************
 *           I_RpcFreeBuffer [RPCRT4.@]
 */
RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
{
  TRACE("(%p)\n", pMsg);
66
  /* FIXME: pfnFree? */
67 68 69 70 71 72 73 74 75 76 77
  HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
  pMsg->Buffer = NULL;
  return S_OK;
}

/***********************************************************************
 *           I_RpcSend [RPCRT4.@]
 */
RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
{
  RpcBinding* bind = (RpcBinding*)pMsg->Handle;
78
  RpcConnection* conn;
79 80
  RPC_CLIENT_INTERFACE* cif = NULL;
  RPC_SERVER_INTERFACE* sif = NULL;
81 82
  UUID* obj;
  UUID* act;
83 84 85 86 87 88
  RPC_STATUS status;
  RpcPktHdr hdr;

  TRACE("(%p)\n", pMsg);
  if (!bind) return RPC_S_INVALID_BINDING;

89 90 91 92 93 94
  status = RPCRT4_OpenBinding(bind, &conn);
  if (status != RPC_S_OK) return status;

  obj = &bind->ObjectUuid;
  act = &bind->ActiveUuid;

95 96 97 98 99 100 101
  if (bind->server) {
    sif = pMsg->RpcInterfaceInformation;
    if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
  } else {
    cif = pMsg->RpcInterfaceInformation;
    if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
  }
102 103 104 105

  /* initialize packet header */
  memset(&hdr, 0, sizeof(hdr));
  hdr.rpc_ver = 4;
106 107
  hdr.ptype = bind->server ? PKT_RESPONSE : PKT_REQUEST;
  hdr.object = *obj; /* FIXME: IIRC iff no object, the header structure excludes this elt */
108 109 110 111 112
  hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID;
  hdr.if_vers = 
    (bind->server) ?
    MAKELONG(sif->InterfaceId.SyntaxVersion.MinorVersion, sif->InterfaceId.SyntaxVersion.MajorVersion) :
    MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, cif->InterfaceId.SyntaxVersion.MajorVersion);
113
  hdr.act_id = *act;
114
  hdr.opnum = pMsg->ProcNum;
115 116 117 118
  /* only the low-order 3 octets of the DataRepresentation go in the header */
  hdr.drep[0] = LOBYTE(LOWORD(pMsg->DataRepresentation));
  hdr.drep[1] = HIBYTE(LOWORD(pMsg->DataRepresentation));
  hdr.drep[2] = LOBYTE(HIWORD(pMsg->DataRepresentation));
119 120 121
  hdr.len = pMsg->BufferLength;

  /* transmit packet */
122 123 124 125 126 127 128 129
  if (!WriteFile(conn->conn, &hdr, sizeof(hdr), NULL, NULL)) {
    status = GetLastError();
    goto fail;
  }
  if (pMsg->BufferLength && !WriteFile(conn->conn, pMsg->Buffer, pMsg->BufferLength, NULL, NULL)) {
    status = GetLastError();
    goto fail;
  }
130 131

  /* success */
132 133 134 135 136 137 138 139 140 141
  if (!bind->server) {
    /* save the connection, so the response can be read from it */
    pMsg->ReservedForRuntime = conn;
    return RPC_S_OK;
  }
  RPCRT4_CloseBinding(bind, conn);
  status = RPC_S_OK;
fail:

  return status;
142 143 144 145 146 147 148 149
}

/***********************************************************************
 *           I_RpcReceive [RPCRT4.@]
 */
RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
{
  RpcBinding* bind = (RpcBinding*)pMsg->Handle;
150 151
  RpcConnection* conn;
  UUID* act;
152 153 154 155 156 157 158
  RPC_STATUS status;
  RpcPktHdr hdr;
  DWORD dwRead;

  TRACE("(%p)\n", pMsg);
  if (!bind) return RPC_S_INVALID_BINDING;

159 160 161 162 163 164 165 166 167
  if (pMsg->ReservedForRuntime) {
    conn = pMsg->ReservedForRuntime;
    pMsg->ReservedForRuntime = NULL;
  } else {
    status = RPCRT4_OpenBinding(bind, &conn);
    if (status != RPC_S_OK) return status;
  }

  act = &bind->ActiveUuid;
168

169 170
  for (;;) {
    /* read packet header */
171
#ifdef OVERLAPPED_WORKS
172 173 174 175 176 177 178 179 180 181
    if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, &conn->ovl)) {
      DWORD err = GetLastError();
      if (err != ERROR_IO_PENDING) {
        status = err;
        goto fail;
      }
      if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
        status = GetLastError();
        goto fail;
      }
182 183
    }
#else
184 185 186 187
    if (!ReadFile(conn->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
      status = GetLastError();
      goto fail;
    }
188
#endif
189 190 191 192
    if (dwRead != sizeof(hdr)) {
      status = RPC_S_PROTOCOL_ERROR;
      goto fail;
    }
193

194 195 196 197 198
    /* read packet body */
    pMsg->BufferLength = hdr.len;
    status = I_RpcGetBuffer(pMsg);
    if (status != RPC_S_OK) goto fail;
    if (!pMsg->BufferLength) dwRead = 0; else
199
#ifdef OVERLAPPED_WORKS
200 201 202 203 204 205 206 207 208 209
    if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, &conn->ovl)) {
      DWORD err = GetLastError();
      if (err != ERROR_IO_PENDING) {
        status = err;
        goto fail;
      }
      if (!GetOverlappedResult(conn->conn, &conn->ovl, &dwRead, TRUE)) {
        status = GetLastError();
        goto fail;
      }
210 211
    }
#else
212 213 214 215
    if (!ReadFile(conn->conn, pMsg->Buffer, hdr.len, &dwRead, NULL)) {
      status = GetLastError();
      goto fail;
    }
216
#endif
217 218 219 220
    if (dwRead != hdr.len) {
      status = RPC_S_PROTOCOL_ERROR;
      goto fail;
    }
221

222 223 224 225 226 227 228 229 230
    /* success */
    status = RPC_S_OK;

    /* FIXME: check packet type, destination, etc? */
    break;
  }
fail:
  RPCRT4_CloseBinding(bind, conn);
  return status;
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
}

/***********************************************************************
 *           I_RpcSendReceive [RPCRT4.@]
 */
RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
{
  RPC_STATUS status;

  TRACE("(%p)\n", pMsg);
  status = I_RpcSend(pMsg);
  if (status == RPC_S_OK)
    status = I_RpcReceive(pMsg);
  return status;
}