Commit 6cfe2aab authored by Kenton Varda's avatar Kenton Varda

Allow override of membrane import/export behavior.

This gives Sandstorm a way to move the membrane to a different process when desired.
parent 5183fcaa
......@@ -324,11 +324,16 @@ public:
if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) {
// Capability that passed across the membrane one way is now passing back the other way.
// Unwrap it rather than double-wrap it.
return otherMembrane.inner->addRef();
Capability::Client unwrapped(otherMembrane.inner->addRef());
return ClientHook::from(
reverse ? policy.importInternal(kj::mv(unwrapped))
: policy.exportExternal(kj::mv(unwrapped)));
}
}
return kj::refcounted<MembraneHook>(cap.addRef(), policy.addRef(), reverse);
return ClientHook::from(
reverse ? policy.importExternal(Capability::Client(cap.addRef()))
: policy.exportInternal(Capability::Client(cap.addRef())));
}
static kj::Own<ClientHook> wrap(kj::Own<ClientHook> cap, MembranePolicy& policy, bool reverse) {
......@@ -337,11 +342,16 @@ public:
if (otherMembrane.policy.get() == &policy && otherMembrane.reverse == !reverse) {
// Capability that passed across the membrane one way is now passing back the other way.
// Unwrap it rather than double-wrap it.
return otherMembrane.inner->addRef();
Capability::Client unwrapped(otherMembrane.inner->addRef());
return ClientHook::from(
reverse ? policy.importInternal(kj::mv(unwrapped))
: policy.exportExternal(kj::mv(unwrapped)));
}
}
return kj::refcounted<MembraneHook>(kj::mv(cap), policy.addRef(), reverse);
return ClientHook::from(
reverse ? policy.importExternal(Capability::Client(kj::mv(cap)))
: policy.exportInternal(Capability::Client(kj::mv(cap))));
}
Request<AnyPointer, AnyPointer> newCall(
......@@ -469,6 +479,24 @@ kj::Own<ClientHook> membrane(kj::Own<ClientHook> inner, MembranePolicy& policy,
} // namespace
Capability::Client MembranePolicy::importExternal(Capability::Client external) {
return Capability::Client(kj::refcounted<MembraneHook>(
ClientHook::from(kj::mv(external)), addRef(), true));
}
Capability::Client MembranePolicy::exportInternal(Capability::Client internal) {
return Capability::Client(kj::refcounted<MembraneHook>(
ClientHook::from(kj::mv(internal)), addRef(), false));
}
Capability::Client MembranePolicy::importInternal(Capability::Client internal) {
return kj::mv(internal);
}
Capability::Client MembranePolicy::exportExternal(Capability::Client external) {
return kj::mv(external);
}
Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy) {
return Capability::Client(membrane(
ClientHook::from(kj::mv(inner)), *policy, false));
......
......@@ -114,6 +114,47 @@ public:
// After the revocation promise has rejected, inboundCall() and outboundCall() will still be
// invoked for new calls, but the `target` passed to them will be a capability that always
// rethrows the revocation exception.
// ---------------------------------------------------------------------------
// Control over importing and exporting.
//
// Most membranes should not override these methods. The default behavior is that a capability
// that crosses the membrane is wrapped in it, and if the wrapped version crosses back the other
// way, it is unwrapped.
virtual Capability::Client importExternal(Capability::Client external);
// An external capability is crossing into the membrane. Returns the capability that should
// substitute for it when called from the inside.
//
// The default implementation creates a capability that invokes this MembranePolicy. E.g. all
// calls will invoke outboundCall().
//
// Note that reverseMembrane(cap, policy) normally calls policy->importExternal(cap), unless
// `cap` itself was originally returned by the default implementation of exportInternal(), in
// which case importInternal() is called instead.
virtual Capability::Client exportInternal(Capability::Client internal);
// An internal capability is crossing out of the membrane. Returns the capability that should
// substitute for it when called from the outside.
//
// The default implementation creates a capability that invokes this MembranePolicy. E.g. all
// calls will invoke inboundCall().
//
// Note that membrane(cap, policy) normally calls policy->exportInternal(cap), unless `cap`
// itself was originally returned by the default implementation of exportInternal(), in which
// case importInternal() is called instead.
virtual Capability::Client importInternal(Capability::Client internal);
// An internal capability which was previously exported is now being re-imported, i.e. a
// capability passed out of the membrane and then back in.
//
// The default implementation simply returns `internal`.
virtual Capability::Client exportExternal(Capability::Client external);
// An external capability which was previously imported is now being re-exported, i.e. a
// capability passed into the membrane and then back out.
//
// The default implementation simply returns `external`.
};
Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment