Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
d07bf3b8
Commit
d07bf3b8
authored
Sep 29, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More capabilities core API WIP.
parent
398dac0d
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
644 additions
and
158 deletions
+644
-158
arena.c++
c++/src/capnp/arena.c++
+60
-6
arena.h
c++/src/capnp/arena.h
+16
-5
capability-context.c++
c++/src/capnp/capability-context.c++
+64
-0
capability-context.h
c++/src/capnp/capability-context.h
+158
-0
capability.c++
c++/src/capnp/capability.c++
+5
-6
capability.h
c++/src/capnp/capability.h
+267
-132
layout.c++
c++/src/capnp/layout.c++
+16
-0
layout.h
c++/src/capnp/layout.h
+19
-4
object.h
c++/src/capnp/object.h
+34
-0
rpc.capnp
c++/src/capnp/rpc.capnp
+5
-5
No files found.
c++/src/capnp/arena.c++
View file @
d07bf3b8
...
@@ -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
c++/src/capnp/arena.h
View file @
d07bf3b8
...
@@ -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
;
...
...
c++/src/capnp/capability-context.c++
0 → 100644
View file @
d07bf3b8
// 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
c++/src/capnp/capability-context.h
0 → 100644
View file @
d07bf3b8
// 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_
c++/src/capnp/capability.c++
View file @
d07bf3b8
...
@@ -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
=
Pipeline
Manager
::
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
c++/src/capnp/capability.h
View file @
d07bf3b8
...
@@ -29,221 +29,356 @@
...
@@ -29,221 +29,356 @@
namespace
capnp
{
namespace
capnp
{
template
<
typename
Answer
>
class
Response
;
template
<
typename
T
>
template
<
typename
T
>
class
RemotePromise
:
public
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>
,
public
T
::
Pipeline
{
class
RemotePromise
:
public
kj
::
Promise
<
Response
<
T
>>
,
public
T
::
Pipeline
{
// A Promise which supports pipelined calls. T is typically a struct type.
// A Promise which supports pipelined calls. T is typically a struct type. T must declare
// an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply
// multiply-inherits that type along with Promise<Response<T>>. T::Pipeline must be movable,
// but does not need to be copyable (i.e. just like Promise<T>).
//
// The promise is for an owned pointer so that the RPC system can allocate the MessageReader
// itself.
public
:
public
:
inline
RemotePromise
(
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>&&
promise
,
inline
RemotePromise
(
kj
::
Promise
<
Response
<
T
>>&&
promise
,
typename
T
::
Pipeline
&&
pipeline
)
typename
T
::
Pipeline
&&
pipeline
)
:
kj
::
Promise
<
Response
<
T
>>
(
kj
::
mv
(
promise
)),
:
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>>>
(
kj
::
mv
(
promise
)),
T
::
Pipeline
(
kj
::
mv
(
pipeline
))
{}
T
::
Pipeline
(
kj
::
mv
(
pipeline
))
{}
inline
RemotePromise
(
decltype
(
nullptr
))
inline
RemotePromise
(
decltype
(
nullptr
))
:
kj
::
Promise
<
kj
::
Own
<
ReaderFor
<
T
>
>>
(
nullptr
)
{}
:
kj
::
Promise
<
Response
<
T
>>
(
nullptr
)
{}
KJ_DISALLOW_COPY
(
RemotePromise
);
KJ_DISALLOW_COPY
(
RemotePromise
);
RemotePromise
(
RemotePromise
&&
other
)
=
default
;
RemotePromise
(
RemotePromise
&&
other
)
=
default
;
RemotePromise
&
operator
=
(
RemotePromise
&&
other
)
=
default
;
RemotePromise
&
operator
=
(
RemotePromise
&&
other
)
=
default
;
};
};
struct
Capability
{
// A capability without type-safe methods. Typed capability clients wrap `Client` and typed
// capability servers subclass `Server` to dispatch to the regular, typed methods.
class
Client
;
class
Server
;
};
// =======================================================================================
// =======================================================================================
class
Call
;
class
RequestHook
;
struct
CallResult
;
class
ResponseHook
;
class
PipelineHook
;
class
ClientHook
;
class
TypelessCapability
{
template
<
typename
Params
,
typename
Answer
>
// This is an internal type used to represent a live capability (or a promise for a capability).
class
Request
:
public
Params
::
Builder
{
// This class should not be used directly by applications; it is intended to be used by the
// A call that hasn't been sent yet. This class extends a Builder for the call's "Params"
// generated code wrappers.
// structure with a method send() that actually sends it.
//
// Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have
// a method `Request<FooParams, C> startFoo()` (as well as a convenience method
// `RemotePromise<C> foo(A::Reader a, B::Reader b)`).
public
:
public
:
virtual
kj
::
Own
<
Call
>
newCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
const
=
0
;
inline
Request
(
typename
Params
::
Builder
builder
,
kj
::
Own
<
RequestHook
>&&
hook
)
// Begin a new call to a method of this capability.
:
Params
::
Builder
(
builder
),
hook
(
kj
::
mv
(
hook
))
{}
virtual
kj
::
Own
<
TypelessCapability
>
addRef
()
const
=
0
;
RemotePromise
<
Answer
>
send
();
// Return a new reference-counted pointer to the same capability. (Reference counting can be
// Send the call and return a promise for the answer.
// implemented using a special Disposer, so that the returned pointer actually has the same
// identity as the original.)
virtual
kj
::
Promise
<
void
>
whenResolved
()
const
=
0
;
private
:
kj
::
Own
<
RequestHook
>
hook
;
};
template
<
typename
Answer
>
class
Response
:
public
Answer
::
Reader
{
// A completed call. This class extends a Reader for the call's answer structure. The Response
// is move-only -- once it goes out-of-scope, the underlying message will be freed.
public
:
inline
Response
(
typename
Answer
::
Reader
reader
,
kj
::
Own
<
ResponseHook
>&&
hook
)
:
Answer
::
Reader
(
reader
),
hook
(
kj
::
mv
(
hook
))
{}
private
:
kj
::
Own
<
ResponseHook
>
hook
;
template
<
typename
,
typename
>
friend
class
Request
;
};
class
Capability
::
Client
{
// Base type for capability clients.
public
:
explicit
Client
(
kj
::
Own
<
ClientHook
>&&
hook
);
Client
(
const
Client
&
other
);
Client
&
operator
=
(
const
Client
&
other
);
// Copies by reference counting. Warning: Refcounting is slow due to atomic ops. Try to only
// use move instead.
Client
(
Client
&&
)
=
default
;
Client
&
operator
=
(
Client
&&
)
=
default
;
// Move is fast.
kj
::
Promise
<
void
>
whenResolved
()
const
;
// If the capability is actually only a promise, the returned promise resolves once the
// If the capability is actually only a promise, the returned promise resolves once the
// capability itself has resolved to its final destination (or propagates the exception if
// capability itself has resolved to its final destination (or propagates the exception if
// the capability promise is rejected). This is mainly useful for error-checking in the case
// the capability promise is rejected). This is mainly useful for error-checking in the case
// where no calls are being made. There is no reason to wait for this before making calls; if
// where no calls are being made. There is no reason to wait for this before making calls; if
// the capability does not resolve, the call results will propagate the error.
// the capability does not resolve, the call results will propagate the error.
// TODO(soon): method implementing Join
// TODO(soon): method(s) for Join
private
:
kj
::
Own
<
ClientHook
>
hook
;
};
};
// =======================================================================================
// =======================================================================================
// Local capabilities
class
CallContextHook
;
template
<
typename
T
>
class
CallContext
:
public
kj
::
DisallowConstCopy
{
// Wrapper around TypelessCallContext with a specific return type.
class
Call
{
public
:
public
:
virtual
ObjectPointer
::
Builder
getRequest
()
=
0
;
explicit
CallContext
(
kj
::
Own
<
CallContextHook
>
hook
);
// Get the request object for this call, to be filled in before sending.
typename
T
::
Builder
getAnswer
();
typename
T
::
Builder
initAnswer
();
typename
T
::
Builder
initAnswer
(
uint
size
);
void
setAnswer
(
typename
T
::
Reader
value
);
void
adoptAnswer
(
Orphan
<
T
>&&
value
);
Orphanage
getAnswerOrphanage
();
// Manipulate the answer (return value) payload. The "Return" message (part of the RPC protocol)
// will typically be allocated the first time one of these is called. Some RPC systems may
// allocate these messages in a limited space (such as a shared memory segment), therefore the
// application should delay calling these as long as is convenient to do so (but don't delay
// if doing so would require extra copies later).
void
allowAsyncCancellation
(
bool
allow
=
true
);
// Indicate that it is OK for the RPC system to discard its Promise for this call's result if
// the caller cancels the call, thereby transitively canceling any asynchronous operations the
// call implementation was performing. This is not done by default because it could represent a
// security risk: applications must be carefully written to ensure that they do not end up in
// a bad state if an operation is canceled at an arbitrary point. However, for long-running
// method calls that hold significant resources, prompt cancellation is often useful.
//
// You can also switch back to disallowing cancellation by passing `false` as the argument.
//
// Keep in mind that asynchronous cancellation cannot occur while the method is synchronously
// executing on a local thread. The method must perform an asynchronous operation or call
// `EventLoop::current().runLater()` to yield control.
bool
isCanceled
();
// As an alternative to `allowAsyncCancellation()`, a server can call this to check for
// cancellation.
//
// Keep in mind that if the method is blocking the event loop, the cancel message won't be
// received, so it is necessary to use `EventLoop::current().runLater()` occasionally.
virtual
RemotePromise
<
CallResult
>
send
()
=
0
;
private
:
// Send the call and return a promise for the result.
kj
::
Own
<
CallContextHook
>
hook
;
};
};
class
CallRunner
{
class
Capability
::
Server
{
// Implements pipelined requests for a particular outstanding call.
// Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects
// will instead subclass a typed Server interface which will take care of implementing
// dispatchCall().
public
:
public
:
virtual
kj
::
Own
<
CallRunner
>
addRef
()
const
=
0
;
virtual
kj
::
Promise
<
void
>
dispatchCall
(
uint64_t
interfaceId
,
uint16_t
methodId
,
// Increment this object's reference count.
kj
::
Own
<
ObjectPointer
::
Reader
>
params
,
CallContext
<
ObjectPointer
>
context
)
=
0
;
// Call the given method. `params` is the input struct, and should be released as soon as it
// is no longer needed. `context` may be used to allocate the output struct and deal with
// cancellation.
// TODO(soon): Method which can optionally be overridden to implement Join when the object is
// a proxy.
};
Capability
::
Client
makeLocalClient
(
kj
::
Own
<
Capability
::
Server
>&&
server
);
// Make a client capability that wraps the given server capability.
// =======================================================================================
struct
PipelineOp
{
struct
PipelineOp
{
enum
Type
{
enum
Type
{
GET_POINTER_FIELD
GET_POINTER_FIELD
};
Type
type
;
// There may be other types in the future...
union
{
uint16_t
pointerIndex
;
};
};
};
virtual
kj
::
Own
<
TypelessCapability
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
Type
type
;
// Extract a promised Capability from the answer.
union
{
uint16_t
pointerIndex
;
// for GET_POINTER_FIELD
};
};
};
struct
CallResult
{
struct
TypelessAnswer
{
// Result of a call. Designed to be used as RemotePromise<CallResult>.
// Result of a call, before it has been type-wrapped. Designed to be used as
// RemotePromise<CallResult>.
typedef
ObjectPointer
::
Reader
Reader
;
typedef
ObjectPointer
::
Reader
Reader
;
// So RemotePromise<CallResult> resolves to Own<ObjectPointer::Reader>.
// So RemotePromise<CallResult> resolves to Own<ObjectPointer::Reader>.
class
Pipeline
{
class
Pipeline
{
public
:
public
:
inline
explicit
Pipeline
(
kj
::
Own
<
CallRunner
>&&
runner
)
:
runner
(
kj
::
mv
(
runner
))
{}
inline
explicit
Pipeline
(
kj
::
Own
<
PipelineHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
Pipeline
getPointerField
(
uint16_t
pointerIndex
)
const
;
Pipeline
getPointerField
(
uint16_t
pointerIndex
)
const
;
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// Return a new Promise representing a sub-object of the result. `pointerIndex` is the index
// of the sub-object within the pointer section of the result (the result must be a struct).
// of the sub-object within the pointer section of the result (the result must be a struct).
//
//
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
// TODO(kenton): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
//
Make `ops` into a Vector so that it can be extended without allocation in this case
.
//
Also make `ops` into a Vector to optimize this
.
inline
kj
::
Own
<
TypelessCapability
>
asCap
()
const
{
return
runner
->
getPipelinedCap
(
ops
);
}
Capability
::
Client
asCap
()
const
;
// Expect that the result is a capability and construct a pipelined version of it now.
// Expect that the result is a capability and construct a pipelined version of it now.
private
:
private
:
kj
::
Own
<
CallRunner
>
runner
;
kj
::
Own
<
PipelineHook
>
hook
;
kj
::
Array
<
CallRunner
::
PipelineOp
>
ops
;
kj
::
Array
<
PipelineOp
>
ops
;
inline
Pipeline
(
kj
::
Own
<
CallRunner
>&&
runner
,
kj
::
Array
<
CallRunner
::
PipelineOp
>&&
ops
)
inline
Pipeline
(
kj
::
Own
<
PipelineHook
>&&
hook
,
kj
::
Array
<
PipelineOp
>&&
ops
)
:
runner
(
kj
::
mv
(
runner
)),
ops
(
kj
::
mv
(
ops
))
{}
:
hook
(
kj
::
mv
(
hook
)),
ops
(
kj
::
mv
(
ops
))
{}
};
};
};
};
// =======================================================================================
// =======================================================================================
// Classes for imbuing message readers/builders with a capability context.
// Hook interfaces which must be implemented by the RPC system. Applications never call these
//
// directly; the RPC system implements them and the types defined earlier in this file wrap them.
// These classes are for use by RPC implementations. Application code need not know about them.
//
// TODO(kenton): Move these to a separate header.
//
// 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.
namespace
_
{
// private
class
ImbuedReaderArena
;
class
ImbuedBuilderArena
;
}
// namespace _ (private)
class
CapExtractorBase
{
// Non-template base class for CapExtractor<T>.
private
:
class
RequestHook
{
virtual
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
// Hook interface implemented by RPC system representing a request being built.
friend
class
_
::
ImbuedReaderArena
;
};
class
CapInjectorBase
{
public
:
// Non-template base class for CapInjector<T>.
virtual
ObjectPointer
::
Builder
getRequest
()
=
0
;
// Get the request object for this call, to be filled in before sending.
private
:
virtual
RemotePromise
<
TypelessAnswer
>
send
()
=
0
;
virtual
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
// Send the call and return a promise for the result.
friend
class
_
::
ImbuedBuilderArena
;
};
};
template
<
typename
CapDescriptor
>
class
ResponseHook
{
class
CapExtractor
:
public
CapExtractorBase
{
// Hook interface implemented by RPC system representing a response.
//
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
//
At present this class has no methods. It exists only for garbage collection -- when the
//
capabilities. (On the wire, an interface pointer actually points to a struct of this type.)
//
ResponseHook is destroyed, the answer can be freed.
public
:
public
:
virtual
kj
::
Own
<
TypelessCapability
>
extractCap
(
typename
CapDescriptor
::
Reader
descriptor
)
=
0
;
// Given the descriptor read off the wire, construct a live capability.
private
:
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
override
final
{
return
extractCap
(
typename
CapDescriptor
::
Reader
(
capDescriptor
));
}
};
};
template
<
typename
CapDescriptor
>
class
PipelineHook
{
class
CapInjector
:
public
CapInjectorBase
{
// Represents a currently-running call, and implements pipelined requests on its result.
// 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
:
public
:
virtual
void
injectCap
(
typename
CapDescriptor
::
Builder
descriptor
,
virtual
kj
::
Own
<
PipelineHook
>
addRef
()
const
=
0
;
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
// Increment this object's reference count.
// Fill in the given descriptor so that it describes the given capability.
private
:
virtual
kj
::
Own
<
ClientHook
>
getPipelinedCap
(
kj
::
ArrayPtr
<
const
PipelineOp
>
ops
)
const
=
0
;
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
// Extract a promised Capability from the answer.
kj
::
Own
<
TypelessCapability
>&&
cap
)
override
final
{
injectCap
(
typename
CapDescriptor
::
Builder
(
builder
.
initCapDescriptor
(
_
::
structSize
<
CapDescriptor
>
())),
kj
::
mv
(
cap
));
}
};
};
class
CapReaderContext
{
class
ClientHook
{
// 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.
public
:
public
:
CapReaderContext
(
Orphanage
arena
,
CapExtractorBase
&
extractor
);
virtual
Request
<
ObjectPointer
,
TypelessAnswer
>
newCall
(
~
CapReaderContext
()
noexcept
(
false
);
uint64_t
interfaceId
,
uint16_t
methodId
)
const
=
0
;
virtual
kj
::
Promise
<
void
>
whenResolved
()
const
=
0
;
ObjectPointer
::
Reader
imbue
(
ObjectPointer
::
Reader
base
);
private
:
void
*
arenaSpace
[
15
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
virtual
kj
::
Own
<
TypelessCapability
>
extractCapInternal
(
const
_
::
StructReader
&
capDescriptor
)
=
0
;
virtual
kj
::
Own
<
ClientHook
>
addRef
()
const
=
0
;
// Return a new reference to the same capability.
friend
class
_
::
ImbuedReaderArena
;
virtual
void
*
getBrand
()
const
=
0
;
// Returns a void* that identifies who made this client. This can be used by an RPC adapter to
// discover when a capability it needs to marshal is one that it created in the first place, and
// therefore it can transfer the capability without proxying.
};
};
class
Ca
pBuilderContext
{
class
Ca
llContextHook
{
//
Class which can "imbue" reader objects from some other message with a capability context,
//
Hook interface implemented by RPC system to manage a call on the server side. See
//
so that interface pointers found in the message can be set to point at live capabilities
.
//
CallContext<T>
.
public
:
public
:
CapBuilderContext
(
Orphanage
arena
,
CapInjectorBase
&
injector
);
virtual
ObjectPointer
::
Builder
getAnswer
()
=
0
;
~
CapBuilderContext
()
noexcept
(
false
);
virtual
void
allowAsyncCancellation
(
bool
allow
)
=
0
;
virtual
bool
isCanceled
()
=
0
;
ObjectPointer
::
Builder
imbue
(
ObjectPointer
::
Builder
base
);
};
private
:
void
*
arenaSpace
[
15
+
sizeof
(
kj
::
MutexGuarded
<
void
*>
)
/
sizeof
(
void
*
)];
virtual
void
injectCapInternal
(
_
::
PointerBuilder
builder
,
kj
::
Own
<
TypelessCapability
>&&
cap
)
=
0
;
// =======================================================================================
// Inline implementation details
template
<
typename
Params
,
typename
Answer
>
RemotePromise
<
Answer
>
Request
<
Params
,
Answer
>::
send
()
{
auto
typelessPromise
=
hook
->
send
();
// 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
<
TypelessAnswer
>>&>
(
typelessPromise
)
.
then
([](
Response
<
TypelessAnswer
>&&
response
)
->
Response
<
Answer
>
{
return
Response
<
Answer
>
(
response
.
getAs
<
Answer
>
(),
kj
::
mv
(
response
.
hook
));
});
// Wrap the typeless pipeline in a typed wrapper.
typename
Answer
::
Pipeline
typedPipeline
(
kj
::
mv
(
kj
::
implicitCast
<
TypelessAnswer
::
Pipeline
&>
(
typelessPromise
)));
return
RemotePromise
<
Answer
>
(
kj
::
mv
(
typedPromise
),
kj
::
mv
(
typedPipeline
));
}
inline
Capability
::
Client
TypelessAnswer
::
Pipeline
::
asCap
()
const
{
return
Capability
::
Client
(
hook
->
getPipelinedCap
(
ops
));
}
inline
Capability
::
Client
::
Client
(
kj
::
Own
<
ClientHook
>&&
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
inline
Capability
::
Client
::
Client
(
const
Client
&
other
)
:
hook
(
other
.
hook
->
addRef
())
{}
inline
Capability
::
Client
&
Capability
::
Client
::
operator
=
(
const
Client
&
other
)
{
hook
=
other
.
hook
->
addRef
();
return
*
this
;
}
inline
kj
::
Promise
<
void
>
Capability
::
Client
::
whenResolved
()
const
{
return
hook
->
whenResolved
();
}
friend
class
_
::
ImbuedBuilderArena
;
template
<
typename
T
>
};
inline
CallContext
<
T
>::
CallContext
(
kj
::
Own
<
CallContextHook
>
hook
)
:
hook
(
kj
::
mv
(
hook
))
{}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
getAnswer
()
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
getAs
<
T
>
();
}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
initAnswer
()
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
initAs
<
T
>
();
}
template
<
typename
T
>
inline
typename
T
::
Builder
CallContext
<
T
>::
initAnswer
(
uint
size
)
{
// `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
return
hook
->
getAnswer
().
template
initAs
<
T
>
(
size
);
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
setAnswer
(
typename
T
::
Reader
value
)
{
hook
->
getAnswer
().
set
(
value
);
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
adoptAnswer
(
Orphan
<
T
>&&
value
)
{
hook
->
getAnswer
().
adopt
(
kj
::
mv
(
value
));
}
template
<
typename
T
>
inline
Orphanage
CallContext
<
T
>::
getAnswerOrphanage
()
{
return
Orphanage
::
getForMessageContaining
(
hook
->
getAnswer
());
}
template
<
typename
T
>
inline
void
CallContext
<
T
>::
allowAsyncCancellation
(
bool
allow
)
{
hook
->
allowAsyncCancellation
(
allow
);
}
template
<
typename
T
>
inline
bool
CallContext
<
T
>::
isCanceled
()
{
return
hook
->
isCanceled
();
}
}
// namespace capnp
}
// namespace capnp
...
...
c++/src/capnp/layout.c++
View file @
d07bf3b8
...
@@ -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
...
...
c++/src/capnp/layout.h
View file @
d07bf3b8
...
@@ -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.
...
...
c++/src/capnp/object.h
View file @
d07bf3b8
...
@@ -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_
c++/src/capnp/rpc.capnp
View file @
d07bf3b8
...
@@ -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.
# }
# }
#
#
# st
ur
ct ConnectionAndProvisionId {
# st
ru
ct ConnectionAndProvisionId {
# # **(level 3)**
# # **(level 3)**
#
#
# connection :Connection;
# connection :Connection;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment