annotate osx/include/capnp/rpc-twoparty.capnp @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0994c39f1e94
children
rev   line source
cannam@62 1 # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@62 2 # Licensed under the MIT License:
cannam@62 3 #
cannam@62 4 # Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@62 5 # of this software and associated documentation files (the "Software"), to deal
cannam@62 6 # in the Software without restriction, including without limitation the rights
cannam@62 7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@62 8 # copies of the Software, and to permit persons to whom the Software is
cannam@62 9 # furnished to do so, subject to the following conditions:
cannam@62 10 #
cannam@62 11 # The above copyright notice and this permission notice shall be included in
cannam@62 12 # all copies or substantial portions of the Software.
cannam@62 13 #
cannam@62 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@62 15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@62 16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@62 17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@62 18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@62 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@62 20 # THE SOFTWARE.
cannam@62 21
cannam@62 22 @0xa184c7885cdaf2a1;
cannam@62 23 # This file defines the "network-specific parameters" in rpc.capnp to support a network consisting
cannam@62 24 # of two vats. Each of these vats may in fact be in communication with other vats, but any
cannam@62 25 # capabilities they forward must be proxied. Thus, to each end of the connection, all capabilities
cannam@62 26 # received from the other end appear to live in a single vat.
cannam@62 27 #
cannam@62 28 # Two notable use cases for this model include:
cannam@62 29 # - Regular client-server communications, where a remote client machine (perhaps living on an end
cannam@62 30 # user's personal device) connects to a server. The server may be part of a cluster, and may
cannam@62 31 # call on other servers in the cluster to help service the user's request. It may even obtain
cannam@62 32 # capabilities from these other servers which it passes on to the user. To simplify network
cannam@62 33 # common traversal problems (e.g. if the user is behind a firewall), it is probably desirable to
cannam@62 34 # multiplex all communications between the server cluster and the client over the original
cannam@62 35 # connection rather than form new ones. This connection should use the two-party protocol, as
cannam@62 36 # the client has no interest in knowing about additional servers.
cannam@62 37 # - Applications running in a sandbox. A supervisor process may execute a confined application
cannam@62 38 # such that all of the confined app's communications with the outside world must pass through
cannam@62 39 # the supervisor. In this case, the connection between the confined app and the supervisor might
cannam@62 40 # as well use the two-party protocol, because the confined app is intentionally prevented from
cannam@62 41 # talking to any other vat anyway. Any external resources will be proxied through the supervisor,
cannam@62 42 # and so to the contained app will appear as if they were hosted by the supervisor itself.
cannam@62 43 #
cannam@62 44 # Since there are only two vats in this network, there is never a need for three-way introductions,
cannam@62 45 # so level 3 is free. Moreover, because it is never necessary to form new connections, the
cannam@62 46 # two-party protocol can be used easily anywhere where a two-way byte stream exists, without regard
cannam@62 47 # to where that byte stream goes or how it was initiated. This makes the two-party runtime library
cannam@62 48 # highly reusable.
cannam@62 49 #
cannam@62 50 # Joins (level 4) _could_ be needed in cases where one or both vats are participating in other
cannam@62 51 # networks that use joins. For instance, if Alice and Bob are speaking through the two-party
cannam@62 52 # protocol, and Bob is also participating on another network, Bob may send Alice two or more
cannam@62 53 # proxied capabilities which, unbeknownst to Bob at the time, are in fact pointing at the same
cannam@62 54 # remote object. Alice may then request to join these capabilities, at which point Bob will have
cannam@62 55 # to forward the join to the other network. Note, however, that if Alice is _not_ participating on
cannam@62 56 # any other network, then Alice will never need to _receive_ a Join, because Alice would always
cannam@62 57 # know when two locally-hosted capabilities are the same and would never export a redundant alias
cannam@62 58 # to Bob. So, Alice can respond to all incoming joins with an error, and only needs to implement
cannam@62 59 # outgoing joins if she herself desires to use this feature. Also, outgoing joins are relatively
cannam@62 60 # easy to implement in this scenario.
cannam@62 61 #
cannam@62 62 # What all this means is that a level 4 implementation of the confined network is barely more
cannam@62 63 # complicated than a level 2 implementation. However, such an implementation allows the "client"
cannam@62 64 # or "confined" app to access the server's/supervisor's network with equal functionality to any
cannam@62 65 # native participant. In other words, an application which implements only the two-party protocol
cannam@62 66 # can be paired with a proxy app in order to participate in any network.
cannam@62 67 #
cannam@62 68 # So, when implementing Cap'n Proto in a new language, it makes sense to implement only the
cannam@62 69 # two-party protocol initially, and then pair applications with an appropriate proxy written in
cannam@62 70 # C++, rather than implement other parameterizations of the RPC protocol directly.
cannam@62 71
cannam@62 72 using Cxx = import "/capnp/c++.capnp";
cannam@62 73 $Cxx.namespace("capnp::rpc::twoparty");
cannam@62 74
cannam@62 75 # Note: SturdyRef is not specified here. It is up to the application to define semantics of
cannam@62 76 # SturdyRefs if desired.
cannam@62 77
cannam@62 78 enum Side {
cannam@62 79 server @0;
cannam@62 80 # The object lives on the "server" or "supervisor" end of the connection. Only the
cannam@62 81 # server/supervisor knows how to interpret the ref; to the client, it is opaque.
cannam@62 82 #
cannam@62 83 # Note that containers intending to implement strong confinement should rewrite SturdyRefs
cannam@62 84 # received from the external network before passing them on to the confined app. The confined
cannam@62 85 # app thus does not ever receive the raw bits of the SturdyRef (which it could perhaps
cannam@62 86 # maliciously leak), but instead receives only a thing that it can pass back to the container
cannam@62 87 # later to restore the ref. See:
cannam@62 88 # http://www.erights.org/elib/capability/dist-confine.html
cannam@62 89
cannam@62 90 client @1;
cannam@62 91 # The object lives on the "client" or "confined app" end of the connection. Only the client
cannam@62 92 # knows how to interpret the ref; to the server/supervisor, it is opaque. Most clients do not
cannam@62 93 # actually know how to persist capabilities at all, so use of this is unusual.
cannam@62 94 }
cannam@62 95
cannam@62 96 struct VatId {
cannam@62 97 side @0 :Side;
cannam@62 98 }
cannam@62 99
cannam@62 100 struct ProvisionId {
cannam@62 101 # Only used for joins, since three-way introductions never happen on a two-party network.
cannam@62 102
cannam@62 103 joinId @0 :UInt32;
cannam@62 104 # The ID from `JoinKeyPart`.
cannam@62 105 }
cannam@62 106
cannam@62 107 struct RecipientId {}
cannam@62 108 # Never used, because there are only two parties.
cannam@62 109
cannam@62 110 struct ThirdPartyCapId {}
cannam@62 111 # Never used, because there is no third party.
cannam@62 112
cannam@62 113 struct JoinKeyPart {
cannam@62 114 # Joins in the two-party case are simplified by a few observations.
cannam@62 115 #
cannam@62 116 # First, on a two-party network, a Join only ever makes sense if the receiving end is also
cannam@62 117 # connected to other networks. A vat which is not connected to any other network can safely
cannam@62 118 # reject all joins.
cannam@62 119 #
cannam@62 120 # Second, since a two-party connection bisects the network -- there can be no other connections
cannam@62 121 # between the networks at either end of the connection -- if one part of a join crosses the
cannam@62 122 # connection, then _all_ parts must cross it. Therefore, a vat which is receiving a Join request
cannam@62 123 # off some other network which needs to be forwarded across the two-party connection can
cannam@62 124 # collect all the parts on its end and only forward them across the two-party connection when all
cannam@62 125 # have been received.
cannam@62 126 #
cannam@62 127 # For example, imagine that Alice and Bob are vats connected over a two-party connection, and
cannam@62 128 # each is also connected to other networks. At some point, Alice receives one part of a Join
cannam@62 129 # request off her network. The request is addressed to a capability that Alice received from
cannam@62 130 # Bob and is proxying to her other network. Alice goes ahead and responds to the Join part as
cannam@62 131 # if she hosted the capability locally (this is important so that if not all the Join parts end
cannam@62 132 # up at Alice, the original sender can detect the failed Join without hanging). As other parts
cannam@62 133 # trickle in, Alice verifies that each part is addressed to a capability from Bob and continues
cannam@62 134 # to respond to each one. Once the complete set of join parts is received, Alice checks if they
cannam@62 135 # were all for the exact same capability. If so, she doesn't need to send anything to Bob at
cannam@62 136 # all. Otherwise, she collects the set of capabilities (from Bob) to which the join parts were
cannam@62 137 # addressed and essentially initiates a _new_ Join request on those capabilities to Bob. Alice
cannam@62 138 # does not forward the Join parts she received herself, but essentially forwards the Join as a
cannam@62 139 # whole.
cannam@62 140 #
cannam@62 141 # On Bob's end, since he knows that Alice will always send all parts of a Join together, he
cannam@62 142 # simply waits until he's received them all, then performs a join on the respective capabilities
cannam@62 143 # as if it had been requested locally.
cannam@62 144
cannam@62 145 joinId @0 :UInt32;
cannam@62 146 # A number identifying this join, chosen by the sender. May be reused once `Finish` messages are
cannam@62 147 # sent corresponding to all of the `Join` messages.
cannam@62 148
cannam@62 149 partCount @1 :UInt16;
cannam@62 150 # The number of capabilities to be joined.
cannam@62 151
cannam@62 152 partNum @2 :UInt16;
cannam@62 153 # Which part this request targets -- a number in the range [0, partCount).
cannam@62 154 }
cannam@62 155
cannam@62 156 struct JoinResult {
cannam@62 157 joinId @0 :UInt32;
cannam@62 158 # Matches `JoinKeyPart`.
cannam@62 159
cannam@62 160 succeeded @1 :Bool;
cannam@62 161 # All JoinResults in the set will have the same value for `succeeded`. The receiver actually
cannam@62 162 # implements the join by waiting for all the `JoinKeyParts` and then performing its own join on
cannam@62 163 # them, then going back and answering all the join requests afterwards.
cannam@62 164
cannam@62 165 cap @2 :AnyPointer;
cannam@62 166 # One of the JoinResults will have a non-null `cap` which is the joined capability.
cannam@62 167 #
cannam@62 168 # TODO(cleanup): Change `AnyPointer` to `Capability` when that is supported.
cannam@62 169 }