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
c3b381ee
Commit
c3b381ee
authored
Jul 08, 2015
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add framework for capability membranes.
parent
cbd18b28
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
482 additions
and
4 deletions
+482
-4
Makefile.am
c++/Makefile.am
+3
-0
CMakeLists.txt
c++/src/capnp/CMakeLists.txt
+3
-0
capability.h
c++/src/capnp/capability.h
+6
-0
layout.c++
c++/src/capnp/layout.c++
+4
-0
layout.h
c++/src/capnp/layout.h
+3
-0
membrane-test.c++
c++/src/capnp/membrane-test.c++
+286
-0
membrane.c++
c++/src/capnp/membrane.c++
+0
-0
membrane.h
c++/src/capnp/membrane.h
+151
-0
rpc-twoparty.c++
c++/src/capnp/rpc-twoparty.c++
+6
-3
rpc-twoparty.h
c++/src/capnp/rpc-twoparty.h
+4
-1
test.capnp
c++/src/capnp/test.capnp
+16
-0
No files found.
c++/Makefile.am
View file @
c3b381ee
...
...
@@ -161,6 +161,7 @@ includecapnp_HEADERS = \
src/capnp/any.h
\
src/capnp/message.h
\
src/capnp/capability.h
\
src/capnp/membrane.h
\
src/capnp/schema.capnp.h
\
src/capnp/schema-lite.h
\
src/capnp/schema.h
\
...
...
@@ -255,6 +256,7 @@ libcapnp_rpc_la_LDFLAGS = -release $(SO_VERSION) -no-undefined
libcapnp_rpc_la_SOURCES
=
\
src/capnp/serialize-async.c++
\
src/capnp/capability.c++
\
src/capnp/membrane.c++
\
src/capnp/dynamic-capability.c++
\
src/capnp/rpc.c++
\
src/capnp/rpc.capnp.c++
\
...
...
@@ -373,6 +375,7 @@ heavy_tests = \
src/kj/parse/char-test.c++
\
src/kj/std/iostream-test.c++
\
src/capnp/capability-test.c++
\
src/capnp/membrane-test.c++
\
src/capnp/schema-test.c++
\
src/capnp/schema-loader-test.c++
\
src/capnp/schema-parser-test.c++
\
...
...
c++/src/capnp/CMakeLists.txt
View file @
c3b381ee
...
...
@@ -36,6 +36,7 @@ set(capnp_headers
any.h
message.h
capability.h
membrane.h
dynamic.h
schema.h
schema.capnp.h
...
...
@@ -62,6 +63,7 @@ install(FILES ${capnp_headers} ${capnp_schemas} DESTINATION "${INCLUDE_INSTALL_D
set
(
capnp-rpc_sources
serialize-async.c++
capability.c++
membrane.c++
dynamic-capability.c++
rpc.c++
rpc.capnp.c++
...
...
@@ -209,6 +211,7 @@ if(BUILD_TESTING)
add_executable
(
capnp-heavy-tests
endian-reverse-test.c++
capability-test.c++
membrane-test.c++
schema-test.c++
schema-loader-test.c++
schema-parser-test.c++
...
...
c++/src/capnp/capability.h
View file @
c3b381ee
...
...
@@ -139,6 +139,7 @@ private:
template
<
typename
,
typename
>
friend
class
Request
;
friend
class
ResponseHook
;
};
class
Capability
::
Client
{
...
...
@@ -488,6 +489,11 @@ class ResponseHook {
public
:
virtual
~
ResponseHook
()
noexcept
(
false
);
// Just here to make sure the type is dynamic.
template
<
typename
T
>
inline
static
kj
::
Own
<
ResponseHook
>
from
(
Response
<
T
>&&
response
)
{
return
kj
::
mv
(
response
.
hook
);
}
};
// class PipelineHook is declared in any.h because it is needed there.
...
...
c++/src/capnp/layout.c++
View file @
c3b381ee
...
...
@@ -2440,6 +2440,10 @@ kj::Maybe<Arena&> PointerReader::getArena() const {
return
segment
==
nullptr
?
nullptr
:
segment
->
getArena
();
}
CapTableReader
*
PointerReader
::
getCapTable
()
{
return
capTable
;
}
PointerReader
PointerReader
::
imbue
(
CapTableReader
*
capTable
)
const
{
auto
result
=
*
this
;
result
.
capTable
=
capTable
;
...
...
c++/src/capnp/layout.h
View file @
c3b381ee
...
...
@@ -411,6 +411,9 @@ public:
kj
::
Maybe
<
Arena
&>
getArena
()
const
;
// Get the arena containing this pointer.
CapTableReader
*
getCapTable
();
// Gets the capability context in which this object is operating.
PointerReader
imbue
(
CapTableReader
*
capTable
)
const
;
// Return a copy of this reader except using the given capability context.
...
...
c++/src/capnp/membrane-test.c++
0 → 100644
View file @
c3b381ee
// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "membrane.h"
#include <kj/test.h>
#include "test-util.h"
#include <kj/function.h>
#include <kj/async-io.h>
#include "rpc-twoparty.h"
namespace
capnp
{
namespace
_
{
namespace
{
using
Thing
=
test
::
TestMembrane
::
Thing
;
class
ThingImpl
:
public
Thing
::
Server
{
public
:
ThingImpl
(
kj
::
StringPtr
text
)
:
text
(
text
)
{}
protected
:
kj
::
Promise
<
void
>
passThrough
(
PassThroughContext
context
)
override
{
context
.
getResults
().
setText
(
text
);
return
kj
::
READY_NOW
;
}
kj
::
Promise
<
void
>
intercept
(
InterceptContext
context
)
override
{
context
.
getResults
().
setText
(
text
);
return
kj
::
READY_NOW
;
}
private
:
kj
::
StringPtr
text
;
};
class
TestMembraneImpl
:
public
test
::
TestMembrane
::
Server
{
protected
:
kj
::
Promise
<
void
>
makeThing
(
MakeThingContext
context
)
override
{
context
.
getResults
().
setThing
(
kj
::
heap
<
ThingImpl
>
(
"inside"
));
return
kj
::
READY_NOW
;
}
kj
::
Promise
<
void
>
callPassThrough
(
CallPassThroughContext
context
)
override
{
auto
params
=
context
.
getParams
();
auto
req
=
params
.
getThing
().
passThroughRequest
();
if
(
params
.
getTailCall
())
{
return
context
.
tailCall
(
kj
::
mv
(
req
));
}
else
{
return
req
.
send
().
then
([
context
](
Response
<
test
::
TestMembrane
::
Result
>&&
result
)
mutable
{
context
.
setResults
(
result
);
});
}
}
kj
::
Promise
<
void
>
callIntercept
(
CallInterceptContext
context
)
override
{
auto
params
=
context
.
getParams
();
auto
req
=
params
.
getThing
().
interceptRequest
();
if
(
params
.
getTailCall
())
{
return
context
.
tailCall
(
kj
::
mv
(
req
));
}
else
{
return
req
.
send
().
then
([
context
](
Response
<
test
::
TestMembrane
::
Result
>&&
result
)
mutable
{
context
.
setResults
(
result
);
});
}
}
kj
::
Promise
<
void
>
loopback
(
LoopbackContext
context
)
override
{
context
.
getResults
().
setThing
(
context
.
getParams
().
getThing
());
return
kj
::
READY_NOW
;
}
};
class
MembranePolicyImpl
:
public
MembranePolicy
,
public
kj
::
Refcounted
{
public
:
kj
::
Maybe
<
Capability
::
Client
>
inboundCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
override
{
if
(
interfaceId
==
capnp
::
typeId
<
Thing
>
()
&&
methodId
==
1
)
{
return
Capability
::
Client
(
kj
::
heap
<
ThingImpl
>
(
"inbound"
));
}
else
{
return
nullptr
;
}
}
kj
::
Maybe
<
Capability
::
Client
>
outboundCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
override
{
if
(
interfaceId
==
capnp
::
typeId
<
Thing
>
()
&&
methodId
==
1
)
{
return
Capability
::
Client
(
kj
::
heap
<
ThingImpl
>
(
"outbound"
));
}
else
{
return
nullptr
;
}
}
kj
::
Own
<
MembranePolicy
>
addRef
()
override
{
return
kj
::
addRef
(
*
this
);
}
};
void
testThingImpl
(
kj
::
WaitScope
&
waitScope
,
test
::
TestMembrane
::
Client
membraned
,
kj
::
Function
<
Thing
::
Client
()
>
makeThing
,
kj
::
StringPtr
localPassThrough
,
kj
::
StringPtr
localIntercept
,
kj
::
StringPtr
remotePassThrough
,
kj
::
StringPtr
remoteIntercept
)
{
KJ_EXPECT
(
makeThing
().
passThroughRequest
().
send
().
wait
(
waitScope
).
getText
()
==
localPassThrough
);
KJ_EXPECT
(
makeThing
().
interceptRequest
().
send
().
wait
(
waitScope
).
getText
()
==
localIntercept
);
{
auto
req
=
membraned
.
callPassThroughRequest
();
req
.
setThing
(
makeThing
());
req
.
setTailCall
(
false
);
KJ_EXPECT
(
req
.
send
().
wait
(
waitScope
).
getText
()
==
remotePassThrough
);
}
{
auto
req
=
membraned
.
callInterceptRequest
();
req
.
setThing
(
makeThing
());
req
.
setTailCall
(
false
);
KJ_EXPECT
(
req
.
send
().
wait
(
waitScope
).
getText
()
==
remoteIntercept
);
}
{
auto
req
=
membraned
.
callPassThroughRequest
();
req
.
setThing
(
makeThing
());
req
.
setTailCall
(
true
);
KJ_EXPECT
(
req
.
send
().
wait
(
waitScope
).
getText
()
==
remotePassThrough
);
}
{
auto
req
=
membraned
.
callInterceptRequest
();
req
.
setThing
(
makeThing
());
req
.
setTailCall
(
true
);
KJ_EXPECT
(
req
.
send
().
wait
(
waitScope
).
getText
()
==
remoteIntercept
);
}
}
struct
TestEnv
{
kj
::
EventLoop
loop
;
kj
::
WaitScope
waitScope
;
test
::
TestMembrane
::
Client
membraned
;
TestEnv
()
:
waitScope
(
loop
),
membraned
(
membrane
(
kj
::
heap
<
TestMembraneImpl
>
(),
kj
::
refcounted
<
MembranePolicyImpl
>
()))
{}
void
testThing
(
kj
::
Function
<
Thing
::
Client
()
>
makeThing
,
kj
::
StringPtr
localPassThrough
,
kj
::
StringPtr
localIntercept
,
kj
::
StringPtr
remotePassThrough
,
kj
::
StringPtr
remoteIntercept
)
{
testThingImpl
(
waitScope
,
membraned
,
kj
::
mv
(
makeThing
),
localPassThrough
,
localIntercept
,
remotePassThrough
,
remoteIntercept
);
}
};
KJ_TEST
(
"call local object inside membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
return
env
.
membraned
.
makeThingRequest
().
send
().
wait
(
env
.
waitScope
).
getThing
();
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call local promise inside membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
return
env
.
membraned
.
makeThingRequest
().
send
().
getThing
();
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call local resolved promise inside membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
auto
thing
=
env
.
membraned
.
makeThingRequest
().
send
().
getThing
();
thing
.
whenResolved
().
wait
(
env
.
waitScope
);
return
thing
;
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call local object outside membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
return
kj
::
heap
<
ThingImpl
>
(
"outside"
);
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
KJ_TEST
(
"call local capability that has passed into and back out of membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
auto
req
=
env
.
membraned
.
loopbackRequest
();
req
.
setThing
(
kj
::
heap
<
ThingImpl
>
(
"outside"
));
return
req
.
send
().
wait
(
env
.
waitScope
).
getThing
();
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
KJ_TEST
(
"call local promise pointing into membrane that eventually resolves to outside"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
auto
req
=
env
.
membraned
.
loopbackRequest
();
req
.
setThing
(
kj
::
heap
<
ThingImpl
>
(
"outside"
));
return
req
.
send
().
getThing
();
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
struct
TestRpcEnv
{
kj
::
AsyncIoContext
io
;
kj
::
TwoWayPipe
pipe
;
TwoPartyClient
client
;
TwoPartyClient
server
;
test
::
TestMembrane
::
Client
membraned
;
TestRpcEnv
()
:
io
(
kj
::
setupAsyncIo
()),
pipe
(
io
.
provider
->
newTwoWayPipe
()),
client
(
*
pipe
.
ends
[
0
]),
server
(
*
pipe
.
ends
[
1
],
membrane
(
kj
::
heap
<
TestMembraneImpl
>
(),
kj
::
refcounted
<
MembranePolicyImpl
>
()),
rpc
::
twoparty
::
Side
::
SERVER
),
membraned
(
client
.
bootstrap
().
castAs
<
test
::
TestMembrane
>
())
{}
void
testThing
(
kj
::
Function
<
Thing
::
Client
()
>
makeThing
,
kj
::
StringPtr
localPassThrough
,
kj
::
StringPtr
localIntercept
,
kj
::
StringPtr
remotePassThrough
,
kj
::
StringPtr
remoteIntercept
)
{
testThingImpl
(
io
.
waitScope
,
membraned
,
kj
::
mv
(
makeThing
),
localPassThrough
,
localIntercept
,
remotePassThrough
,
remoteIntercept
);
}
};
KJ_TEST
(
"call remote object inside membrane"
)
{
TestRpcEnv
env
;
env
.
testThing
([
&
]()
{
return
env
.
membraned
.
makeThingRequest
().
send
().
wait
(
env
.
io
.
waitScope
).
getThing
();
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call remote promise inside membrane"
)
{
TestRpcEnv
env
;
env
.
testThing
([
&
]()
{
return
env
.
membraned
.
makeThingRequest
().
send
().
getThing
();
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call remote resolved promise inside membrane"
)
{
TestEnv
env
;
env
.
testThing
([
&
]()
{
auto
thing
=
env
.
membraned
.
makeThingRequest
().
send
().
getThing
();
thing
.
whenResolved
().
wait
(
env
.
waitScope
);
return
thing
;
},
"inside"
,
"inbound"
,
"inside"
,
"inside"
);
}
KJ_TEST
(
"call remote object outside membrane"
)
{
TestRpcEnv
env
;
env
.
testThing
([
&
]()
{
return
kj
::
heap
<
ThingImpl
>
(
"outside"
);
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
KJ_TEST
(
"call remote capability that has passed into and back out of membrane"
)
{
TestRpcEnv
env
;
env
.
testThing
([
&
]()
{
auto
req
=
env
.
membraned
.
loopbackRequest
();
req
.
setThing
(
kj
::
heap
<
ThingImpl
>
(
"outside"
));
return
req
.
send
().
wait
(
env
.
io
.
waitScope
).
getThing
();
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
KJ_TEST
(
"call remote promise pointing into membrane that eventually resolves to outside"
)
{
TestRpcEnv
env
;
env
.
testThing
([
&
]()
{
auto
req
=
env
.
membraned
.
loopbackRequest
();
req
.
setThing
(
kj
::
heap
<
ThingImpl
>
(
"outside"
));
return
req
.
send
().
getThing
();
},
"outside"
,
"outside"
,
"outside"
,
"outbound"
);
}
}
// namespace
}
// namespace _
}
// namespace capnp
c++/src/capnp/membrane.c++
0 → 100644
View file @
c3b381ee
This diff is collapsed.
Click to expand it.
c++/src/capnp/membrane.h
0 → 100644
View file @
c3b381ee
// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CAPNP_MEMBRANE_H_
#define CAPNP_MEMBRANE_H_
// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards
// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a
// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely
// introducing new objects.
//
// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability
// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this
// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice
// indicates it should be revoked, after which all calls through the wrapper will throw exceptions.
// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new
// capability in that call, or if Carol returns a capability to Bob in the response to a call, then
// the two are now able to communicate using this new capability, which Alice cannot revoke. In
// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which
// recursively wraps all objects that pass through it in either direction. Thus, all connections
// formed between Bob and Carol (originating from Alice's original introduction) can be revoked
// together by revoking the membrane.
//
// Note that when a capability is passed into a membrane and then passed back out, the result is
// the original capability, not a double-membraned capability. This means that in our revocation
// example, if Bob uses his capability to Carol to obtain another capability from her, then send
// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to
// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use
// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then
// passed back can be recognized as the original capability.
//
// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html
#include "capability.h"
namespace
capnp
{
class
MembranePolicy
{
// Applications may implement this interface to define a membrane policy, which allows some
// calls crossing the membrane to be blocked or redirected.
public
:
virtual
kj
::
Maybe
<
Capability
::
Client
>
inboundCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
=
0
;
// Given an inbound call (a call originating "outside" the membrane destined for an object
// "inside" the membrane), decides what to do with it. The policy may:
//
// - Return null to indicate that the call should proceed to the destination. All capabilities
// in the parameters or result will be properly wrapped in the same membrane.
// - Return a capability to have the call redirected to that capability. Note that the redirect
// capability will be treated as outside the membrane, so the params and results will not be
// auto-wrapped; however, the callee can easily wrap the returned capability in the membrane
// itself before returning to achieve this effect.
// - Throw an exception to cause the call to fail with that exception.
virtual
kj
::
Maybe
<
Capability
::
Client
>
outboundCall
(
uint64_t
interfaceId
,
uint16_t
methodId
)
=
0
;
// Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating
// outside.
//
// Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases
// that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would
// redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run
// into inconsistent behavion when a promise is returned across a membrane, and that promise
// later resolves to a capability on the other side of the membrane: calls on the promise
// will enter and then exit the membrane, but calls on the eventual resolution will not cross
// the membrane at all, so it is important that these two cases behave the same.
virtual
kj
::
Own
<
MembranePolicy
>
addRef
()
=
0
;
// Return a new owned pointer to the same policy.
//
// Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement
// `addRef()` as `return kj::addRef(*this);`.
//
// Note that the membraning system considers two membranes created with the same MembranePolicy
// object actually to be the *same* membrane. This is relevant when an object passes into the
// membrane and then back out (or out and then back in): instead of double-wrapping the object,
// the wrapping will be removed.
};
Capability
::
Client
membrane
(
Capability
::
Client
inner
,
kj
::
Own
<
MembranePolicy
>
policy
);
// Wrap `inner` in a membrane specified by `filter`. `inner` is considered "inside" the membrane,
// while the returned capability should only be called from outside the membrane.
Capability
::
Client
reverseMembrane
(
Capability
::
Client
outer
,
kj
::
Own
<
MembranePolicy
>
policy
);
// Like `membrane` but treat the input capability as "outside" the membrane, and return a
// capability appropriate for use inside.
//
// Applications typically won't use this directly; the membraning code automatically sets up
// reverse membranes where needed.
template
<
typename
ClientType
>
ClientType
membrane
(
ClientType
inner
,
kj
::
Own
<
MembranePolicy
>
policy
);
template
<
typename
ClientType
>
ClientType
reverseMembrane
(
ClientType
inner
,
kj
::
Own
<
MembranePolicy
>
policy
);
// Convenience templates which return the same interface type as the input.
template
<
typename
ServerType
>
typename
ServerType
::
Serves
::
Client
membrane
(
kj
::
Own
<
ServerType
>
inner
,
kj
::
Own
<
MembranePolicy
>
policy
);
template
<
typename
ServerType
>
typename
ServerType
::
Serves
::
Client
reverseMembrane
(
kj
::
Own
<
ServerType
>
inner
,
kj
::
Own
<
MembranePolicy
>
policy
);
// Convenience templates which input a capability server type and return the appropriate client
// type.
// =======================================================================================
// inline implementation details
template
<
typename
ClientType
>
ClientType
membrane
(
ClientType
inner
,
kj
::
Own
<
MembranePolicy
>
policy
)
{
return
membrane
(
Capability
::
Client
(
kj
::
mv
(
inner
)),
kj
::
mv
(
policy
))
.
castAs
<
typename
ClientType
::
Calls
>
();
}
template
<
typename
ClientType
>
ClientType
reverseMembrane
(
ClientType
inner
,
kj
::
Own
<
MembranePolicy
>
policy
)
{
return
reverseMembrane
(
Capability
::
Client
(
kj
::
mv
(
inner
)),
kj
::
mv
(
policy
))
.
castAs
<
typename
ClientType
::
Calls
>
();
}
template
<
typename
ServerType
>
typename
ServerType
::
Serves
::
Client
membrane
(
kj
::
Own
<
ServerType
>
inner
,
kj
::
Own
<
MembranePolicy
>
policy
)
{
return
membrane
(
Capability
::
Client
(
kj
::
mv
(
inner
)),
kj
::
mv
(
policy
))
.
castAs
<
typename
ServerType
::
Serves
::
Client
>
();
}
template
<
typename
ServerType
>
typename
ServerType
::
Serves
::
Client
reverseMembrane
(
kj
::
Own
<
ServerType
>
inner
,
kj
::
Own
<
MembranePolicy
>
policy
)
{
return
reverseMembrane
(
Capability
::
Client
(
kj
::
mv
(
inner
)),
kj
::
mv
(
policy
))
.
castAs
<
typename
ServerType
::
Serves
::
Client
>
();
}
}
// namespace capnp
#endif // CAPNP_MEMBRANE_H_
c++/src/capnp/rpc-twoparty.c++
View file @
c3b381ee
...
...
@@ -182,14 +182,17 @@ TwoPartyClient::TwoPartyClient(kj::AsyncIoStream& connection)
TwoPartyClient
::
TwoPartyClient
(
kj
::
AsyncIoStream
&
connection
,
Capability
::
Client
bootstrapInterface
)
:
network
(
connection
,
rpc
::
twoparty
::
Side
::
CLIENT
),
Capability
::
Client
bootstrapInterface
,
rpc
::
twoparty
::
Side
side
)
:
network
(
connection
,
side
),
rpcSystem
(
network
,
bootstrapInterface
)
{}
Capability
::
Client
TwoPartyClient
::
bootstrap
()
{
MallocMessageBuilder
message
(
4
);
auto
vatId
=
message
.
getRoot
<
rpc
::
twoparty
::
VatId
>
();
vatId
.
setSide
(
rpc
::
twoparty
::
Side
::
SERVER
);
vatId
.
setSide
(
network
.
getSide
()
==
rpc
::
twoparty
::
Side
::
CLIENT
?
rpc
::
twoparty
::
Side
::
SERVER
:
rpc
::
twoparty
::
Side
::
CLIENT
);
return
rpcSystem
.
bootstrap
(
vatId
);
}
...
...
c++/src/capnp/rpc-twoparty.h
View file @
c3b381ee
...
...
@@ -59,6 +59,8 @@ public:
kj
::
Promise
<
void
>
onDisconnect
()
{
return
disconnectPromise
.
addBranch
();
}
// Returns a promise that resolves when the peer disconnects.
rpc
::
twoparty
::
Side
getSide
()
{
return
side
;
}
// implements VatNetwork -----------------------------------------------------
kj
::
Maybe
<
kj
::
Own
<
TwoPartyVatNetworkBase
::
Connection
>>
connect
(
...
...
@@ -136,7 +138,8 @@ class TwoPartyClient {
public
:
explicit
TwoPartyClient
(
kj
::
AsyncIoStream
&
connection
);
TwoPartyClient
(
kj
::
AsyncIoStream
&
connection
,
Capability
::
Client
bootstrapInterface
);
TwoPartyClient
(
kj
::
AsyncIoStream
&
connection
,
Capability
::
Client
bootstrapInterface
,
rpc
::
twoparty
::
Side
side
=
rpc
::
twoparty
::
Side
::
CLIENT
);
Capability
::
Client
bootstrap
();
// Get the server's bootstrap interface.
...
...
c++/src/capnp/test.capnp
View file @
c3b381ee
...
...
@@ -803,6 +803,22 @@ interface TestMoreStuff extends(TestCallOrder) {
# this can be used to test garbage collection.
}
interface TestMembrane {
makeThing @0 () -> (thing :Thing);
callPassThrough @1 (thing :Thing, tailCall :Bool) -> Result;
callIntercept @2 (thing :Thing, tailCall :Bool) -> Result;
loopback @3 (thing :Thing) -> (thing :Thing);
interface Thing {
passThrough @0 () -> Result;
intercept @1 () -> Result;
}
struct Result {
text @0 :Text;
}
}
struct TestTransferCap {
list @0 :List(Element);
struct Element {
...
...
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