capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

membrane.c++ (21505B)


      1 // Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "membrane.h"
     23 #include <kj/debug.h>
     24 
     25 namespace capnp {
     26 
     27 namespace {
     28 
     29 static const char DUMMY = 0;
     30 static constexpr const void* MEMBRANE_BRAND = &DUMMY;
     31 
     32 kj::Own<ClientHook> membrane(kj::Own<ClientHook> inner, MembranePolicy& policy, bool reverse);
     33 
     34 class MembraneCapTableReader final: public _::CapTableReader {
     35 public:
     36   MembraneCapTableReader(MembranePolicy& policy, bool reverse)
     37       : policy(policy), reverse(reverse) {}
     38 
     39   AnyPointer::Reader imbue(AnyPointer::Reader reader) {
     40     return AnyPointer::Reader(imbue(
     41         _::PointerHelpers<AnyPointer>::getInternalReader(kj::mv(reader))));
     42   }
     43 
     44   _::PointerReader imbue(_::PointerReader reader) {
     45     KJ_REQUIRE(inner == nullptr, "can only call this once");
     46     inner = reader.getCapTable();
     47     return reader.imbue(this);
     48   }
     49 
     50   _::StructReader imbue(_::StructReader reader) {
     51     KJ_REQUIRE(inner == nullptr, "can only call this once");
     52     inner = reader.getCapTable();
     53     return reader.imbue(this);
     54   }
     55 
     56   _::ListReader imbue(_::ListReader reader) {
     57     KJ_REQUIRE(inner == nullptr, "can only call this once");
     58     inner = reader.getCapTable();
     59     return reader.imbue(this);
     60   }
     61 
     62   kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override {
     63     // The underlying message is inside the membrane, and we're pulling a cap out of it. Therefore,
     64     // we want to wrap the extracted capability in the membrane.
     65     return inner->extractCap(index).map([this](kj::Own<ClientHook>&& cap) {
     66       return membrane(kj::mv(cap), policy, reverse);
     67     });
     68   }
     69 
     70 private:
     71   _::CapTableReader* inner = nullptr;
     72   MembranePolicy& policy;
     73   bool reverse;
     74 };
     75 
     76 class MembraneCapTableBuilder final: public _::CapTableBuilder {
     77 public:
     78   MembraneCapTableBuilder(MembranePolicy& policy, bool reverse)
     79       : policy(policy), reverse(reverse) {}
     80 
     81   AnyPointer::Builder imbue(AnyPointer::Builder builder) {
     82     KJ_REQUIRE(inner == nullptr, "can only call this once");
     83     auto pointerBuilder = _::PointerHelpers<AnyPointer>::getInternalBuilder(kj::mv(builder));
     84     inner = pointerBuilder.getCapTable();
     85     return AnyPointer::Builder(pointerBuilder.imbue(this));
     86   }
     87 
     88   AnyPointer::Builder unimbue(AnyPointer::Builder builder) {
     89     auto pointerBuilder = _::PointerHelpers<AnyPointer>::getInternalBuilder(kj::mv(builder));
     90     KJ_REQUIRE(pointerBuilder.getCapTable() == this);
     91     return AnyPointer::Builder(pointerBuilder.imbue(inner));
     92   }
     93 
     94   kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override {
     95     // The underlying message is inside the membrane, and we're pulling a cap out of it. Therefore,
     96     // we want to wrap the extracted capability in the membrane.
     97     return inner->extractCap(index).map([this](kj::Own<ClientHook>&& cap) {
     98       return membrane(kj::mv(cap), policy, reverse);
     99     });
    100   }
    101 
    102   uint injectCap(kj::Own<ClientHook>&& cap) override {
    103     // The underlying message is inside the membrane, and we're inserting a cap from outside into
    104     // it. Therefore we want to add a reverse membrane.
    105     return inner->injectCap(membrane(kj::mv(cap), policy, !reverse));
    106   }
    107 
    108   void dropCap(uint index) override {
    109     inner->dropCap(index);
    110   }
    111 
    112 private:
    113   _::CapTableBuilder* inner = nullptr;
    114   MembranePolicy& policy;
    115   bool reverse;
    116 };
    117 
    118 class MembranePipelineHook final: public PipelineHook, public kj::Refcounted {
    119 public:
    120   MembranePipelineHook(
    121       kj::Own<PipelineHook>&& inner, kj::Own<MembranePolicy>&& policy, bool reverse)
    122       : inner(kj::mv(inner)), policy(kj::mv(policy)), reverse(reverse) {}
    123 
    124   kj::Own<PipelineHook> addRef() override {
    125     return kj::addRef(*this);
    126   }
    127 
    128   kj::Own<ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) override {
    129     return membrane(inner->getPipelinedCap(ops), *policy, reverse);
    130   }
    131 
    132   kj::Own<ClientHook> getPipelinedCap(kj::Array<PipelineOp>&& ops) override {
    133     return membrane(inner->getPipelinedCap(kj::mv(ops)), *policy, reverse);
    134   }
    135 
    136 private:
    137   kj::Own<PipelineHook> inner;
    138   kj::Own<MembranePolicy> policy;
    139   bool reverse;
    140 };
    141 
    142 class MembraneResponseHook final: public ResponseHook {
    143 public:
    144   MembraneResponseHook(
    145       kj::Own<ResponseHook>&& inner, kj::Own<MembranePolicy>&& policy, bool reverse)
    146       : inner(kj::mv(inner)), policy(kj::mv(policy)), capTable(*this->policy, reverse) {}
    147 
    148   AnyPointer::Reader imbue(AnyPointer::Reader reader) { return capTable.imbue(reader); }
    149 
    150 private:
    151   kj::Own<ResponseHook> inner;
    152   kj::Own<MembranePolicy> policy;
    153   MembraneCapTableReader capTable;
    154 };
    155 
    156 class MembraneRequestHook final: public RequestHook {
    157 public:
    158   MembraneRequestHook(kj::Own<RequestHook>&& inner, kj::Own<MembranePolicy>&& policy, bool reverse)
    159       : inner(kj::mv(inner)), policy(kj::mv(policy)),
    160         reverse(reverse), capTable(*this->policy, reverse) {}
    161 
    162   static Request<AnyPointer, AnyPointer> wrap(
    163       Request<AnyPointer, AnyPointer>&& inner, MembranePolicy& policy, bool reverse) {
    164     AnyPointer::Builder builder = inner;
    165     auto innerHook = RequestHook::from(kj::mv(inner));
    166     if (innerHook->getBrand() == MEMBRANE_BRAND) {
    167       auto& otherMembrane = kj::downcast<MembraneRequestHook>(*innerHook);
    168       if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) {
    169         // Request that passed across the membrane one way is now passing back the other way.
    170         // Unwrap it rather than double-wrap it.
    171         builder = otherMembrane.capTable.unimbue(builder);
    172         return { builder, kj::mv(otherMembrane.inner) };
    173       }
    174     }
    175 
    176     auto newHook = kj::heap<MembraneRequestHook>(kj::mv(innerHook), policy.addRef(), reverse);
    177     builder = newHook->capTable.imbue(builder);
    178     return { builder, kj::mv(newHook) };
    179   }
    180 
    181   static kj::Own<RequestHook> wrap(
    182       kj::Own<RequestHook>&& inner, MembranePolicy& policy, bool reverse) {
    183     if (inner->getBrand() == MEMBRANE_BRAND) {
    184       auto& otherMembrane = kj::downcast<MembraneRequestHook>(*inner);
    185       if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) {
    186         // Request that passed across the membrane one way is now passing back the other way.
    187         // Unwrap it rather than double-wrap it.
    188         return kj::mv(otherMembrane.inner);
    189       }
    190     }
    191 
    192     return kj::heap<MembraneRequestHook>(kj::mv(inner), policy.addRef(), reverse);
    193   }
    194 
    195   RemotePromise<AnyPointer> send() override {
    196     auto promise = inner->send();
    197 
    198     auto newPipeline = AnyPointer::Pipeline(kj::refcounted<MembranePipelineHook>(
    199         PipelineHook::from(kj::mv(promise)), policy->addRef(), reverse));
    200 
    201     auto onRevoked = policy->onRevoked();
    202 
    203     bool reverse = this->reverse;  // for capture
    204     auto newPromise = promise.then(kj::mvCapture(policy,
    205         [reverse](kj::Own<MembranePolicy>&& policy, Response<AnyPointer>&& response) {
    206       AnyPointer::Reader reader = response;
    207       auto newRespHook = kj::heap<MembraneResponseHook>(
    208           ResponseHook::from(kj::mv(response)), policy->addRef(), reverse);
    209       reader = newRespHook->imbue(reader);
    210       return Response<AnyPointer>(reader, kj::mv(newRespHook));
    211     }));
    212 
    213     KJ_IF_MAYBE(r, kj::mv(onRevoked)) {
    214       newPromise = newPromise.exclusiveJoin(r->then([]() -> Response<AnyPointer> {
    215         KJ_FAIL_REQUIRE("onRevoked() promise resolved; it should only reject");
    216       }));
    217     }
    218 
    219     return RemotePromise<AnyPointer>(kj::mv(newPromise), kj::mv(newPipeline));
    220   }
    221 
    222   kj::Promise<void> sendStreaming() override {
    223     auto promise = inner->sendStreaming();
    224 
    225     KJ_IF_MAYBE(r, policy->onRevoked()) {
    226       promise = promise.exclusiveJoin(r->then([]() {
    227         KJ_FAIL_REQUIRE("onRevoked() promise resolved; it should only reject");
    228       }));
    229     }
    230 
    231     return promise;
    232   }
    233 
    234   const void* getBrand() override {
    235     return MEMBRANE_BRAND;
    236   }
    237 
    238 private:
    239   kj::Own<RequestHook> inner;
    240   kj::Own<MembranePolicy> policy;
    241   bool reverse;
    242   MembraneCapTableBuilder capTable;
    243 };
    244 
    245 class MembraneCallContextHook final: public CallContextHook, public kj::Refcounted {
    246 public:
    247   MembraneCallContextHook(kj::Own<CallContextHook>&& inner,
    248                           kj::Own<MembranePolicy>&& policy, bool reverse)
    249       : inner(kj::mv(inner)), policy(kj::mv(policy)), reverse(reverse),
    250         paramsCapTable(*this->policy, reverse),
    251         resultsCapTable(*this->policy, reverse) {}
    252 
    253   AnyPointer::Reader getParams() override {
    254     KJ_REQUIRE(!releasedParams);
    255     KJ_IF_MAYBE(p, params) {
    256       return *p;
    257     } else {
    258       auto result = paramsCapTable.imbue(inner->getParams());
    259       params = result;
    260       return result;
    261     }
    262   }
    263 
    264   void releaseParams() override {
    265     // Note that releaseParams() is idempotent -- it can be called multiple times.
    266     releasedParams = true;
    267     inner->releaseParams();
    268   }
    269 
    270   AnyPointer::Builder getResults(kj::Maybe<MessageSize> sizeHint) override {
    271     KJ_IF_MAYBE(r, results) {
    272       return *r;
    273     } else {
    274       auto result = resultsCapTable.imbue(inner->getResults(sizeHint));
    275       results = result;
    276       return result;
    277     }
    278   }
    279 
    280   void setPipeline(kj::Own<PipelineHook>&& pipeline) override {
    281     inner->setPipeline(kj::refcounted<MembranePipelineHook>(
    282         kj::mv(pipeline), policy->addRef(), !reverse));
    283   }
    284 
    285   kj::Promise<void> tailCall(kj::Own<RequestHook>&& request) override {
    286     return inner->tailCall(MembraneRequestHook::wrap(kj::mv(request), *policy, !reverse));
    287   }
    288 
    289   void allowCancellation() override {
    290     inner->allowCancellation();
    291   }
    292 
    293   kj::Promise<AnyPointer::Pipeline> onTailCall() override {
    294     return inner->onTailCall().then([this](AnyPointer::Pipeline&& innerPipeline) {
    295       return AnyPointer::Pipeline(kj::refcounted<MembranePipelineHook>(
    296           PipelineHook::from(kj::mv(innerPipeline)), policy->addRef(), reverse));
    297     });
    298   }
    299 
    300   ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own<RequestHook>&& request) override {
    301     auto pair = inner->directTailCall(
    302         MembraneRequestHook::wrap(kj::mv(request), *policy, !reverse));
    303 
    304     return {
    305       kj::mv(pair.promise),
    306       kj::refcounted<MembranePipelineHook>(kj::mv(pair.pipeline), policy->addRef(), reverse)
    307     };
    308   }
    309 
    310   kj::Own<CallContextHook> addRef() override {
    311     return kj::addRef(*this);
    312   }
    313 
    314 private:
    315   kj::Own<CallContextHook> inner;
    316   kj::Own<MembranePolicy> policy;
    317   bool reverse;
    318 
    319   MembraneCapTableReader paramsCapTable;
    320   kj::Maybe<AnyPointer::Reader> params;
    321   bool releasedParams = false;
    322 
    323   MembraneCapTableBuilder resultsCapTable;
    324   kj::Maybe<AnyPointer::Builder> results;
    325 };
    326 
    327 class MembraneHook final: public ClientHook, public kj::Refcounted {
    328 public:
    329   MembraneHook(kj::Own<ClientHook>&& inner, kj::Own<MembranePolicy>&& policyParam, bool reverse)
    330       : inner(kj::mv(inner)), policy(kj::mv(policyParam)), reverse(reverse) {
    331     KJ_IF_MAYBE(r, policy->onRevoked()) {
    332       revocationTask = r->eagerlyEvaluate([this](kj::Exception&& exception) {
    333         this->inner = newBrokenCap(kj::mv(exception));
    334       });
    335     }
    336   }
    337 
    338   static kj::Own<ClientHook> wrap(ClientHook& cap, MembranePolicy& policy, bool reverse) {
    339     if (cap.getBrand() == MEMBRANE_BRAND) {
    340       auto& otherMembrane = kj::downcast<MembraneHook>(cap);
    341       auto& rootPolicy = policy.rootPolicy();
    342       if (&otherMembrane.policy->rootPolicy() == &rootPolicy &&
    343           otherMembrane.reverse == !reverse) {
    344         // Capability that passed across the membrane one way is now passing back the other way.
    345         // Unwrap it rather than double-wrap it.
    346         Capability::Client unwrapped(otherMembrane.inner->addRef());
    347         return ClientHook::from(
    348             reverse ? rootPolicy.importInternal(kj::mv(unwrapped), *otherMembrane.policy, policy)
    349                     : rootPolicy.exportExternal(kj::mv(unwrapped), *otherMembrane.policy, policy));
    350       }
    351     }
    352 
    353     return ClientHook::from(
    354         reverse ? policy.importExternal(Capability::Client(cap.addRef()))
    355                 : policy.exportInternal(Capability::Client(cap.addRef())));
    356   }
    357 
    358   static kj::Own<ClientHook> wrap(kj::Own<ClientHook> cap, MembranePolicy& policy, bool reverse) {
    359     if (cap->getBrand() == MEMBRANE_BRAND) {
    360       auto& otherMembrane = kj::downcast<MembraneHook>(*cap);
    361       auto& rootPolicy = policy.rootPolicy();
    362       if (&otherMembrane.policy->rootPolicy() == &rootPolicy &&
    363           otherMembrane.reverse == !reverse) {
    364         // Capability that passed across the membrane one way is now passing back the other way.
    365         // Unwrap it rather than double-wrap it.
    366         Capability::Client unwrapped(otherMembrane.inner->addRef());
    367         return ClientHook::from(
    368             reverse ? rootPolicy.importInternal(kj::mv(unwrapped), *otherMembrane.policy, policy)
    369                     : rootPolicy.exportExternal(kj::mv(unwrapped), *otherMembrane.policy, policy));
    370       }
    371     }
    372 
    373     return ClientHook::from(
    374         reverse ? policy.importExternal(Capability::Client(kj::mv(cap)))
    375                 : policy.exportInternal(Capability::Client(kj::mv(cap))));
    376   }
    377 
    378   Request<AnyPointer, AnyPointer> newCall(
    379       uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) override {
    380     KJ_IF_MAYBE(r, resolved) {
    381       return r->get()->newCall(interfaceId, methodId, sizeHint);
    382     }
    383 
    384     auto redirect = reverse
    385         ? policy->outboundCall(interfaceId, methodId, Capability::Client(inner->addRef()))
    386         : policy->inboundCall(interfaceId, methodId, Capability::Client(inner->addRef()));
    387     KJ_IF_MAYBE(r, redirect) {
    388       if (policy->shouldResolveBeforeRedirecting()) {
    389         // The policy says that *if* this capability points into the membrane, then we want to
    390         // redirect the call. However, if this capability is a promise, then it could resolve to
    391         // something outside the membrane later. We have to wait before we actually redirect,
    392         // otherwise behavior will differ depending on whether the promise is resolved.
    393         KJ_IF_MAYBE(p, whenMoreResolved()) {
    394           return newLocalPromiseClient(p->attach(addRef()))
    395               ->newCall(interfaceId, methodId, sizeHint);
    396         }
    397       }
    398 
    399       return ClientHook::from(kj::mv(*r))->newCall(interfaceId, methodId, sizeHint);
    400     } else {
    401       // For pass-through calls, we don't worry about promises, because if the capability resolves
    402       // to something outside the membrane, then the call will pass back out of the membrane too.
    403       return MembraneRequestHook::wrap(
    404           inner->newCall(interfaceId, methodId, sizeHint), *policy, reverse);
    405     }
    406   }
    407 
    408   VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
    409                               kj::Own<CallContextHook>&& context) override {
    410     KJ_IF_MAYBE(r, resolved) {
    411       return r->get()->call(interfaceId, methodId, kj::mv(context));
    412     }
    413 
    414     auto redirect = reverse
    415         ? policy->outboundCall(interfaceId, methodId, Capability::Client(inner->addRef()))
    416         : policy->inboundCall(interfaceId, methodId, Capability::Client(inner->addRef()));
    417     KJ_IF_MAYBE(r, redirect) {
    418       if (policy->shouldResolveBeforeRedirecting()) {
    419         // The policy says that *if* this capability points into the membrane, then we want to
    420         // redirect the call. However, if this capability is a promise, then it could resolve to
    421         // something outside the membrane later. We have to wait before we actually redirect,
    422         // otherwise behavior will differ depending on whether the promise is resolved.
    423         KJ_IF_MAYBE(p, whenMoreResolved()) {
    424           return newLocalPromiseClient(p->attach(addRef()))
    425               ->call(interfaceId, methodId, kj::mv(context));
    426         }
    427       }
    428 
    429       return ClientHook::from(kj::mv(*r))->call(interfaceId, methodId, kj::mv(context));
    430     } else {
    431       // !reverse because calls to the CallContext go in the opposite direction.
    432       auto result = inner->call(interfaceId, methodId,
    433           kj::refcounted<MembraneCallContextHook>(kj::mv(context), policy->addRef(), !reverse));
    434 
    435       KJ_IF_MAYBE(r, policy->onRevoked()) {
    436         result.promise = result.promise.exclusiveJoin(kj::mv(*r));
    437       }
    438 
    439       return {
    440         kj::mv(result.promise),
    441         kj::refcounted<MembranePipelineHook>(kj::mv(result.pipeline), policy->addRef(), reverse)
    442       };
    443     }
    444   }
    445 
    446   kj::Maybe<ClientHook&> getResolved() override {
    447     KJ_IF_MAYBE(r, resolved) {
    448       return **r;
    449     }
    450 
    451     KJ_IF_MAYBE(newInner, inner->getResolved()) {
    452       kj::Own<ClientHook> newResolved = wrap(*newInner, *policy, reverse);
    453       ClientHook& result = *newResolved;
    454       resolved = kj::mv(newResolved);
    455       return result;
    456     } else {
    457       return nullptr;
    458     }
    459   }
    460 
    461   kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() override {
    462     KJ_IF_MAYBE(r, resolved) {
    463       return kj::Promise<kj::Own<ClientHook>>(r->get()->addRef());
    464     }
    465 
    466     KJ_IF_MAYBE(promise, inner->whenMoreResolved()) {
    467       KJ_IF_MAYBE(r, policy->onRevoked()) {
    468         *promise = promise->exclusiveJoin(r->then([]() -> kj::Own<ClientHook> {
    469           KJ_FAIL_REQUIRE("onRevoked() promise resolved; it should only reject");
    470         }));
    471       }
    472 
    473       return promise->then([this](kj::Own<ClientHook>&& newInner) {
    474         kj::Own<ClientHook> newResolved = wrap(*newInner, *policy, reverse);
    475         if (resolved == nullptr) {
    476           resolved = newResolved->addRef();
    477         }
    478         return newResolved;
    479       });
    480     } else {
    481       return nullptr;
    482     }
    483   }
    484 
    485   kj::Own<ClientHook> addRef() override {
    486     return kj::addRef(*this);
    487   }
    488 
    489   const void* getBrand() override {
    490     return MEMBRANE_BRAND;
    491   }
    492 
    493   kj::Maybe<int> getFd() override {
    494     // We can't let FDs pass over membranes because we have no way to enforce the membrane policy
    495     // on them. If the MembranePolicy wishes to explicitly permit certain FDs to pass, it can
    496     // always do so by overriding the appropriate policy methods.
    497     return nullptr;
    498   }
    499 
    500 private:
    501   kj::Own<ClientHook> inner;
    502   kj::Own<MembranePolicy> policy;
    503   bool reverse;
    504   kj::Maybe<kj::Own<ClientHook>> resolved;
    505   kj::Promise<void> revocationTask = nullptr;
    506 };
    507 
    508 kj::Own<ClientHook> membrane(kj::Own<ClientHook> inner, MembranePolicy& policy, bool reverse) {
    509   return MembraneHook::wrap(kj::mv(inner), policy, reverse);
    510 }
    511 
    512 }  // namespace
    513 
    514 Capability::Client MembranePolicy::importExternal(Capability::Client external) {
    515   return Capability::Client(kj::refcounted<MembraneHook>(
    516       ClientHook::from(kj::mv(external)), addRef(), true));
    517 }
    518 
    519 Capability::Client MembranePolicy::exportInternal(Capability::Client internal) {
    520   return Capability::Client(kj::refcounted<MembraneHook>(
    521       ClientHook::from(kj::mv(internal)), addRef(), false));
    522 }
    523 
    524 Capability::Client MembranePolicy::importInternal(
    525     Capability::Client internal, MembranePolicy& exportPolicy, MembranePolicy& importPolicy) {
    526   return kj::mv(internal);
    527 }
    528 
    529 Capability::Client MembranePolicy::exportExternal(
    530     Capability::Client external, MembranePolicy& importPolicy, MembranePolicy& exportPolicy) {
    531   return kj::mv(external);
    532 }
    533 
    534 Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy) {
    535   return Capability::Client(membrane(
    536       ClientHook::from(kj::mv(inner)), *policy, false));
    537 }
    538 
    539 Capability::Client reverseMembrane(Capability::Client inner, kj::Own<MembranePolicy> policy) {
    540   return Capability::Client(membrane(
    541       ClientHook::from(kj::mv(inner)), *policy, true));
    542 }
    543 
    544 namespace _ {  // private
    545 
    546 _::OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to,
    547                                    kj::Own<MembranePolicy> policy, bool reverse) {
    548   MembraneCapTableReader capTable(*policy, reverse);
    549   return _::OrphanBuilder::copy(
    550       OrphanageInternal::getArena(to),
    551       OrphanageInternal::getCapTable(to),
    552       capTable.imbue(from));
    553 }
    554 
    555 _::OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to,
    556                                    kj::Own<MembranePolicy> policy, bool reverse) {
    557   MembraneCapTableReader capTable(*policy, reverse);
    558   return _::OrphanBuilder::copy(
    559       OrphanageInternal::getArena(to),
    560       OrphanageInternal::getCapTable(to),
    561       capTable.imbue(from));
    562 }
    563 
    564 _::OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to,
    565                                    kj::Own<MembranePolicy> policy, bool reverse) {
    566   MembraneCapTableReader capTable(*policy, reverse);
    567   return _::OrphanBuilder::copy(
    568       OrphanageInternal::getArena(to),
    569       OrphanageInternal::getCapTable(to),
    570       capTable.imbue(from));
    571 }
    572 
    573 }  // namespace _ (private)
    574 
    575 }  // namespace capnp
    576