Commit 77a57f8c authored by Kenton Varda's avatar Kenton Varda

Fix RPC loopback bootstrap().

When VatNetwork::connect() returns nullptr, it means that the caller is trying to connect to itself.

rpc-test.c++ failed to test this in two ways:
- The test VatNetwork's connect() never returned null.
- There was no test case for loopback connect.

As a result, the code to handle loopback in rpc.c++ had bitrotted. It failed to handle the new bootstrap mechanism introduced in v0.5, and instead only implemented the restorer mechanism from 0.4.
parent 7c35ceb9
......@@ -198,7 +198,7 @@ typedef VatNetwork<
class TestNetworkAdapter final: public TestNetworkAdapterBase {
public:
TestNetworkAdapter(TestNetwork& network): network(network) {}
TestNetworkAdapter(TestNetwork& network, kj::StringPtr self): network(network), self(self) {}
~TestNetworkAdapter() {
kj::Exception exception = KJ_EXCEPTION(FAILED, "Network was destroyed.");
......@@ -362,6 +362,10 @@ public:
};
kj::Maybe<kj::Own<Connection>> connect(test::TestSturdyRefHostId::Reader hostId) override {
if (hostId.getHost() == self) {
return nullptr;
}
TestNetworkAdapter& dst = KJ_REQUIRE_NONNULL(network.find(hostId.getHost()));
auto iter = connections.find(&dst);
......@@ -400,6 +404,7 @@ public:
private:
TestNetwork& network;
kj::StringPtr self;
uint sent = 0;
uint received = 0;
......@@ -411,7 +416,7 @@ private:
TestNetwork::~TestNetwork() noexcept(false) {}
TestNetworkAdapter& TestNetwork::add(kj::StringPtr name) {
return *(map[name] = kj::heap<TestNetworkAdapter>(*this));
return *(map[name] = kj::heap<TestNetworkAdapter>(*this, name));
}
// =======================================================================================
......@@ -456,6 +461,12 @@ struct TestContext {
serverNetwork(network.add("server")),
rpcClient(makeRpcClient(clientNetwork)),
rpcServer(makeRpcServer(serverNetwork, restorer)) {}
TestContext(Capability::Client bootstrap)
: waitScope(loop),
clientNetwork(network.add("client")),
serverNetwork(network.add("server")),
rpcClient(makeRpcClient(clientNetwork)),
rpcServer(makeRpcServer(serverNetwork, bootstrap)) {}
TestContext(Capability::Client bootstrap,
RealmGateway<test::TestSturdyRef, Text>::Client gateway)
: waitScope(loop),
......@@ -1264,6 +1275,26 @@ TEST(Rpc, RealmGatewayImportExport) {
EXPECT_EQ("foo", response.getSturdyRef());
}
KJ_TEST("loopback bootstrap()") {
int callCount = 0;
test::TestInterface::Client bootstrap = kj::heap<TestInterfaceImpl>(callCount);
MallocMessageBuilder hostIdBuilder;
auto hostId = hostIdBuilder.getRoot<test::TestSturdyRefHostId>();
hostId.setHost("server");
TestContext context(bootstrap);
auto client = context.rpcServer.bootstrap(hostId).castAs<test::TestInterface>();
auto request = client.fooRequest();
request.setI(123);
request.setJ(true);
auto response = request.send().wait(context.waitScope);
KJ_EXPECT(response.getX() == "foo");
KJ_EXPECT(callCount == 1);
}
} // namespace
} // namespace _ (private)
} // namespace capnp
......@@ -2999,11 +2999,16 @@ public:
KJ_IF_MAYBE(connection, network.baseConnect(vatId)) {
auto& state = getConnectionState(kj::mv(*connection));
return Capability::Client(state.restore(objectId));
} else if (objectId.isNull()) {
// Turns out `vatId` refers to ourselves, so we can also pass it as the client ID for
// baseCreateFor().
return bootstrapFactory.baseCreateFor(vatId);
} else KJ_IF_MAYBE(r, restorer) {
return r->baseRestore(objectId);
} else {
return Capability::Client(newBrokenCap(
"SturdyRef referred to a local object but there is no local SturdyRef restorer."));
"This vat only supports a bootstrap interface, not the old Cap'n-Proto-0.4-style "
"named exports."));
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment