Commit d07bf3b8 authored by Kenton Varda's avatar Kenton Varda

More capabilities core API WIP.

parent 398dac0d
...@@ -24,10 +24,13 @@ ...@@ -24,10 +24,13 @@
#define CAPNP_PRIVATE #define CAPNP_PRIVATE
#include "arena.h" #include "arena.h"
#include "message.h" #include "message.h"
#include "capability.h"
#include <kj/debug.h> #include <kj/debug.h>
#include <vector> #include <vector>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "capability.h"
#include "capability-context.h"
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
...@@ -99,10 +102,42 @@ void BasicReaderArena::reportReadLimitReached() { ...@@ -99,10 +102,42 @@ void BasicReaderArena::reportReadLimitReached() {
} }
} }
namespace {
class DummyClientHook final: public ClientHook {
public:
Request<ObjectPointer, TypelessAnswer> newCall(
uint64_t interfaceId, uint16_t methodId) const override {
KJ_FAIL_REQUIRE("Calling capability that was extracted from a message that had no "
"capability context.");
}
kj::Promise<void> whenResolved() const override {
return kj::READY_NOW;
}
kj::Own<ClientHook> addRef() const override {
return kj::heap<DummyClientHook>();
}
void* getBrand() const override {
return nullptr;
}
};
} // namespace
kj::Own<ClientHook> BasicReaderArena::extractCap(const _::StructReader& capDescriptor) {
KJ_FAIL_REQUIRE("Message contained a capability but is not imbued with a capability context.") {
return kj::heap<DummyClientHook>();
}
}
// ======================================================================================= // =======================================================================================
ImbuedReaderArena::ImbuedReaderArena(Arena* base) ImbuedReaderArena::ImbuedReaderArena(Arena* base, CapExtractorBase* capExtractor)
: base(base), segment0(nullptr, SegmentId(0), nullptr, nullptr) {} : base(base), capExtractor(capExtractor),
segment0(nullptr, SegmentId(0), nullptr, nullptr) {}
ImbuedReaderArena::~ImbuedReaderArena() noexcept(false) {} ImbuedReaderArena::~ImbuedReaderArena() noexcept(false) {}
SegmentReader* ImbuedReaderArena::imbue(SegmentReader* baseSegment) { SegmentReader* ImbuedReaderArena::imbue(SegmentReader* baseSegment) {
...@@ -139,8 +174,6 @@ SegmentReader* ImbuedReaderArena::imbue(SegmentReader* baseSegment) { ...@@ -139,8 +174,6 @@ SegmentReader* ImbuedReaderArena::imbue(SegmentReader* baseSegment) {
return result; return result;
} }
// implements Arena ------------------------------------------------
SegmentReader* ImbuedReaderArena::tryGetSegment(SegmentId id) { SegmentReader* ImbuedReaderArena::tryGetSegment(SegmentId id) {
return imbue(base->tryGetSegment(id)); return imbue(base->tryGetSegment(id));
} }
...@@ -149,6 +182,10 @@ void ImbuedReaderArena::reportReadLimitReached() { ...@@ -149,6 +182,10 @@ void ImbuedReaderArena::reportReadLimitReached() {
return base->reportReadLimitReached(); return base->reportReadLimitReached();
} }
kj::Own<ClientHook> ImbuedReaderArena::extractCap(const _::StructReader& capDescriptor) {
return capExtractor->extractCapInternal(capDescriptor);
}
// ======================================================================================= // =======================================================================================
BasicBuilderArena::BasicBuilderArena(MessageBuilder* message) BasicBuilderArena::BasicBuilderArena(MessageBuilder* message)
...@@ -288,10 +325,19 @@ void BasicBuilderArena::reportReadLimitReached() { ...@@ -288,10 +325,19 @@ void BasicBuilderArena::reportReadLimitReached() {
} }
} }
kj::Own<ClientHook> BasicBuilderArena::extractCap(const _::StructReader& capDescriptor) {
KJ_FAIL_REQUIRE("Message contains no capabilities.");
}
void BasicBuilderArena::injectCap(_::PointerBuilder pointer, kj::Own<ClientHook>&& cap) {
KJ_FAIL_REQUIRE("Cannot inject capability into a builder that has not been imbued with a "
"capability context.");
}
// ======================================================================================= // =======================================================================================
ImbuedBuilderArena::ImbuedBuilderArena(BuilderArena* base) ImbuedBuilderArena::ImbuedBuilderArena(BuilderArena* base, CapInjectorBase* capInjector)
: base(base), segment0(nullptr) {} : base(base), capInjector(capInjector), segment0(nullptr) {}
ImbuedBuilderArena::~ImbuedBuilderArena() noexcept(false) {} ImbuedBuilderArena::~ImbuedBuilderArena() noexcept(false) {}
SegmentBuilder* ImbuedBuilderArena::imbue(SegmentBuilder* baseSegment) { SegmentBuilder* ImbuedBuilderArena::imbue(SegmentBuilder* baseSegment) {
...@@ -334,6 +380,10 @@ void ImbuedBuilderArena::reportReadLimitReached() { ...@@ -334,6 +380,10 @@ void ImbuedBuilderArena::reportReadLimitReached() {
base->reportReadLimitReached(); base->reportReadLimitReached();
} }
kj::Own<ClientHook> ImbuedBuilderArena::extractCap(const _::StructReader& capDescriptor) {
return capInjector->getInjectedCapInternal(capDescriptor);
}
SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) { SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) {
return imbue(base->getSegment(id)); return imbue(base->getSegment(id));
} }
...@@ -344,5 +394,9 @@ BuilderArena::AllocateResult ImbuedBuilderArena::allocate(WordCount amount) { ...@@ -344,5 +394,9 @@ BuilderArena::AllocateResult ImbuedBuilderArena::allocate(WordCount amount) {
return result; return result;
} }
void ImbuedBuilderArena::injectCap(_::PointerBuilder pointer, kj::Own<ClientHook>&& cap) {
return capInjector->injectCapInternal(pointer, kj::mv(cap));
}
} // namespace _ (private) } // namespace _ (private)
} // namespace capnp } // namespace capnp
...@@ -34,10 +34,13 @@ ...@@ -34,10 +34,13 @@
#include <kj/mutex.h> #include <kj/mutex.h>
#include "common.h" #include "common.h"
#include "message.h" #include "message.h"
#include "layout.h"
namespace capnp { namespace capnp {
class TypelessCapability; class CapExtractorBase;
class CapInjectorBase;
class ClientHook;
namespace _ { // private namespace _ { // private
...@@ -182,7 +185,7 @@ public: ...@@ -182,7 +185,7 @@ public:
// the VALIDATE_INPUT() macro which may throw an exception; if it return normally, the caller // the VALIDATE_INPUT() macro which may throw an exception; if it return normally, the caller
// will need to continue with default values. // will need to continue with default values.
virtual kj::Own<TypelessCapability> extractCap(const _::StructReader& capDescriptor); virtual kj::Own<ClientHook> extractCap(const _::StructReader& capDescriptor) = 0;
// Given a StructReader for a capability descriptor embedded in the message, return the // Given a StructReader for a capability descriptor embedded in the message, return the
// corresponding capability. // corresponding capability.
}; };
...@@ -196,6 +199,7 @@ public: ...@@ -196,6 +199,7 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<ClientHook> extractCap(const _::StructReader& capDescriptor);
private: private:
MessageReader* message; MessageReader* message;
...@@ -210,7 +214,7 @@ private: ...@@ -210,7 +214,7 @@ private:
class ImbuedReaderArena final: public Arena { class ImbuedReaderArena final: public Arena {
public: public:
ImbuedReaderArena(Arena* base); ImbuedReaderArena(Arena* base, CapExtractorBase* capExtractor);
~ImbuedReaderArena() noexcept(false); ~ImbuedReaderArena() noexcept(false);
KJ_DISALLOW_COPY(ImbuedReaderArena); KJ_DISALLOW_COPY(ImbuedReaderArena);
...@@ -219,9 +223,11 @@ public: ...@@ -219,9 +223,11 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<ClientHook> extractCap(const _::StructReader& capDescriptor);
private: private:
Arena* base; Arena* base;
CapExtractorBase* capExtractor;
// Optimize for single-segment messages so that small messages are handled quickly. // Optimize for single-segment messages so that small messages are handled quickly.
SegmentReader segment0; SegmentReader segment0;
...@@ -248,7 +254,7 @@ public: ...@@ -248,7 +254,7 @@ public:
// the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific
// segment first if there is one, then fall back to the arena. // segment first if there is one, then fall back to the arena.
virtual void injectCap(_::PointerBuilder pointer, kj::Own<TypelessCapability>&& cap) = 0; virtual void injectCap(_::PointerBuilder pointer, kj::Own<ClientHook>&& cap) = 0;
// Add the capability to the message and initialize the given pointer as an interface pointer // Add the capability to the message and initialize the given pointer as an interface pointer
// pointing to this cap. // pointing to this cap.
}; };
...@@ -271,10 +277,12 @@ public: ...@@ -271,10 +277,12 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<ClientHook> extractCap(const _::StructReader& capDescriptor);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
AllocateResult allocate(WordCount amount) override; AllocateResult allocate(WordCount amount) override;
void injectCap(_::PointerBuilder pointer, kj::Own<ClientHook>&& cap);
private: private:
MessageBuilder* message; MessageBuilder* message;
...@@ -294,7 +302,7 @@ class ImbuedBuilderArena final: public BuilderArena { ...@@ -294,7 +302,7 @@ class ImbuedBuilderArena final: public BuilderArena {
// A BuilderArena imbued with the ability to inject capabilities. // A BuilderArena imbued with the ability to inject capabilities.
public: public:
ImbuedBuilderArena(BuilderArena* base); ImbuedBuilderArena(BuilderArena* base, CapInjectorBase* capInjector);
~ImbuedBuilderArena() noexcept(false); ~ImbuedBuilderArena() noexcept(false);
KJ_DISALLOW_COPY(ImbuedBuilderArena); KJ_DISALLOW_COPY(ImbuedBuilderArena);
...@@ -304,13 +312,16 @@ public: ...@@ -304,13 +312,16 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<ClientHook> extractCap(const _::StructReader& capDescriptor);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
AllocateResult allocate(WordCount amount) override; AllocateResult allocate(WordCount amount) override;
void injectCap(_::PointerBuilder pointer, kj::Own<ClientHook>&& cap);
private: private:
BuilderArena* base; BuilderArena* base;
CapInjectorBase* capInjector;
ImbuedSegmentBuilder segment0; ImbuedSegmentBuilder segment0;
......
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CAPNP_PRIVATE
#include "capability-context.h"
#include "arena.h"
#include <kj/debug.h>
namespace capnp {
CapReaderContext::CapReaderContext(CapExtractorBase& extractor): extractor(&extractor) {}
CapReaderContext::~CapReaderContext() noexcept(false) {
if (extractor == nullptr) {
kj::dtor(arena());
}
}
ObjectPointer::Reader CapReaderContext::imbue(ObjectPointer::Reader base) {
KJ_REQUIRE(extractor != nullptr, "imbue() can only be called once.");
KJ_IF_MAYBE(oldArena, base.reader.getArena()) {
kj::ctor(arena(), oldArena, extractor);
} else {
KJ_FAIL_REQUIRE("Cannot imbue unchecked message.");
}
extractor = nullptr;
return ObjectPointer::Reader(base.reader.imbue(arena()));
}
CapBuilderContext::CapBuilderContext(CapInjectorBase& injector): injector(&injector) {}
CapBuilderContext::~CapBuilderContext() noexcept(false) {
if (injector == nullptr) {
kj::dtor(arena());
}
}
ObjectPointer::Builder CapBuilderContext::imbue(ObjectPointer::Builder base) {
KJ_REQUIRE(injector != nullptr, "imbue() can only be called once.");
kj::ctor(arena(), &base.builder.getArena(), injector);
injector = nullptr;
return ObjectPointer::Builder(base.builder.imbue(arena()));
}
} // namespace capnp
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Classes for imbuing message readers/builders with a capability context.
//
// These classes are for use by RPC implementations. Application code need not know about them.
//
// Normally, MessageReader and MessageBuilder do not support interface pointers because they
// are not RPC-aware and so have no idea how to convert between a serialized CapabilityDescriptor
// and a live capability. To fix this, a reader/builder object needs to be "imbued" with a
// capability context. This creates a new reader/builder which points at the same object but has
// the ability to deal with interface fields. Use `CapReaderContext` and `CapBuilderContext` to
// accomplish this.
#ifndef CAPNP_CAPABILITY_CONTEXT_H_
#define CAPNP_CAPABILITY_CONTEXT_H_
#include "layout.h"
#include "object.h"
#include <kj/mutex.h>
namespace capnp {
class ClientHook;
namespace _ { // private
class ImbuedReaderArena;
class ImbuedBuilderArena;
} // namespace _ (private)
class CapExtractorBase {
// Non-template base class for CapExtractor<T>.
private:
virtual kj::Own<ClientHook> extractCapInternal(const _::StructReader& capDescriptor) = 0;
friend class _::ImbuedReaderArena;
};
class CapInjectorBase {
// Non-template base class for CapInjector<T>.
private:
virtual void injectCapInternal(_::PointerBuilder builder, kj::Own<ClientHook>&& cap) = 0;
virtual kj::Own<ClientHook> getInjectedCapInternal(const _::StructReader& capDescriptor) = 0;
friend class _::ImbuedBuilderArena;
};
template <typename CapDescriptor>
class CapExtractor: public CapExtractorBase {
// Callback used to read a capability from a message, implemented by the RPC system.
// `CapDescriptor` is the struct type which the RPC implementation uses to represent
// capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
public:
virtual kj::Own<ClientHook> extractCap(typename CapDescriptor::Reader descriptor) = 0;
// Given the descriptor read off the wire, construct a live capability.
private:
kj::Own<ClientHook> extractCapInternal(const _::StructReader& capDescriptor) override final {
return extractCap(typename CapDescriptor::Reader(capDescriptor));
}
};
template <typename CapDescriptor>
class CapInjector: public CapInjectorBase {
// Callback used to write a capability into a message, implemented by the RPC system.
// `CapDescriptor` is the struct type which the RPC implementation uses to represent
// capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
public:
virtual void injectCap(typename CapDescriptor::Builder descriptor, kj::Own<ClientHook>&& cap) = 0;
// Fill in the given descriptor so that it describes the given capability.
virtual kj::Own<ClientHook> getInjectedCap(typename CapDescriptor::Reader descriptor) = 0;
// Read back a cap that was previously injected with `injectCap`. This should return a new
// reference.
private:
void injectCapInternal(_::PointerBuilder builder, kj::Own<ClientHook>&& cap) override final {
injectCap(
typename CapDescriptor::Builder(builder.initCapDescriptor(_::structSize<CapDescriptor>())),
kj::mv(cap));
}
kj::Own<ClientHook> getInjectedCapInternal(const _::StructReader& capDescriptor) {
return getInjectedCap(typename CapDescriptor::Reader(capDescriptor));
}
};
// -------------------------------------------------------------------
class CapReaderContext {
// Class which can "imbue" reader objects from some other message with a capability context,
// so that interface pointers found in the message can be extracted and called.
//
// `imbue()` can only be called once per context.
public:
CapReaderContext(CapExtractorBase& extractor);
~CapReaderContext() noexcept(false);
ObjectPointer::Reader imbue(ObjectPointer::Reader base);
private:
CapExtractorBase* extractor; // becomes null once arena is allocated
void* arenaSpace[12 + sizeof(kj::MutexGuarded<void*>) / sizeof(void*)];
_::ImbuedReaderArena& arena() { return *reinterpret_cast<_::ImbuedReaderArena*>(arenaSpace); }
friend class _::ImbuedReaderArena;
};
class CapBuilderContext {
// Class which can "imbue" reader objects from some other message with a capability context,
// so that interface pointers found in the message can be set to point at live capabilities.
//
// `imbue()` can only be called once per context.
public:
CapBuilderContext(CapInjectorBase& injector);
~CapBuilderContext() noexcept(false);
ObjectPointer::Builder imbue(ObjectPointer::Builder base);
private:
CapInjectorBase* injector; // becomes null once arena is allocated
void* arenaSpace[12 + sizeof(kj::MutexGuarded<void*>) / sizeof(void*)];
_::ImbuedBuilderArena& arena() { return *reinterpret_cast<_::ImbuedBuilderArena*>(arenaSpace); }
friend class _::ImbuedBuilderArena;
};
} // namespace capnp
#endif // CAPNP_CAPABILITY_CONTEXT_H_
...@@ -24,19 +24,18 @@ ...@@ -24,19 +24,18 @@
#include "capability.h" #include "capability.h"
namespace capnp { namespace capnp {
namespace _ { // private
CallResult::Pipeline CallResult::Pipeline::getPointerField(uint16_t pointerIndex) const { TypelessAnswer::Pipeline TypelessAnswer::Pipeline::getPointerField(
auto newOps = kj::heapArray<PipelineManager::Op>(ops.size() + 1); uint16_t pointerIndex) const {
auto newOps = kj::heapArray<PipelineOp>(ops.size() + 1);
for (auto i: kj::indices(ops)) { for (auto i: kj::indices(ops)) {
newOps[i] = ops[i]; newOps[i] = ops[i];
} }
auto& newOp = newOps[ops.size()]; auto& newOp = newOps[ops.size()];
newOp.type = PipelineManager::Op::GET_POINTER_FIELD; newOp.type = PipelineOp::GET_POINTER_FIELD;
newOp.pointerIndex = pointerIndex; newOp.pointerIndex = pointerIndex;
return Pipeline(call->addRef(), kj::mv(newOps)); return Pipeline(hook->addRef(), kj::mv(newOps));
} }
} // namespace _ (private)
} // namespace capnp } // namespace capnp
This diff is collapsed.
...@@ -2104,6 +2104,14 @@ PointerReader PointerBuilder::asReader() const { ...@@ -2104,6 +2104,14 @@ PointerReader PointerBuilder::asReader() const {
return PointerReader(segment, pointer, std::numeric_limits<int>::max()); return PointerReader(segment, pointer, std::numeric_limits<int>::max());
} }
BuilderArena& PointerBuilder::getArena() const {
return *segment->getArena();
}
PointerBuilder PointerBuilder::imbue(ImbuedBuilderArena& newArena) const {
return PointerBuilder(newArena.imbue(segment), pointer);
}
// ======================================================================================= // =======================================================================================
// PointerReader // PointerReader
...@@ -2139,6 +2147,14 @@ bool PointerReader::isNull() const { ...@@ -2139,6 +2147,14 @@ bool PointerReader::isNull() const {
return pointer == nullptr || pointer->isNull(); return pointer == nullptr || pointer->isNull();
} }
kj::Maybe<Arena&> PointerReader::getArena() const {
return segment == nullptr ? nullptr : segment->getArena();
}
PointerReader PointerReader::imbue(ImbuedReaderArena& newArena) const {
return PointerReader(newArena.imbue(segment), pointer, nestingLimit);
}
// ======================================================================================= // =======================================================================================
// StructBuilder // StructBuilder
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
namespace capnp { namespace capnp {
class TypelessCapability; class ClientHook;
namespace _ { // private namespace _ { // private
...@@ -54,7 +54,10 @@ struct WirePointer; ...@@ -54,7 +54,10 @@ struct WirePointer;
struct WireHelpers; struct WireHelpers;
class SegmentReader; class SegmentReader;
class SegmentBuilder; class SegmentBuilder;
class Arena;
class BuilderArena; class BuilderArena;
class ImbuedReaderArena;
class ImbuedBuilderArena;
// ============================================================================= // =============================================================================
...@@ -284,7 +287,7 @@ public: ...@@ -284,7 +287,7 @@ public:
ListBuilder getList(FieldSize elementSize, const word* defaultValzue); ListBuilder getList(FieldSize elementSize, const word* defaultValzue);
ListBuilder getStructList(StructSize elementSize, const word* defaultValue); ListBuilder getStructList(StructSize elementSize, const word* defaultValue);
template <typename T> typename T::Builder getBlob(const void* defaultValue,ByteCount defaultSize); template <typename T> typename T::Builder getBlob(const void* defaultValue,ByteCount defaultSize);
kj::Own<TypelessCapability> getCapability(); kj::Own<ClientHook> getCapability();
// Get methods: Get the value. If it is null, initialize it to a copy of the default value. // Get methods: Get the value. If it is null, initialize it to a copy of the default value.
// The default value is encoded as an "unchecked message" for structs, lists, and objects, or a // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
// simple byte array for blobs. // simple byte array for blobs.
...@@ -300,7 +303,7 @@ public: ...@@ -300,7 +303,7 @@ public:
void setStruct(const StructReader& value); void setStruct(const StructReader& value);
void setList(const ListReader& value); void setList(const ListReader& value);
template <typename T> void setBlob(typename T::Reader value); template <typename T> void setBlob(typename T::Reader value);
void setCapability(kj::Own<TypelessCapability>&& cap); void setCapability(kj::Own<ClientHook>&& cap);
// Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding
// the existing object. // the existing object.
...@@ -321,6 +324,12 @@ public: ...@@ -321,6 +324,12 @@ public:
PointerReader asReader() const; PointerReader asReader() const;
BuilderArena& getArena() const;
// Get the arena containing this pointer.
PointerBuilder imbue(ImbuedBuilderArena& newArena) const;
// Imbue the pointer with a capability context, returning the imbued pointer.
private: private:
SegmentBuilder* segment; // Memory segment in which the pointer resides. SegmentBuilder* segment; // Memory segment in which the pointer resides.
WirePointer* pointer; // Pointer to the pointer. WirePointer* pointer; // Pointer to the pointer.
...@@ -342,7 +351,7 @@ public: ...@@ -342,7 +351,7 @@ public:
ListReader getList(FieldSize expectedElementSize, const word* defaultValue) const; ListReader getList(FieldSize expectedElementSize, const word* defaultValue) const;
template <typename T> template <typename T>
typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const; typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const;
kj::Own<TypelessCapability> getCapability(); kj::Own<ClientHook> getCapability();
// Get methods: Get the value. If it is null, return the default value instead. // Get methods: Get the value. If it is null, return the default value instead.
// The default value is encoded as an "unchecked message" for structs, lists, and objects, or a // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
// simple byte array for blobs. // simple byte array for blobs.
...@@ -352,6 +361,12 @@ public: ...@@ -352,6 +361,12 @@ public:
// word* can actually be passed to readUnchecked() to read the designated sub-object later. If // word* can actually be passed to readUnchecked() to read the designated sub-object later. If
// this isn't an unchecked message, throws an exception. // this isn't an unchecked message, throws an exception.
kj::Maybe<Arena&> getArena() const;
// Get the arena containing this pointer.
PointerReader imbue(ImbuedReaderArena& newArena) const;
// Imbue the pointer with a capability context, returning the imbued pointer.
private: private:
SegmentReader* segment; // Memory segment in which the pointer resides. SegmentReader* segment; // Memory segment in which the pointer resides.
const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer. const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer.
......
...@@ -63,6 +63,7 @@ struct ObjectPointer { ...@@ -63,6 +63,7 @@ struct ObjectPointer {
_::PointerReader reader; _::PointerReader reader;
friend struct ObjectPointer; friend struct ObjectPointer;
friend class Orphanage; friend class Orphanage;
friend class CapReaderContext;
}; };
class Builder { class Builder {
...@@ -143,6 +144,7 @@ struct ObjectPointer { ...@@ -143,6 +144,7 @@ struct ObjectPointer {
private: private:
_::PointerBuilder builder; _::PointerBuilder builder;
friend class CapBuilderContext;
}; };
}; };
...@@ -281,6 +283,38 @@ inline Orphan<T> Orphan<ObjectPointer>::releaseAs() { ...@@ -281,6 +283,38 @@ inline Orphan<T> Orphan<ObjectPointer>::releaseAs() {
return Orphan<T>(kj::mv(builder)); return Orphan<T>(kj::mv(builder));
} }
// Using ObjectPointer as the template type should work...
template <>
inline typename ObjectPointer::Reader ObjectPointer::Reader::getAs<ObjectPointer>() {
return *this;
}
template <>
inline typename ObjectPointer::Builder ObjectPointer::Builder::getAs<ObjectPointer>() {
return *this;
}
template <>
inline typename ObjectPointer::Builder ObjectPointer::Builder::initAs<ObjectPointer>() {
clear();
return *this;
}
template <>
inline void ObjectPointer::Builder::setAs<ObjectPointer>(ObjectPointer::Reader value) {
return builder.copyFrom(value.reader);
}
template <>
inline void ObjectPointer::Builder::adopt<ObjectPointer>(Orphan<ObjectPointer>&& orphan) {
builder.adopt(kj::mv(orphan.builder));
}
template <>
inline Orphan<ObjectPointer> ObjectPointer::Builder::disownAs<ObjectPointer>() {
return Orphan<ObjectPointer>(builder.disown());
}
template <>
inline Orphan<ObjectPointer> Orphan<ObjectPointer>::releaseAs() {
return kj::mv(*this);
}
} // namespace capnp } // namespace capnp
#endif // CAPNP_OBJECT_H_ #endif // CAPNP_OBJECT_H_
...@@ -950,7 +950,7 @@ using JoinAnswer = Object; ...@@ -950,7 +950,7 @@ using JoinAnswer = Object;
# #
# # Level 4 features ----------------------------------------------- # # Level 4 features -----------------------------------------------
# #
# newJoiner(count :UInt32): NewJoinerResponse; # newJoiner(count :UInt32) :NewJoinerResponse;
# # Prepare a new Join operation, which will eventually lead to forming a new direct connection # # Prepare a new Join operation, which will eventually lead to forming a new direct connection
# # to the host of the joined capability. `count` is the number of capabilities to join. # # to the host of the joined capability. `count` is the number of capabilities to join.
# #
...@@ -973,7 +973,7 @@ using JoinAnswer = Object; ...@@ -973,7 +973,7 @@ using JoinAnswer = Object;
# # message on it with the specified `ProvisionId` in order to receive the final capability. # # message on it with the specified `ProvisionId` in order to receive the final capability.
# } # }
# #
# acceptConnectionFromJoiner(parts: List(JoinKeyPart), paths :List(VatPath)) # acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath))
# :ConnectionAndProvisionId; # :ConnectionAndProvisionId;
# # Called on a joined capability's host to receive the connection from the joiner, once all # # Called on a joined capability's host to receive the connection from the joiner, once all
# # key parts have arrived. The caller should expect to receive an `Accept` message over the # # key parts have arrived. The caller should expect to receive an `Accept` message over the
...@@ -1002,17 +1002,17 @@ using JoinAnswer = Object; ...@@ -1002,17 +1002,17 @@ using JoinAnswer = Object;
# sendToTarget :RecipientId; # sendToTarget :RecipientId;
# } # }
# #
# connectToIntroduced(capId: ThirdPartyCapId) :ConnectionAndProvisionId; # connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId;
# # Given a ThirdPartyCapId received over this connection, connect to the third party. The # # Given a ThirdPartyCapId received over this connection, connect to the third party. The
# # caller should then send an `Accept` message over the new connection. # # caller should then send an `Accept` message over the new connection.
# #
# acceptIntroducedConnection(recipientId: RecipientId): Connection # acceptIntroducedConnection(recipientId :RecipientId) :Connection;
# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the # # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the
# # recipient to connect, and return the connection formed. Usually, the first message received # # recipient to connect, and return the connection formed. Usually, the first message received
# # on the new connection will be an `Accept` message. # # on the new connection will be an `Accept` message.
# } # }
# #
# sturct ConnectionAndProvisionId { # struct ConnectionAndProvisionId {
# # **(level 3)** # # **(level 3)**
# #
# connection :Connection; # connection :Connection;
......
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