annotate osx/include/capnp/membrane.h @ 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) 2015 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 #ifndef CAPNP_MEMBRANE_H_
cannam@62 23 #define CAPNP_MEMBRANE_H_
cannam@62 24 // In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards
cannam@62 25 // calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a
cannam@62 26 // membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely
cannam@62 27 // introducing new objects.
cannam@62 28 //
cannam@62 29 // The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability
cannam@62 30 // to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this
cannam@62 31 // by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice
cannam@62 32 // indicates it should be revoked, after which all calls through the wrapper will throw exceptions.
cannam@62 33 // However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new
cannam@62 34 // capability in that call, or if Carol returns a capability to Bob in the response to a call, then
cannam@62 35 // the two are now able to communicate using this new capability, which Alice cannot revoke. In
cannam@62 36 // order to avoid this problem, Alice must use not just a wrapper but a "membrane", which
cannam@62 37 // recursively wraps all objects that pass through it in either direction. Thus, all connections
cannam@62 38 // formed between Bob and Carol (originating from Alice's original introduction) can be revoked
cannam@62 39 // together by revoking the membrane.
cannam@62 40 //
cannam@62 41 // Note that when a capability is passed into a membrane and then passed back out, the result is
cannam@62 42 // the original capability, not a double-membraned capability. This means that in our revocation
cannam@62 43 // example, if Bob uses his capability to Carol to obtain another capability from her, then send
cannam@62 44 // it back to her, the capability Carol receives back will NOT be revoked when Bob's access to
cannam@62 45 // Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use
cannam@62 46 // cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then
cannam@62 47 // passed back can be recognized as the original capability.
cannam@62 48 //
cannam@62 49 // Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html
cannam@62 50
cannam@62 51 #include "capability.h"
cannam@62 52
cannam@62 53 namespace capnp {
cannam@62 54
cannam@62 55 class MembranePolicy {
cannam@62 56 // Applications may implement this interface to define a membrane policy, which allows some
cannam@62 57 // calls crossing the membrane to be blocked or redirected.
cannam@62 58
cannam@62 59 public:
cannam@62 60 virtual kj::Maybe<Capability::Client> inboundCall(
cannam@62 61 uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
cannam@62 62 // Given an inbound call (a call originating "outside" the membrane destined for an object
cannam@62 63 // "inside" the membrane), decides what to do with it. The policy may:
cannam@62 64 //
cannam@62 65 // - Return null to indicate that the call should proceed to the destination. All capabilities
cannam@62 66 // in the parameters or result will be properly wrapped in the same membrane.
cannam@62 67 // - Return a capability to have the call redirected to that capability. Note that the redirect
cannam@62 68 // capability will be treated as outside the membrane, so the params and results will not be
cannam@62 69 // auto-wrapped; however, the callee can easily wrap the returned capability in the membrane
cannam@62 70 // itself before returning to achieve this effect.
cannam@62 71 // - Throw an exception to cause the call to fail with that exception.
cannam@62 72 //
cannam@62 73 // `target` is the underlying capability (*inside* the membrane) for which the call is destined.
cannam@62 74 // Generally, the only way you should use `target` is to wrap it in some capability which you
cannam@62 75 // return as a redirect. The redirect capability may modify the call in some way and send it to
cannam@62 76 // `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when
cannam@62 77 // copying parameters or results across the membrane.
cannam@62 78 //
cannam@62 79 // Note that since `target` is inside the capability, if you were to directly return it (rather
cannam@62 80 // than return null), the effect would be that the membrane would be broken: the call would
cannam@62 81 // proceed directly and any new capabilities introduced through it would not be membraned. You
cannam@62 82 // generally should not do that.
cannam@62 83
cannam@62 84 virtual kj::Maybe<Capability::Client> outboundCall(
cannam@62 85 uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
cannam@62 86 // Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating
cannam@62 87 // outside.
cannam@62 88 //
cannam@62 89 // Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases
cannam@62 90 // that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would
cannam@62 91 // redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run
cannam@62 92 // into inconsistent behavion when a promise is returned across a membrane, and that promise
cannam@62 93 // later resolves to a capability on the other side of the membrane: calls on the promise
cannam@62 94 // will enter and then exit the membrane, but calls on the eventual resolution will not cross
cannam@62 95 // the membrane at all, so it is important that these two cases behave the same.
cannam@62 96
cannam@62 97 virtual kj::Own<MembranePolicy> addRef() = 0;
cannam@62 98 // Return a new owned pointer to the same policy.
cannam@62 99 //
cannam@62 100 // Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement
cannam@62 101 // `addRef()` as `return kj::addRef(*this);`.
cannam@62 102 //
cannam@62 103 // Note that the membraning system considers two membranes created with the same MembranePolicy
cannam@62 104 // object actually to be the *same* membrane. This is relevant when an object passes into the
cannam@62 105 // membrane and then back out (or out and then back in): instead of double-wrapping the object,
cannam@62 106 // the wrapping will be removed.
cannam@62 107 };
cannam@62 108
cannam@62 109 Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy);
cannam@62 110 // Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane,
cannam@62 111 // while the returned capability should only be called from outside the membrane.
cannam@62 112
cannam@62 113 Capability::Client reverseMembrane(Capability::Client outer, kj::Own<MembranePolicy> policy);
cannam@62 114 // Like `membrane` but treat the input capability as "outside" the membrane, and return a
cannam@62 115 // capability appropriate for use inside.
cannam@62 116 //
cannam@62 117 // Applications typically won't use this directly; the membraning code automatically sets up
cannam@62 118 // reverse membranes where needed.
cannam@62 119
cannam@62 120 template <typename ClientType>
cannam@62 121 ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy);
cannam@62 122 template <typename ClientType>
cannam@62 123 ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy);
cannam@62 124 // Convenience templates which return the same interface type as the input.
cannam@62 125
cannam@62 126 template <typename ServerType>
cannam@62 127 typename ServerType::Serves::Client membrane(
cannam@62 128 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
cannam@62 129 template <typename ServerType>
cannam@62 130 typename ServerType::Serves::Client reverseMembrane(
cannam@62 131 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
cannam@62 132 // Convenience templates which input a capability server type and return the appropriate client
cannam@62 133 // type.
cannam@62 134
cannam@62 135 template <typename Reader>
cannam@62 136 Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
cannam@62 137 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
cannam@62 138 // Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities
cannam@62 139 // found within it. `from` is interpreted as "outside" the membrane while `to` is "inside".
cannam@62 140
cannam@62 141 template <typename Reader>
cannam@62 142 Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
cannam@62 143 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
cannam@62 144 // Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside".
cannam@62 145
cannam@62 146 // =======================================================================================
cannam@62 147 // inline implementation details
cannam@62 148
cannam@62 149 template <typename ClientType>
cannam@62 150 ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy) {
cannam@62 151 return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
cannam@62 152 .castAs<typename ClientType::Calls>();
cannam@62 153 }
cannam@62 154 template <typename ClientType>
cannam@62 155 ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy) {
cannam@62 156 return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
cannam@62 157 .castAs<typename ClientType::Calls>();
cannam@62 158 }
cannam@62 159
cannam@62 160 template <typename ServerType>
cannam@62 161 typename ServerType::Serves::Client membrane(
cannam@62 162 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
cannam@62 163 return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
cannam@62 164 .castAs<typename ServerType::Serves>();
cannam@62 165 }
cannam@62 166 template <typename ServerType>
cannam@62 167 typename ServerType::Serves::Client reverseMembrane(
cannam@62 168 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
cannam@62 169 return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
cannam@62 170 .castAs<typename ServerType::Serves>();
cannam@62 171 }
cannam@62 172
cannam@62 173 namespace _ { // private
cannam@62 174
cannam@62 175 OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to,
cannam@62 176 kj::Own<MembranePolicy> policy, bool reverse);
cannam@62 177 OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to,
cannam@62 178 kj::Own<MembranePolicy> policy, bool reverse);
cannam@62 179 OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to,
cannam@62 180 kj::Own<MembranePolicy> policy, bool reverse);
cannam@62 181
cannam@62 182 } // namespace _ (private)
cannam@62 183
cannam@62 184 template <typename Reader>
cannam@62 185 Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
cannam@62 186 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
cannam@62 187 return _::copyOutOfMembrane(
cannam@62 188 _::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
cannam@62 189 to, kj::mv(policy), true);
cannam@62 190 }
cannam@62 191
cannam@62 192 template <typename Reader>
cannam@62 193 Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
cannam@62 194 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
cannam@62 195 return _::copyOutOfMembrane(
cannam@62 196 _::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
cannam@62 197 to, kj::mv(policy), false);
cannam@62 198 }
cannam@62 199
cannam@62 200 } // namespace capnp
cannam@62 201
cannam@62 202 #endif // CAPNP_MEMBRANE_H_