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
9 years ago
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++
\
...
...
This diff is collapsed.
Click to expand it.
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++
...
...
This diff is collapsed.
Click to expand it.
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.
...
...
This diff is collapsed.
Click to expand it.
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
;
...
...
This diff is collapsed.
Click to expand it.
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.
...
...
This diff is collapsed.
Click to expand it.
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
This diff is collapsed.
Click to expand it.
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_
This diff is collapsed.
Click to expand it.
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
);
}
...
...
This diff is collapsed.
Click to expand it.
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.
...
...
This diff is collapsed.
Click to expand it.
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 {
...
...
This diff is collapsed.
Click to expand it.
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