blob: 63de056aafb49ca6c619d79f1b56690ca9358ca9 [file] [log] [blame]
// Copyright 2021 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 "transport_socket.h"
#include <lib/fidl/internal.h>
#include <lib/fidl/llcpp/message.h>
#include <zircon/assert.h>
#include <zircon/fidl.h>
#include <zircon/types.h>
#include <cstring>
#include <memory>
namespace fidl {
namespace internal {
namespace {
zx_status_t socket_write(fidl_handle_t handle, WriteOptions write_options, const WriteArgs& args) {
ZX_ASSERT(args.handles_count == 0);
ZX_ASSERT(args.data_count == 1); // 1 iovec
size_t actual;
zx_channel_iovec_t iovec = static_cast<const zx_channel_iovec_t*>(args.data)[0];
zx_status_t status = zx_socket_write(handle, 0, iovec.buffer, iovec.capacity, &actual);
if (status != ZX_OK) {
return status;
}
ZX_ASSERT(actual == iovec.capacity);
return ZX_OK;
}
zx_status_t socket_read(fidl_handle_t handle, const ReadOptions& read_options,
const ReadArgs& args) {
ZX_DEBUG_ASSERT(args.storage_view != nullptr);
ZX_DEBUG_ASSERT(args.out_data != nullptr);
SocketMessageStorageView* rd_view = static_cast<SocketMessageStorageView*>(args.storage_view);
size_t actual;
zx_status_t status =
zx_socket_read(handle, 0, rd_view->bytes.data, rd_view->bytes.capacity, &actual);
if (status != ZX_OK) {
return status;
}
*args.out_data = rd_view->bytes.data;
*args.out_data_actual_count = static_cast<uint32_t>(actual);
*args.out_handles = nullptr;
*args.out_handle_metadata = nullptr;
*args.out_handles_actual_count = 0;
return ZX_OK;
}
zx_status_t socket_create_waiter(fidl_handle_t handle, async_dispatcher_t* dispatcher,
TransportWaitSuccessHandler success_handler,
TransportWaitFailureHandler failure_handler,
AnyTransportWaiter& any_transport_waiter) {
any_transport_waiter.emplace<SocketWaiter>(handle, dispatcher, std::move(success_handler),
std::move(failure_handler));
return ZX_OK;
}
void socket_create_thread_checker(async_dispatcher_t* dispatcher, ThreadingPolicy threading_policy,
AnyThreadChecker& any_thread_checker) {
any_thread_checker.emplace<ZirconThreadChecker>(threading_policy);
}
void socket_close(fidl_handle_t handle) { zx_handle_close(handle); }
void socket_close_many(const fidl_handle_t* handles, size_t num_handles) {
zx_handle_close_many(handles, num_handles);
}
} // namespace
const TransportVTable SocketTransport::VTable = {
.type = FIDL_TRANSPORT_TYPE_TEST,
.encoding_configuration = &SocketTransport::EncodingConfiguration,
.write = socket_write,
.read = socket_read,
.create_waiter = socket_create_waiter,
.create_thread_checker = socket_create_thread_checker,
};
void SocketWaiter::HandleWaitFinished(async_dispatcher_t* dispatcher, zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK) {
return failure_handler_(fidl::UnbindInfo::DispatcherError(status));
}
if (!(signal->observed & ZX_SOCKET_READABLE)) {
ZX_ASSERT(signal->observed & ZX_SOCKET_PEER_CLOSED);
return failure_handler_(fidl::UnbindInfo::PeerClosed(ZX_ERR_PEER_CLOSED));
}
FIDL_INTERNAL_DISABLE_AUTO_VAR_INIT InlineMessageBuffer<ZX_CHANNEL_MAX_MSG_BYTES> bytes;
IncomingMessage msg =
fidl::MessageRead(zx::unowned_socket(async_wait_t::object),
fidl::internal::SocketMessageStorageView{.bytes = bytes.view()});
if (!msg.ok()) {
return failure_handler_(fidl::UnbindInfo{msg});
}
return success_handler_(msg, nullptr);
}
const CodingConfig SocketTransport::EncodingConfiguration = {
.max_iovecs_write = 1,
.handle_metadata_stride = 0,
.close = socket_close,
.close_many = socket_close_many,
};
} // namespace internal
} // namespace fidl