| // 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, const WriteOptions& write_options, const void* data, |
| uint32_t data_count, const fidl_handle_t* handles, |
| const void* handle_metadata, uint32_t handles_count) { |
| ZX_ASSERT(handles_count == 0); |
| ZX_ASSERT(data_count == 1); // 1 iovec |
| size_t actual; |
| zx_channel_iovec_t iovec = static_cast<const zx_channel_iovec_t*>(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, void* data, |
| uint32_t data_capacity, fidl_handle_t* handles, void* handle_metadata, |
| uint32_t handles_capacity, uint32_t* out_data_actual_count, |
| uint32_t* out_handles_actual_count) { |
| size_t actual; |
| zx_status_t status = zx_socket_read(handle, 0, data, data_capacity, &actual); |
| if (status != ZX_OK) { |
| return status; |
| } |
| *out_data_actual_count = static_cast<uint32_t>(actual); |
| *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_close(fidl_handle_t handle) { zx_handle_close(handle); } |
| |
| } // 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, |
| .close = socket_close, |
| }; |
| |
| 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), bytes.view(), |
| nullptr, nullptr, 0); |
| if (!msg.ok()) { |
| return failure_handler_(fidl::UnbindInfo{msg}); |
| } |
| return success_handler_(msg, nullptr); |
| } |
| |
| const CodingConfig SocketTransport::EncodingConfiguration = {}; |
| |
| AnyTransport MakeAnyTransport(zx::socket socket) { |
| return AnyTransport::Make<SocketTransport>(socket.release()); |
| } |
| AnyUnownedTransport MakeAnyUnownedTransport(const zx::socket& socket) { |
| return MakeAnyUnownedTransport(socket.borrow()); |
| } |
| AnyUnownedTransport MakeAnyUnownedTransport(const zx::unowned_socket& socket) { |
| return AnyUnownedTransport::Make<SocketTransport>(socket->get()); |
| } |
| |
| } // namespace internal |
| } // namespace fidl |