blob: 57a7def8637a9e85638f6ad53cb78c2c040a95d9 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuchsia/io/llcpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/fd.h>
#include <lib/fidl-async/cpp/bind.h>
#include <fbl/unique_fd.h>
#include <zxtest/zxtest.h>
namespace {
class Server final : public llcpp::fuchsia::io::Node::Interface {
public:
explicit Server(llcpp::fuchsia::io::NodeInfo describe_info)
: describe_info_(std::move(describe_info)) {}
void Clone(uint32_t flags, ::zx::channel object, CloneCompleter::Sync& completer) override {
ADD_FAILURE("Clone should not be called");
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void Close(CloseCompleter::Sync& completer) override {
EXPECT_OK(completer.Reply(ZX_OK).status());
// FDIO expects the channel to be closed after replying.
completer.Close(ZX_OK);
}
void Describe(DescribeCompleter::Sync& completer) override {
ASSERT_TRUE(describe_info_.has_value(), "Describe called more than once");
EXPECT_OK(completer.Reply(std::move(*describe_info_)).status());
describe_info_.reset();
}
void Sync(SyncCompleter::Sync& completer) override {
ADD_FAILURE("Sync should not be called");
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void GetAttr(GetAttrCompleter::Sync& completer) override {
ADD_FAILURE("GetAttr should not be called");
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void SetAttr(uint32_t flags, ::llcpp::fuchsia::io::NodeAttributes attributes,
SetAttrCompleter::Sync& completer) override {
ADD_FAILURE("SetAttr should not be called");
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
private:
fit::optional<llcpp::fuchsia::io::NodeInfo> describe_info_;
};
// Serves |node_info| over |server_channel| to |client_channel| using a |Server| instance by
// creating a file descriptor from |client_channel| and immediately closing it.
void ServeAndExerciseFileDescriptionTeardown(llcpp::fuchsia::io::NodeInfo node_info,
zx::channel client_channel,
zx::channel server_channel) {
Server server(std::move(node_info));
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto bind_result = fidl::BindServer(loop.dispatcher(), std::move(server_channel), &server);
ASSERT_TRUE(bind_result.is_ok(), "failed to bind server: %s",
zx_status_get_string(bind_result.error()));
ASSERT_OK(loop.StartThread("fake-socket-server"));
{
fbl::unique_fd fd;
ASSERT_OK(fdio_fd_create(client_channel.release(), fd.reset_and_get_address()));
}
}
TEST(SocketCleanup, Datagram) {
zx::channel client_channel, server_channel;
ASSERT_OK(zx::channel::create(0, &client_channel, &server_channel));
zx::eventpair client_event, server_event;
ASSERT_OK(zx::eventpair::create(0, &client_event, &server_event));
llcpp::fuchsia::io::DatagramSocket dgram_info{.event = std::move(client_event)};
llcpp::fuchsia::io::NodeInfo node_info;
node_info.set_datagram_socket(fidl::unowned_ptr(&dgram_info));
zx::unowned_channel client_handle(client_channel);
ASSERT_NO_FATAL_FAILURES(ServeAndExerciseFileDescriptionTeardown(
std::move(node_info), std::move(client_channel), std::move(server_channel)));
// Client must have disposed of its channel and eventpair handle on close.
EXPECT_STATUS(client_handle->wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite_past(), nullptr),
ZX_ERR_BAD_HANDLE);
EXPECT_OK(server_event.wait_one(ZX_EVENTPAIR_PEER_CLOSED, zx::time::infinite_past(), nullptr));
}
TEST(SocketCleanup, Stream) {
zx::channel client_channel, server_channel;
ASSERT_OK(zx::channel::create(0, &client_channel, &server_channel));
zx::socket client_socket, server_socket;
ASSERT_OK(zx::socket::create(0, &client_socket, &server_socket));
llcpp::fuchsia::io::StreamSocket stream_info{.socket = std::move(client_socket)};
llcpp::fuchsia::io::NodeInfo node_info;
node_info.set_stream_socket(fidl::unowned_ptr(&stream_info));
zx::unowned_channel client_handle(client_channel);
ASSERT_NO_FATAL_FAILURES(ServeAndExerciseFileDescriptionTeardown(
std::move(node_info), std::move(client_channel), std::move(server_channel)));
// Client must have disposed of its channel and socket handles on close.
EXPECT_STATUS(client_handle->wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite_past(), nullptr),
ZX_ERR_BAD_HANDLE);
EXPECT_OK(server_socket.wait_one(ZX_SOCKET_PEER_CLOSED, zx::time::infinite_past(), nullptr));
}
} // namespace