rpc.h 19.3 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21 22 23 24

#ifndef CAPNP_RPC_H_
#define CAPNP_RPC_H_

25 26 27 28
#if defined(__GNUC__) && !CAPNP_HEADER_WARNINGS
#pragma GCC system_header
#endif

29
#include "capability.h"
30
#include "rpc-prelude.h"
31 32 33

namespace capnp {

34
template <typename VatId, typename ProvisionId, typename RecipientId,
35 36 37 38
          typename ThirdPartyCapId, typename JoinResult>
class VatNetwork;
template <typename SturdyRefObjectId>
class SturdyRefRestorer;
39

40
template <typename VatId>
41 42 43 44 45 46 47 48 49 50 51 52 53
class RpcSystem: public _::RpcSystemBase {
  // Represents the RPC system, which is the portal to objects available on the network.
  //
  // The RPC implementation sits on top of an implementation of `VatNetwork`.  The `VatNetwork`
  // determines how to form connections between vats -- specifically, two-way, private, reliable,
  // sequenced datagram connections.  The RPC implementation determines how to use such connections
  // to manage object references and make method calls.
  //
  // See `makeRpcServer()` and `makeRpcClient()` below for convenient syntax for setting up an
  // `RpcSystem` given a `VatNetwork`.
  //
  // See `ez-rpc.h` for an even simpler interface for setting up RPC in a typical two-party
  // client/server scenario.
54 55

public:
56 57 58 59
  template <typename ProvisionId, typename RecipientId,
            typename ThirdPartyCapId, typename JoinResult>
  RpcSystem(
      VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
60 61
      kj::Maybe<Capability::Client> bootstrapInterface,
      kj::Maybe<RealmGateway<>::Client> gateway = nullptr);
62

63 64 65 66
  template <typename ProvisionId, typename RecipientId,
            typename ThirdPartyCapId, typename JoinResult,
            typename LocalSturdyRefObjectId>
  RpcSystem(
67 68 69
      VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
      SturdyRefRestorer<LocalSturdyRefObjectId>& restorer);

70
  RpcSystem(RpcSystem&& other) = default;
71

72 73 74 75 76 77 78 79
  Capability::Client bootstrap(typename VatId::Reader vatId);
  // Connect to the given vat and return its bootstrap interface.

  Capability::Client restore(typename VatId::Reader hostId, AnyPointer::Reader objectId)
      KJ_DEPRECATED("Please transition to using a bootstrap interface instead.");
  // ** DEPRECATED **
  //
  // Restores the given SturdyRef from the network and return the capability representing it.
80 81 82
  //
  // `hostId` identifies the host from which to request the ref, in the format specified by the
  // `VatNetwork` in use.  `objectId` is the object ID in whatever format is expected by said host.
83 84 85 86 87
  //
  // This method will be removed in a future version of Cap'n Proto. Instead, please transition
  // to using bootstrap(), which is equivalent to calling restore() with a null `objectId`.
  // You may emulate the old concept of object IDs by exporting a bootstrap interface which has
  // methods that can be used to obtain other capabilities by ID.
88 89
};

90 91 92 93 94
template <typename VatId, typename ProvisionId, typename RecipientId,
          typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
    Capability::Client bootstrapInterface);
95 96 97
// Make an RPC server.  Typical usage (e.g. in a main() function):
//
//    MyEventLoop eventLoop;
98
//    kj::WaitScope waitScope(eventLoop);
99
//    MyNetwork network;
100 101
//    MyMainInterface::Client bootstrap = makeMain();
//    auto server = makeRpcServer(network, bootstrap);
102
//    kj::NEVER_DONE.wait(waitScope);  // run forever
103 104 105
//
// See also ez-rpc.h, which has simpler instructions for the common case of a two-party
// client-server RPC connection.
106

107
template <typename VatId, typename ProvisionId, typename RecipientId,
108 109 110
          typename ThirdPartyCapId, typename JoinResult, typename RealmGatewayClient,
          typename InternalRef = _::InternalRefFromRealmGatewayClient<RealmGatewayClient>,
          typename ExternalRef = _::ExternalRefFromRealmGatewayClient<RealmGatewayClient>>
111 112
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
113
    Capability::Client bootstrapInterface, RealmGatewayClient gateway);
114 115 116 117
// Make an RPC server for a VatNetwork that resides in a different realm from the application.
// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format
// and the network's ("external") format.

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
template <typename VatId, typename LocalSturdyRefObjectId,
          typename ProvisionId, typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
    SturdyRefRestorer<LocalSturdyRefObjectId>& restorer)
    KJ_DEPRECATED("Please transition to using a bootstrap interface instead.");
// ** DEPRECATED **
//
// Create an RPC server which exports multiple main interfaces by object ID. The `restorer` object
// can be used to look up objects by ID.
//
// Please transition to exporting only one interface, which is known as the "bootstrap" interface.
// For backwards-compatibility with old clients, continue to implement SturdyRefRestorer, but
// return the new bootstrap interface when the request object ID is null. When new clients connect
// and request the bootstrap interface, they will get that interface. Eventually, once all clients
// are updated to request only the bootstrap interface, stop implementing SturdyRefRestorer and
// switch to passing the bootstrap capability itself as the second parameter to `makeRpcServer()`.

template <typename VatId, typename ProvisionId,
137
          typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
138 139
RpcSystem<VatId> makeRpcClient(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network);
140 141 142
// Make an RPC client.  Typical usage (e.g. in a main() function):
//
//    MyEventLoop eventLoop;
143
//    kj::WaitScope waitScope(eventLoop);
144
//    MyNetwork network;
145
//    auto client = makeRpcClient(network);
146
//    MyCapability::Client cap = client.restore(hostId, objId).castAs<MyCapability>();
147
//    auto response = cap.fooRequest().send().wait(waitScope);
148 149 150 151
//    handleMyResponse(response);
//
// See also ez-rpc.h, which has simpler instructions for the common case of a two-party
// client-server RPC connection.
152

153
template <typename VatId, typename ProvisionId, typename RecipientId,
154 155 156
          typename ThirdPartyCapId, typename JoinResult, typename RealmGatewayClient,
          typename InternalRef = _::InternalRefFromRealmGatewayClient<RealmGatewayClient>,
          typename ExternalRef = _::ExternalRefFromRealmGatewayClient<RealmGatewayClient>>
157 158
RpcSystem<VatId> makeRpcClient(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
159
    RealmGatewayClient gateway);
160 161 162 163
// Make an RPC client for a VatNetwork that resides in a different realm from the application.
// The given RealmGateway is used to translate SturdyRefs between the app's ("internal") format
// and the network's ("external") format.

164 165
template <typename SturdyRefObjectId>
class SturdyRefRestorer: public _::SturdyRefRestorerBase {
166 167 168 169 170 171 172 173 174 175
  // ** DEPRECATED **
  //
  // In Cap'n Proto 0.4.x, applications could export multiple main interfaces identified by
  // object IDs. The callback used to map object IDs to objects was `SturdyRefRestorer`, as we
  // imagined this would eventually be used for restoring SturdyRefs as well. In practice, it was
  // never used for real SturdyRefs, only for exporting singleton objects under well-known names.
  //
  // The new preferred strategy is to export only a _single_ such interface, called the
  // "bootstrap interface". That interface can itself have methods for obtaining other objects, of
  // course, but that is up to the app. `SturdyRefRestorer` exists for backwards-compatibility.
176 177 178
  //
  // Hint:  Use SturdyRefRestorer<capnp::Text> to define a server that exports services under
  //   string names.
179

180
public:
181 182 183
  virtual Capability::Client restore(typename SturdyRefObjectId::Reader ref)
      KJ_DEPRECATED(
          "Please transition to using bootstrap interfaces instead of SturdyRefRestorer.") = 0;
184
  // Restore the given object, returning a capability representing it.
185

186
private:
187
  Capability::Client baseRestore(AnyPointer::Reader ref) override final;
188 189 190
};

// =======================================================================================
191
// VatNetwork
192 193

class OutgoingRpcMessage {
194 195
  // A message to be sent by a `VatNetwork`.

196
public:
197
  virtual AnyPointer::Builder getBody() = 0;
198 199 200
  // Get the message body, which the caller may fill in any way it wants.  (The standard RPC
  // implementation initializes it as a Message as defined in rpc.capnp.)

201 202 203
  virtual kj::ArrayPtr<kj::Maybe<kj::Own<ClientHook>>> getCapTable() = 0;
  // Calls getCapTable() on the underlying MessageBuilder.

204 205 206 207 208 209
  virtual void send() = 0;
  // Send the message, or at least put it in a queue to be sent later.  Note that the builder
  // returned by `getBody()` remains valid at least until the `OutgoingRpcMessage` is destroyed.
};

class IncomingRpcMessage {
210 211
  // A message received from a `VatNetwork`.

212
public:
213
  virtual AnyPointer::Reader getBody() = 0;
214 215
  // Get the message body, to be interpreted by the caller.  (The standard RPC implementation
  // interprets it as a Message as defined in rpc.capnp.)
216 217 218

  virtual void initCapTable(kj::Array<kj::Maybe<kj::Own<ClientHook>>>&& capTable) = 0;
  // Calls initCapTable() on the underlying MessageReader.
219 220
};

221
template <typename VatId, typename ProvisionId, typename RecipientId,
222
          typename ThirdPartyCapId, typename JoinResult>
223
class VatNetwork: public _::VatNetworkBase {
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
  // Cap'n Proto RPC operates between vats, where a "vat" is some sort of host of objects.
  // Typically one Cap'n Proto process (in the Unix sense) is one vat.  The RPC system is what
  // allows calls between objects hosted in different vats.
  //
  // The RPC implementation sits on top of an implementation of `VatNetwork`.  The `VatNetwork`
  // determines how to form connections between vats -- specifically, two-way, private, reliable,
  // sequenced datagram connections.  The RPC implementation determines how to use such connections
  // to manage object references and make method calls.
  //
  // The most common implementation of VatNetwork is TwoPartyVatNetwork (rpc-twoparty.h).  Most
  // simple client-server apps will want to use it.  (You may even want to use the EZ RPC
  // interfaces in `ez-rpc.h` and avoid all of this.)
  //
  // TODO(someday):  Provide a standard implementation for the public internet.

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
public:
  class Connection;

  struct ConnectionAndProvisionId {
    // Result of connecting to a vat introduced by another vat.

    kj::Own<Connection> connection;
    // Connection to the new vat.

    kj::Own<OutgoingRpcMessage> firstMessage;
    // An already-allocated `OutgoingRpcMessage` associated with `connection`.  The RPC system will
    // construct this as an `Accept` message and send it.

    Orphan<ProvisionId> provisionId;
    // A `ProvisionId` already allocated inside `firstMessage`, which the RPC system will use to
    // build the `Accept` message.
  };

  class Connection: public _::VatNetworkBase::Connection {
    // A two-way RPC connection.
    //
    // This object may represent a connection that doesn't exist yet, but is expected to exist
    // in the future.  In this case, sent messages will automatically be queued and sent once the
    // connection is ready, so that the caller doesn't need to know the difference.

  public:
    // Level 0 features ----------------------------------------------

267
    virtual kj::Own<OutgoingRpcMessage> newOutgoingMessage(uint firstSegmentWordSize) = 0;
268 269 270 271 272 273
    // Allocate a new message to be sent on this connection.
    //
    // If `firstSegmentWordSize` is non-zero, it should be treated as a hint suggesting how large
    // to make the first segment.  This is entirely a hint and the connection may adjust it up or
    // down.  If it is zero, the connection should choose the size itself.

274 275 276
    virtual kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> receiveIncomingMessage() = 0;
    // Wait for a message to be received and return it.  If the read stream cleanly terminates,
    // return null.  If any other problem occurs, throw an exception.
Kenton Varda's avatar
Kenton Varda committed
277 278 279 280

    virtual kj::Promise<void> shutdown() = 0;
    // Waits until all outgoing messages have been sent, then shuts down the outgoing stream. The
    // returned promise resolves after shutdown is complete.
281 282 283 284
  };

  // Level 0 features ------------------------------------------------

285 286
  virtual kj::Maybe<kj::Own<Connection>> connect(typename VatId::Reader hostId) = 0;
  // Connect to a VatId.  Note that this method immediately returns a `Connection`, even
287 288 289 290 291 292 293
  // if the network connection has not yet been established.  Messages can be queued to this
  // connection and will be delivered once it is open.  The caller must attempt to read from the
  // connection to verify that it actually succeeded; the read will fail if the connection
  // couldn't be opened.  Some network implementations may actually start sending messages before
  // hearing back from the server at all, to avoid a round trip.
  //
  // Returns nullptr if `hostId` refers to the local host.
294

295 296
  virtual kj::Promise<kj::Own<Connection>> accept() = 0;
  // Wait for the next incoming connection and return it.
297 298 299 300 301

  // Level 4 features ------------------------------------------------
  // TODO(someday)

private:
302
  kj::Maybe<kj::Own<_::VatNetworkBase::Connection>>
303 304
      baseConnect(_::StructReader hostId) override final;
  kj::Promise<kj::Own<_::VatNetworkBase::Connection>> baseAccept() override final;
305 306 307 308 309 310 311 312 313
};

// =======================================================================================
// ***************************************************************************************
// Inline implementation details start here
// ***************************************************************************************
// =======================================================================================

template <typename SturdyRef, typename ProvisionId, typename RecipientId,
314
          typename ThirdPartyCapId, typename JoinResult>
315
kj::Maybe<kj::Own<_::VatNetworkBase::Connection>>
316
    VatNetwork<SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>::
317 318
    baseConnect(_::StructReader ref) {
  auto maybe = connect(typename SturdyRef::Reader(ref));
319 320 321
  return maybe.map([](kj::Own<Connection>& conn) -> kj::Own<_::VatNetworkBase::Connection> {
    return kj::mv(conn);
  });
322 323 324
}

template <typename SturdyRef, typename ProvisionId, typename RecipientId,
325
          typename ThirdPartyCapId, typename JoinResult>
326
kj::Promise<kj::Own<_::VatNetworkBase::Connection>>
327 328
    VatNetwork<SturdyRef, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>::baseAccept() {
  return accept().then(
329 330 331 332 333 334
      [](kj::Own<Connection>&& connection) -> kj::Own<_::VatNetworkBase::Connection> {
    return kj::mv(connection);
  });
}

template <typename SturdyRef>
335
Capability::Client SturdyRefRestorer<SturdyRef>::baseRestore(AnyPointer::Reader ref) {
336 337
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
338
  return restore(ref.getAs<SturdyRef>());
339
#pragma GCC diagnostic pop
340 341
}

342 343 344 345 346
template <typename VatId>
template <typename ProvisionId, typename RecipientId,
          typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId>::RpcSystem(
      VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
347 348 349
      kj::Maybe<Capability::Client> bootstrap,
      kj::Maybe<RealmGateway<>::Client> gateway)
    : _::RpcSystemBase(network, kj::mv(bootstrap), kj::mv(gateway)) {}
350 351

template <typename VatId>
352
template <typename ProvisionId, typename RecipientId,
353
          typename ThirdPartyCapId, typename JoinResult,
354
          typename LocalSturdyRefObjectId>
355 356 357
RpcSystem<VatId>::RpcSystem(
      VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
      SturdyRefRestorer<LocalSturdyRefObjectId>& restorer)
358
    : _::RpcSystemBase(network, restorer) {}
359

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
template <typename VatId>
Capability::Client RpcSystem<VatId>::bootstrap(typename VatId::Reader vatId) {
  return baseBootstrap(_::PointerHelpers<VatId>::getInternalReader(vatId));
}

template <typename VatId>
Capability::Client RpcSystem<VatId>::restore(
    typename VatId::Reader hostId, AnyPointer::Reader objectId) {
  return baseRestore(_::PointerHelpers<VatId>::getInternalReader(hostId), objectId);
}

template <typename VatId, typename ProvisionId, typename RecipientId,
          typename ThirdPartyCapId, typename JoinResult>
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
    Capability::Client bootstrapInterface) {
  return RpcSystem<VatId>(network, kj::mv(bootstrapInterface));
377 378
}

379 380
template <typename VatId, typename ProvisionId, typename RecipientId,
          typename ThirdPartyCapId, typename JoinResult,
381
          typename RealmGatewayClient, typename InternalRef, typename ExternalRef>
382 383
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
384
    Capability::Client bootstrapInterface, RealmGatewayClient gateway) {
385 386 387 388
  return RpcSystem<VatId>(network, kj::mv(bootstrapInterface),
      gateway.template castAs<RealmGateway<>>());
}

389
template <typename VatId, typename LocalSturdyRefObjectId,
390
          typename ProvisionId, typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
391 392
RpcSystem<VatId> makeRpcServer(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
393
    SturdyRefRestorer<LocalSturdyRefObjectId>& restorer) {
394
  return RpcSystem<VatId>(network, restorer);
395 396
}

397
template <typename VatId, typename ProvisionId,
398
          typename RecipientId, typename ThirdPartyCapId, typename JoinResult>
399 400 401
RpcSystem<VatId> makeRpcClient(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network) {
  return RpcSystem<VatId>(network, nullptr);
402 403
}

404 405
template <typename VatId, typename ProvisionId,
          typename RecipientId, typename ThirdPartyCapId, typename JoinResult,
406
          typename RealmGatewayClient, typename InternalRef, typename ExternalRef>
407 408
RpcSystem<VatId> makeRpcClient(
    VatNetwork<VatId, ProvisionId, RecipientId, ThirdPartyCapId, JoinResult>& network,
409
    RealmGatewayClient gateway) {
410 411 412
  return RpcSystem<VatId>(network, nullptr, gateway.template castAs<RealmGateway<>>());
}

413 414 415
}  // namespace capnp

#endif  // CAPNP_RPC_H_