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