Commit b365bc9b authored by Kenton Varda's avatar Kenton Varda

Spin off libraries kj-async and capnp-rpc, so that people who don't want them…

Spin off libraries kj-async and capnp-rpc, so that people who don't want them can avoid their large footprint.
parent d122a3db
...@@ -172,7 +172,7 @@ includecapnp_HEADERS = \ ...@@ -172,7 +172,7 @@ includecapnp_HEADERS = \
src/capnp/rpc.capnp.h \ src/capnp/rpc.capnp.h \
src/capnp/rpc-twoparty.capnp.h src/capnp/rpc-twoparty.capnp.h
lib_LTLIBRARIES = libkj.la libcapnp.la libcapnp-rpc.la libcapnpc.la lib_LTLIBRARIES = libkj.la libkj-async.la libcapnp.la libcapnp-rpc.la libcapnpc.la
# -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333 # -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333
libkj_la_LIBADD = $(PTHREAD_LIBS) -lpthread libkj_la_LIBADD = $(PTHREAD_LIBS) -lpthread
...@@ -191,12 +191,17 @@ libkj_la_SOURCES= \ ...@@ -191,12 +191,17 @@ libkj_la_SOURCES= \
src/kj/io.c++ \ src/kj/io.c++ \
src/kj/mutex.c++ \ src/kj/mutex.c++ \
src/kj/thread.c++ \ src/kj/thread.c++ \
src/kj/async.c++ \
src/kj/async-unix.c++ \
src/kj/async-io.c++ \
src/kj/main.c++ \ src/kj/main.c++ \
src/kj/parse/char.c++ src/kj/parse/char.c++
# -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333
libkj_async_la_LIBADD = libkj.la $(PTHREAD_LIBS) -lpthread
libkj_async_la_LDFLAGS = -release $(VERSION) -no-undefined
libkj_async_la_SOURCES= \
src/kj/async.c++ \
src/kj/async-unix.c++ \
src/kj/async-io.c++
# -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333 # -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333
libcapnp_la_LIBADD = libkj.la $(PTHREAD_LIBS) -lpthread libcapnp_la_LIBADD = libkj.la $(PTHREAD_LIBS) -lpthread
libcapnp_la_LDFLAGS = -release $(VERSION) -no-undefined libcapnp_la_LDFLAGS = -release $(VERSION) -no-undefined
...@@ -209,21 +214,22 @@ libcapnp_la_SOURCES= \ ...@@ -209,21 +214,22 @@ libcapnp_la_SOURCES= \
src/capnp/list.c++ \ src/capnp/list.c++ \
src/capnp/object.c++ \ src/capnp/object.c++ \
src/capnp/message.c++ \ src/capnp/message.c++ \
src/capnp/capability.c++ \
src/capnp/capability-context.c++ \
src/capnp/schema.capnp.c++ \ src/capnp/schema.capnp.c++ \
src/capnp/schema.c++ \ src/capnp/schema.c++ \
src/capnp/schema-loader.c++ \ src/capnp/schema-loader.c++ \
src/capnp/dynamic.c++ \ src/capnp/dynamic.c++ \
src/capnp/stringify.c++ \ src/capnp/stringify.c++ \
src/capnp/serialize.c++ \ src/capnp/serialize.c++ \
src/capnp/serialize-async.c++ \
src/capnp/serialize-packed.c++ src/capnp/serialize-packed.c++
# -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333 # -lpthread is here to work around https://bugzilla.redhat.com/show_bug.cgi?id=661333
libcapnp_rpc_la_LIBADD = libcapnp.la libkj.la $(PTHREAD_LIBS) -lpthread libcapnp_rpc_la_LIBADD = libcapnp.la libkj-async.la libkj.la $(PTHREAD_LIBS) -lpthread
libcapnp_rpc_la_LDFLAGS = -release $(VERSION) -no-undefined libcapnp_rpc_la_LDFLAGS = -release $(VERSION) -no-undefined
libcapnp_rpc_la_SOURCES= \ libcapnp_rpc_la_SOURCES= \
src/capnp/serialize-async.c++ \
src/capnp/capability.c++ \
src/capnp/capability-context.c++ \
src/capnp/dynamic-capability.c++ \
src/capnp/rpc.c++ \ src/capnp/rpc.c++ \
src/capnp/rpc.capnp.c++ \ src/capnp/rpc.capnp.c++ \
src/capnp/rpc-twoparty.c++ \ src/capnp/rpc-twoparty.c++ \
...@@ -318,7 +324,7 @@ BUILT_SOURCES = $(test_capnpc_outputs) ...@@ -318,7 +324,7 @@ BUILT_SOURCES = $(test_capnpc_outputs)
check_PROGRAMS = capnp-test capnp-evolution-test check_PROGRAMS = capnp-test capnp-evolution-test
capnp_test_LDADD = gtest/lib/libgtest.la gtest/lib/libgtest_main.la \ capnp_test_LDADD = gtest/lib/libgtest.la gtest/lib/libgtest_main.la \
libcapnpc.la libcapnp-rpc.la libcapnp.la libkj.la libcapnpc.la libcapnp-rpc.la libcapnp.la libkj-async.la libkj.la
capnp_test_CPPFLAGS = -Igtest/include -I$(srcdir)/gtest/include capnp_test_CPPFLAGS = -Igtest/include -I$(srcdir)/gtest/include
capnp_test_SOURCES = \ capnp_test_SOURCES = \
src/kj/common-test.c++ \ src/kj/common-test.c++ \
......
...@@ -35,87 +35,6 @@ ...@@ -35,87 +35,6 @@
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
namespace {
class BrokenPipeline final: public PipelineHook, public kj::Refcounted {
public:
BrokenPipeline(const kj::Exception& exception): exception(exception) {}
kj::Own<const PipelineHook> addRef() const override {
return kj::addRef(*this);
}
kj::Own<const ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) const override;
private:
kj::Exception exception;
};
class BrokenRequest final: public RequestHook {
public:
BrokenRequest(const kj::Exception& exception, uint firstSegmentWordSize)
: exception(exception),
message(firstSegmentWordSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : firstSegmentWordSize) {}
RemotePromise<ObjectPointer> send() override {
return RemotePromise<ObjectPointer>(kj::cp(exception),
ObjectPointer::Pipeline(kj::refcounted<BrokenPipeline>(exception)));
}
kj::Exception exception;
LocalMessage message;
};
class BrokenClient final: public ClientHook, public kj::Refcounted {
public:
BrokenClient(const kj::Exception& exception): exception(exception) {}
BrokenClient(const char* description)
: exception(kj::Exception::Nature::PRECONDITION, kj::Exception::Durability::PERMANENT,
"", 0, kj::str(description)) {}
Request<ObjectPointer, ObjectPointer> newCall(
uint64_t interfaceId, uint16_t methodId, uint firstSegmentWordSize) const override {
auto hook = kj::heap<BrokenRequest>(exception, firstSegmentWordSize);
auto root = hook->message.getRoot();
return Request<ObjectPointer, ObjectPointer>(root, kj::mv(hook));
}
VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
kj::Own<CallContextHook>&& context) const override {
return VoidPromiseAndPipeline { kj::cp(exception), kj::heap<BrokenPipeline>(exception) };
}
kj::Maybe<kj::Promise<kj::Own<const ClientHook>>> whenMoreResolved() const override {
return kj::Promise<kj::Own<const ClientHook>>(kj::cp(exception));
}
kj::Own<const ClientHook> addRef() const override {
return kj::addRef(*this);
}
const void* getBrand() const override {
return nullptr;
}
private:
kj::Exception exception;
};
kj::Own<const ClientHook> BrokenPipeline::getPipelinedCap(
kj::ArrayPtr<const PipelineOp> ops) const {
return kj::heap<BrokenClient>(exception);
}
} // namespace
kj::Own<const ClientHook> newBrokenCap(const char* reason) {
return kj::refcounted<BrokenClient>(reason);
}
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason) {
return kj::refcounted<BrokenClient>(kj::mv(reason));
}
Arena::~Arena() noexcept(false) {} Arena::~Arena() noexcept(false) {}
BuilderArena::~BuilderArena() noexcept(false) {} BuilderArena::~BuilderArena() noexcept(false) {}
...@@ -183,12 +102,13 @@ void BasicReaderArena::reportReadLimitReached() { ...@@ -183,12 +102,13 @@ void BasicReaderArena::reportReadLimitReached() {
} }
} }
kj::Own<const ClientHook> BasicReaderArena::extractCap(const _::StructReader& capDescriptor) { kj::Maybe<kj::Own<const ClientHook>> BasicReaderArena::extractCap(
KJ_FAIL_REQUIRE("Message contained a capability but is not imbued with a capability context.") { const _::StructReader& capDescriptor) {
return newBrokenCap( return nullptr;
"Calling capability extracted from message that was not imbued with a capability " }
"context.");
} kj::Maybe<kj::Own<const ClientHook>> BasicReaderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
} }
// ======================================================================================= // =======================================================================================
...@@ -240,10 +160,15 @@ void ImbuedReaderArena::reportReadLimitReached() { ...@@ -240,10 +160,15 @@ void ImbuedReaderArena::reportReadLimitReached() {
return base->reportReadLimitReached(); return base->reportReadLimitReached();
} }
kj::Own<const ClientHook> ImbuedReaderArena::extractCap(const _::StructReader& capDescriptor) { kj::Maybe<kj::Own<const ClientHook>> ImbuedReaderArena::extractCap(
const _::StructReader& capDescriptor) {
return capExtractor->extractCapInternal(capDescriptor); return capExtractor->extractCapInternal(capDescriptor);
} }
kj::Maybe<kj::Own<const ClientHook>> ImbuedReaderArena::newBrokenCap(kj::StringPtr description) {
return capExtractor->newBrokenCapInternal(description);
}
// ======================================================================================= // =======================================================================================
BasicBuilderArena::BasicBuilderArena(MessageBuilder* message) BasicBuilderArena::BasicBuilderArena(MessageBuilder* message)
...@@ -383,8 +308,13 @@ void BasicBuilderArena::reportReadLimitReached() { ...@@ -383,8 +308,13 @@ void BasicBuilderArena::reportReadLimitReached() {
} }
} }
kj::Own<const ClientHook> BasicBuilderArena::extractCap(const _::StructReader& capDescriptor) { kj::Maybe<kj::Own<const ClientHook>> BasicBuilderArena::extractCap(
KJ_FAIL_REQUIRE("Message contains no capabilities."); const _::StructReader& capDescriptor) {
return nullptr;
}
kj::Maybe<kj::Own<const ClientHook>> BasicBuilderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
} }
OrphanBuilder BasicBuilderArena::injectCap(kj::Own<const ClientHook>&& cap) { OrphanBuilder BasicBuilderArena::injectCap(kj::Own<const ClientHook>&& cap) {
...@@ -450,10 +380,15 @@ void ImbuedBuilderArena::reportReadLimitReached() { ...@@ -450,10 +380,15 @@ void ImbuedBuilderArena::reportReadLimitReached() {
base->reportReadLimitReached(); base->reportReadLimitReached();
} }
kj::Own<const ClientHook> ImbuedBuilderArena::extractCap(const _::StructReader& capDescriptor) { kj::Maybe<kj::Own<const ClientHook>> ImbuedBuilderArena::extractCap(
const _::StructReader& capDescriptor) {
return capInjector->getInjectedCapInternal(capDescriptor); return capInjector->getInjectedCapInternal(capDescriptor);
} }
kj::Maybe<kj::Own<const ClientHook>> ImbuedBuilderArena::newBrokenCap(kj::StringPtr description) {
return capInjector->newBrokenCapInternal(description);
}
SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) { SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) {
return imbue(base->getSegment(id)); return imbue(base->getSegment(id));
} }
......
...@@ -58,12 +58,6 @@ class ReadLimiter; ...@@ -58,12 +58,6 @@ class ReadLimiter;
class Segment; class Segment;
typedef kj::Id<uint32_t, Segment> SegmentId; typedef kj::Id<uint32_t, Segment> SegmentId;
kj::Own<const ClientHook> newBrokenCap(const char* reason);
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason);
// Helper function that creates a capability which simply throws exceptions when called.
// Implemented in arena.c++ rather than capability.c++ because it is needed by layout.c++ and we
// don't want capability.c++ to be required by people not using caps.
class ReadLimiter { class ReadLimiter {
// Used to keep track of how much data has been processed from a message, and cut off further // Used to keep track of how much data has been processed from a message, and cut off further
// processing if and when a particular limit is reached. This is primarily intended to guard // processing if and when a particular limit is reached. This is primarily intended to guard
...@@ -192,9 +186,13 @@ public: ...@@ -192,9 +186,13 @@ public:
// the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller // the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller
// will need to continue with default values. // will need to continue with default values.
virtual kj::Own<const ClientHook> extractCap(const _::StructReader& capDescriptor) = 0; virtual kj::Maybe<kj::Own<const 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. Returns null if the message is not imbued with a capability context.
virtual kj::Maybe<kj::Own<const ClientHook>> newBrokenCap(kj::StringPtr description) = 0;
// Returns a capability which, when called, always throws an exception with the given description.
// Returns null if the message is not imbued with a capability context.
}; };
class BasicReaderArena final: public Arena { class BasicReaderArena final: public Arena {
...@@ -206,7 +204,8 @@ public: ...@@ -206,7 +204,8 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<const ClientHook> extractCap(const _::StructReader& capDescriptor); kj::Maybe<kj::Own<const ClientHook>> extractCap(const _::StructReader& capDescriptor);
kj::Maybe<kj::Own<const ClientHook>> newBrokenCap(kj::StringPtr description);
private: private:
MessageReader* message; MessageReader* message;
...@@ -230,7 +229,8 @@ public: ...@@ -230,7 +229,8 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<const ClientHook> extractCap(const _::StructReader& capDescriptor); kj::Maybe<kj::Own<const ClientHook>> extractCap(const _::StructReader& capDescriptor);
kj::Maybe<kj::Own<const ClientHook>> newBrokenCap(kj::StringPtr description);
private: private:
Arena* base; Arena* base;
...@@ -287,7 +287,8 @@ public: ...@@ -287,7 +287,8 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<const ClientHook> extractCap(const _::StructReader& capDescriptor); kj::Maybe<kj::Own<const ClientHook>> extractCap(const _::StructReader& capDescriptor);
kj::Maybe<kj::Own<const ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
...@@ -323,7 +324,8 @@ public: ...@@ -323,7 +324,8 @@ public:
// implements Arena ------------------------------------------------ // implements Arena ------------------------------------------------
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Own<const ClientHook> extractCap(const _::StructReader& capDescriptor); kj::Maybe<kj::Own<const ClientHook>> extractCap(const _::StructReader& capDescriptor);
kj::Maybe<kj::Own<const ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
......
...@@ -131,7 +131,7 @@ kj::Own<const ClientHook> LocalMessage::getInjectedCap( ...@@ -131,7 +131,7 @@ kj::Own<const ClientHook> LocalMessage::getInjectedCap(
auto lock = state.lockExclusive(); auto lock = state.lockExclusive();
KJ_ASSERT(descriptor.getIndex() < lock->caps.size(), KJ_ASSERT(descriptor.getIndex() < lock->caps.size(),
"Invalid capability descriptor in message.") { "Invalid capability descriptor in message.") {
return _::newBrokenCap("Calling capability from invalid descriptor."); return newBrokenCap("Calling capability from invalid descriptor.");
} }
return lock->caps[descriptor.getIndex()]->addRef(); return lock->caps[descriptor.getIndex()]->addRef();
} }
...@@ -145,4 +145,87 @@ void LocalMessage::dropCap(_::LocalCapDescriptor::Reader descriptor) const { ...@@ -145,4 +145,87 @@ void LocalMessage::dropCap(_::LocalCapDescriptor::Reader descriptor) const {
lock->caps[descriptor.getIndex()] = nullptr; lock->caps[descriptor.getIndex()] = nullptr;
} }
// =======================================================================================
namespace {
class BrokenPipeline final: public PipelineHook, public kj::Refcounted {
public:
BrokenPipeline(const kj::Exception& exception): exception(exception) {}
kj::Own<const PipelineHook> addRef() const override {
return kj::addRef(*this);
}
kj::Own<const ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) const override;
private:
kj::Exception exception;
};
class BrokenRequest final: public RequestHook {
public:
BrokenRequest(const kj::Exception& exception, uint firstSegmentWordSize)
: exception(exception),
message(firstSegmentWordSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : firstSegmentWordSize) {}
RemotePromise<ObjectPointer> send() override {
return RemotePromise<ObjectPointer>(kj::cp(exception),
ObjectPointer::Pipeline(kj::refcounted<BrokenPipeline>(exception)));
}
kj::Exception exception;
LocalMessage message;
};
class BrokenClient final: public ClientHook, public kj::Refcounted {
public:
BrokenClient(const kj::Exception& exception): exception(exception) {}
BrokenClient(const char* description)
: exception(kj::Exception::Nature::PRECONDITION, kj::Exception::Durability::PERMANENT,
"", 0, kj::str(description)) {}
Request<ObjectPointer, ObjectPointer> newCall(
uint64_t interfaceId, uint16_t methodId, uint firstSegmentWordSize) const override {
auto hook = kj::heap<BrokenRequest>(exception, firstSegmentWordSize);
auto root = hook->message.getRoot();
return Request<ObjectPointer, ObjectPointer>(root, kj::mv(hook));
}
VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
kj::Own<CallContextHook>&& context) const override {
return VoidPromiseAndPipeline { kj::cp(exception), kj::heap<BrokenPipeline>(exception) };
}
kj::Maybe<kj::Promise<kj::Own<const ClientHook>>> whenMoreResolved() const override {
return kj::Promise<kj::Own<const ClientHook>>(kj::cp(exception));
}
kj::Own<const ClientHook> addRef() const override {
return kj::addRef(*this);
}
const void* getBrand() const override {
return nullptr;
}
private:
kj::Exception exception;
};
kj::Own<const ClientHook> BrokenPipeline::getPipelinedCap(
kj::ArrayPtr<const PipelineOp> ops) const {
return kj::heap<BrokenClient>(exception);
}
} // namespace
kj::Own<const ClientHook> newBrokenCap(const char* reason) {
return kj::refcounted<BrokenClient>(reason);
}
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason) {
return kj::refcounted<BrokenClient>(kj::mv(reason));
}
} // namespace capnp } // namespace capnp
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <kj/mutex.h> #include <kj/mutex.h>
#include <kj/vector.h> #include <kj/vector.h>
namespace kj { class Exception; }
namespace capnp { namespace capnp {
class ClientHook; class ClientHook;
...@@ -58,6 +60,7 @@ class CapExtractorBase { ...@@ -58,6 +60,7 @@ class CapExtractorBase {
private: private:
virtual kj::Own<const ClientHook> extractCapInternal( virtual kj::Own<const ClientHook> extractCapInternal(
const _::StructReader& capDescriptor) const = 0; const _::StructReader& capDescriptor) const = 0;
virtual kj::Own<const ClientHook> newBrokenCapInternal(kj::StringPtr description) const = 0;
friend class _::ImbuedReaderArena; friend class _::ImbuedReaderArena;
}; };
...@@ -70,6 +73,7 @@ private: ...@@ -70,6 +73,7 @@ private:
virtual void dropCapInternal(const _::StructReader& capDescriptor) const = 0; virtual void dropCapInternal(const _::StructReader& capDescriptor) const = 0;
virtual kj::Own<const ClientHook> getInjectedCapInternal( virtual kj::Own<const ClientHook> getInjectedCapInternal(
const _::StructReader& capDescriptor) const = 0; const _::StructReader& capDescriptor) const = 0;
virtual kj::Own<const ClientHook> newBrokenCapInternal(kj::StringPtr description) const = 0;
friend class _::ImbuedBuilderArena; friend class _::ImbuedBuilderArena;
}; };
...@@ -85,9 +89,8 @@ public: ...@@ -85,9 +89,8 @@ public:
private: private:
kj::Own<const ClientHook> extractCapInternal( kj::Own<const ClientHook> extractCapInternal(
const _::StructReader& capDescriptor) const override final { const _::StructReader& capDescriptor) const override final;
return extractCap(typename CapDescriptor::Reader(capDescriptor)); kj::Own<const ClientHook> newBrokenCapInternal(kj::StringPtr description) const override final;
}
}; };
template <typename CapDescriptor> template <typename CapDescriptor>
...@@ -112,21 +115,11 @@ public: ...@@ -112,21 +115,11 @@ public:
private: private:
_::OrphanBuilder injectCapInternal(_::BuilderArena* arena, _::OrphanBuilder injectCapInternal(_::BuilderArena* arena,
kj::Own<const ClientHook>&& cap) const override final { kj::Own<const ClientHook>&& cap) const override final;
auto result = _::OrphanBuilder::initStruct(arena, _::structSize<CapDescriptor>()); void dropCapInternal(const _::StructReader& capDescriptor) const override final;
injectCap(typename CapDescriptor::Builder(result.asStruct(_::structSize<CapDescriptor>())),
kj::mv(cap));
return kj::mv(result);
}
void dropCapInternal(const _::StructReader& capDescriptor) const override final {
dropCap(typename CapDescriptor::Reader(capDescriptor));
}
kj::Own<const ClientHook> getInjectedCapInternal( kj::Own<const ClientHook> getInjectedCapInternal(
const _::StructReader& capDescriptor) const override final { const _::StructReader& capDescriptor) const override final;
return getInjectedCap(typename CapDescriptor::Reader(capDescriptor)); kj::Own<const ClientHook> newBrokenCapInternal(kj::StringPtr description) const override final;
}
}; };
// ------------------------------------------------------------------- // -------------------------------------------------------------------
...@@ -214,6 +207,57 @@ private: ...@@ -214,6 +207,57 @@ private:
void dropCap(_::LocalCapDescriptor::Reader descriptor) const override; void dropCap(_::LocalCapDescriptor::Reader descriptor) const override;
}; };
kj::Own<const ClientHook> newBrokenCap(const char* reason);
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason);
// Helper function that creates a capability which simply throws exceptions when called.
// =======================================================================================
// inline implementation details
template <typename CapDescriptor>
kj::Own<const ClientHook> CapExtractor<CapDescriptor>::extractCapInternal(
const _::StructReader& capDescriptor) const {
return extractCap(typename CapDescriptor::Reader(capDescriptor));
}
template <typename CapDescriptor>
kj::Own<const ClientHook> CapExtractor<CapDescriptor>::newBrokenCapInternal(
kj::StringPtr description) const {
// Notice that because this method was virtualized and then implemented in the template,
// we can call newBrokenCap which is only implemented in libcapnp-rpc even though arena.c++
// (in libcapnp proper) is the only caller of this method.
return newBrokenCap(description.cStr());
}
template <typename CapDescriptor>
_::OrphanBuilder CapInjector<CapDescriptor>::injectCapInternal(
_::BuilderArena* arena, kj::Own<const ClientHook>&& cap) const {
auto result = _::OrphanBuilder::initStruct(arena, _::structSize<CapDescriptor>());
injectCap(typename CapDescriptor::Builder(result.asStruct(_::structSize<CapDescriptor>())),
kj::mv(cap));
return kj::mv(result);
}
template <typename CapDescriptor>
void CapInjector<CapDescriptor>::dropCapInternal(const _::StructReader& capDescriptor) const {
dropCap(typename CapDescriptor::Reader(capDescriptor));
}
template <typename CapDescriptor>
kj::Own<const ClientHook> CapInjector<CapDescriptor>::getInjectedCapInternal(
const _::StructReader& capDescriptor) const {
return getInjectedCap(typename CapDescriptor::Reader(capDescriptor));
}
template <typename CapDescriptor>
kj::Own<const ClientHook> CapInjector<CapDescriptor>::newBrokenCapInternal(
kj::StringPtr description) const {
// Notice that because this method was virtualized and then implemented in the template,
// we can call newBrokenCap which is only implemented in libcapnp-rpc even though arena.c++
// (in libcapnp proper) is the only caller of this method.
return newBrokenCap(description.cStr());
}
} // namespace capnp } // namespace capnp
#endif // CAPNP_CAPABILITY_CONTEXT_H_ #endif // CAPNP_CAPABILITY_CONTEXT_H_
...@@ -73,14 +73,6 @@ kj::Promise<void> ClientHook::whenResolved() const { ...@@ -73,14 +73,6 @@ kj::Promise<void> ClientHook::whenResolved() const {
} }
} }
kj::Own<const ClientHook> newBrokenCap(const char* reason) {
return _::newBrokenCap(reason);
}
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason) {
return _::newBrokenCap(kj::mv(reason));
}
// ======================================================================================= // =======================================================================================
namespace { namespace {
......
...@@ -346,10 +346,6 @@ public: ...@@ -346,10 +346,6 @@ public:
virtual kj::Own<CallContextHook> addRef() = 0; virtual kj::Own<CallContextHook> addRef() = 0;
}; };
kj::Own<const ClientHook> newBrokenCap(const char* reason);
kj::Own<const ClientHook> newBrokenCap(kj::Exception&& reason);
// Helper function that creates a capability which simply throws exceptions when called.
// ======================================================================================= // =======================================================================================
// Extend PointerHelpers for interfaces // Extend PointerHelpers for interfaces
......
// 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.
// This file contains the parts of dynamic.h that live in capnp-rpc.so.
#include "dynamic.h"
#include <kj/debug.h>
namespace capnp {
DynamicCapability::Client DynamicCapability::Client::upcast(InterfaceSchema requestedSchema) const {
KJ_REQUIRE(schema.extends(requestedSchema), "Can't upcast to non-superclass.") {}
return DynamicCapability::Client(requestedSchema, hook->addRef());
}
Request<DynamicStruct, DynamicStruct> DynamicCapability::Client::newRequest(
InterfaceSchema::Method method, uint firstSegmentWordSize) const {
auto methodInterface = method.getContainingInterface();
KJ_REQUIRE(schema.extends(methodInterface), "Interface does not implement this method.");
auto proto = method.getProto();
auto paramType = methodInterface.getDependency(proto.getParamStructType()).asStruct();
auto resultType = methodInterface.getDependency(proto.getResultStructType()).asStruct();
auto typeless = hook->newCall(
methodInterface.getProto().getId(), method.getIndex(), firstSegmentWordSize);
return Request<DynamicStruct, DynamicStruct>(
typeless.getAs<DynamicStruct>(paramType), kj::mv(typeless.hook), resultType);
}
Request<DynamicStruct, DynamicStruct> DynamicCapability::Client::newRequest(
kj::StringPtr methodName, uint firstSegmentWordSize) const {
return newRequest(schema.getMethodByName(methodName), firstSegmentWordSize);
}
kj::Promise<void> DynamicCapability::Server::dispatchCall(
uint64_t interfaceId, uint16_t methodId,
CallContext<ObjectPointer, ObjectPointer> context) {
KJ_IF_MAYBE(interface, schema.findSuperclass(interfaceId)) {
auto methods = interface->getMethods();
if (methodId < methods.size()) {
auto method = methods[methodId];
auto proto = method.getProto();
return call(method, CallContext<DynamicStruct, DynamicStruct>(*context.hook,
interface->getDependency(proto.getParamStructType()).asStruct(),
interface->getDependency(proto.getResultStructType()).asStruct()));
} else {
return internalUnimplemented(
interface->getProto().getDisplayName().cStr(), interfaceId, methodId);
}
} else {
return internalUnimplemented(schema.getProto().getDisplayName().cStr(), interfaceId);
}
}
RemotePromise<DynamicStruct> Request<DynamicStruct, DynamicStruct>::send() {
auto typelessPromise = hook->send();
auto resultSchemaCopy = resultSchema;
// Convert the Promise to return the correct response type.
// Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
// Pipeline part of the RemotePromise.
auto typedPromise = kj::implicitCast<kj::Promise<Response<ObjectPointer>>&>(typelessPromise)
.thenInAnyThread([=](Response<ObjectPointer>&& response) -> Response<DynamicStruct> {
return Response<DynamicStruct>(response.getAs<DynamicStruct>(resultSchemaCopy),
kj::mv(response.hook));
});
// Wrap the typeless pipeline in a typed wrapper.
DynamicStruct::Pipeline typedPipeline(resultSchema,
kj::mv(kj::implicitCast<ObjectPointer::Pipeline&>(typelessPromise)));
return RemotePromise<DynamicStruct>(kj::mv(typedPromise), kj::mv(typedPipeline));
}
} // namespace capnp
...@@ -1373,75 +1373,6 @@ DynamicList::Reader DynamicList::Builder::asReader() const { ...@@ -1373,75 +1373,6 @@ DynamicList::Reader DynamicList::Builder::asReader() const {
// ======================================================================================= // =======================================================================================
DynamicCapability::Client DynamicCapability::Client::upcast(InterfaceSchema requestedSchema) const {
KJ_REQUIRE(schema.extends(requestedSchema), "Can't upcast to non-superclass.") {}
return DynamicCapability::Client(requestedSchema, hook->addRef());
}
Request<DynamicStruct, DynamicStruct> DynamicCapability::Client::newRequest(
InterfaceSchema::Method method, uint firstSegmentWordSize) const {
auto methodInterface = method.getContainingInterface();
KJ_REQUIRE(schema.extends(methodInterface), "Interface does not implement this method.");
auto proto = method.getProto();
auto paramType = methodInterface.getDependency(proto.getParamStructType()).asStruct();
auto resultType = methodInterface.getDependency(proto.getResultStructType()).asStruct();
auto typeless = hook->newCall(
methodInterface.getProto().getId(), method.getIndex(), firstSegmentWordSize);
return Request<DynamicStruct, DynamicStruct>(
typeless.getAs<DynamicStruct>(paramType), kj::mv(typeless.hook), resultType);
}
Request<DynamicStruct, DynamicStruct> DynamicCapability::Client::newRequest(
kj::StringPtr methodName, uint firstSegmentWordSize) const {
return newRequest(schema.getMethodByName(methodName), firstSegmentWordSize);
}
kj::Promise<void> DynamicCapability::Server::dispatchCall(
uint64_t interfaceId, uint16_t methodId,
CallContext<ObjectPointer, ObjectPointer> context) {
KJ_IF_MAYBE(interface, schema.findSuperclass(interfaceId)) {
auto methods = interface->getMethods();
if (methodId < methods.size()) {
auto method = methods[methodId];
auto proto = method.getProto();
return call(method, CallContext<DynamicStruct, DynamicStruct>(*context.hook,
interface->getDependency(proto.getParamStructType()).asStruct(),
interface->getDependency(proto.getResultStructType()).asStruct()));
} else {
return internalUnimplemented(
interface->getProto().getDisplayName().cStr(), interfaceId, methodId);
}
} else {
return internalUnimplemented(schema.getProto().getDisplayName().cStr(), interfaceId);
}
}
RemotePromise<DynamicStruct> Request<DynamicStruct, DynamicStruct>::send() {
auto typelessPromise = hook->send();
auto resultSchemaCopy = resultSchema;
// Convert the Promise to return the correct response type.
// Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
// Pipeline part of the RemotePromise.
auto typedPromise = kj::implicitCast<kj::Promise<Response<ObjectPointer>>&>(typelessPromise)
.thenInAnyThread([=](Response<ObjectPointer>&& response) -> Response<DynamicStruct> {
return Response<DynamicStruct>(response.getAs<DynamicStruct>(resultSchemaCopy),
kj::mv(response.hook));
});
// Wrap the typeless pipeline in a typed wrapper.
DynamicStruct::Pipeline typedPipeline(resultSchema,
kj::mv(kj::implicitCast<ObjectPointer::Pipeline&>(typelessPromise)));
return RemotePromise<DynamicStruct>(kj::mv(typedPromise), kj::mv(typedPipeline));
}
// =======================================================================================
DynamicValue::Reader::Reader(ConstSchema constant) { DynamicValue::Reader::Reader(ConstSchema constant) {
auto typeSchema = constant.getProto().getConst().getType(); auto typeSchema = constant.getProto().getConst().getType();
auto value = constant.getProto().getConst().getValue(); auto value = constant.getProto().getConst().getValue();
......
...@@ -1712,14 +1712,19 @@ struct WireHelpers { ...@@ -1712,14 +1712,19 @@ struct WireHelpers {
goto useDefault; goto useDefault;
} }
return setCapabilityPointer(dstSegment, dst, KJ_IF_MAYBE(cap, srcSegment->getArena()->extractCap(StructReader(
srcSegment->getArena()->extractCap(StructReader(
srcSegment, ptr, srcSegment, ptr,
reinterpret_cast<const WirePointer*>(ptr + src->structRef.dataSize.get()), reinterpret_cast<const WirePointer*>(ptr + src->structRef.dataSize.get()),
src->structRef.dataSize.get() * BITS_PER_WORD, src->structRef.dataSize.get() * BITS_PER_WORD,
src->structRef.ptrCount.get(), src->structRef.ptrCount.get(),
0 * BITS, nestingLimit - 1)), 0 * BITS, nestingLimit - 1))) {
orphanArena); return setCapabilityPointer(dstSegment, dst, kj::mv(*cap), orphanArena);
} else {
KJ_FAIL_REQUIRE("Message contained capability pointer but is not imbued with a "
"capability context.") {
goto useDefault;
}
}
} }
case WirePointer::FAR: case WirePointer::FAR:
...@@ -1799,12 +1804,23 @@ struct WireHelpers { ...@@ -1799,12 +1804,23 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(kj::Own<const ClientHook> readCapabilityPointer( static KJ_ALWAYS_INLINE(kj::Own<const ClientHook> readCapabilityPointer(
SegmentReader* segment, const WirePointer* ref, const word* refTarget, int nestingLimit)) { SegmentReader* segment, const WirePointer* ref, const word* refTarget, int nestingLimit)) {
kj::Maybe<kj::Own<const ClientHook>> maybeCap;
if (ref->isNull()) { if (ref->isNull()) {
return newBrokenCap("Calling null capability pointer."); maybeCap = segment->getArena()->newBrokenCap("Calling null capability pointer.");
} else { } else {
return segment->getArena()->extractCap(readStructOrCapDescPointer( maybeCap = segment->getArena()->extractCap(readStructOrCapDescPointer(
WirePointer::CAPABILITY, segment, ref, refTarget, nullptr, nestingLimit)); WirePointer::CAPABILITY, segment, ref, refTarget, nullptr, nestingLimit));
} }
KJ_IF_MAYBE(cap, maybeCap) {
return kj::mv(*cap);
} else {
// We can't really recover from this. Luckily, this is the caller's error, not the message
// sender's.
KJ_FAIL_REQUIRE("Tried to read a capability out of a message that doesn't have a "
"capability context.");
}
} }
static KJ_ALWAYS_INLINE(StructReader readStructOrCapDescPointer(WirePointer::Kind kind, static KJ_ALWAYS_INLINE(StructReader readStructOrCapDescPointer(WirePointer::Kind kind,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rpc.h" #include "rpc.h"
#include "capability-context.h"
#include "test-util.h" #include "test-util.h"
#include <kj/debug.h> #include <kj/debug.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rpc-twoparty.h" #include "rpc-twoparty.h"
#include "capability-context.h"
#include "test-util.h" #include "test-util.h"
#include <kj/async-unix.h> #include <kj/async-unix.h>
#include <kj/debug.h> #include <kj/debug.h>
......
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