| // Copyright 2024 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 <fidl/fuchsia.unknown/cpp/wire.h> |
| #include <lib/fidl/cpp/wire/channel.h> |
| #include <lib/fit/defer.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zxio/null.h> |
| #include <lib/zxio/ops.h> |
| |
| #include "sdk/lib/zxio/private.h" |
| |
| namespace funknown = fuchsia_unknown; |
| |
| namespace { |
| |
| class Transferable : public HasIo { |
| public: |
| Transferable(zx::channel channel) : HasIo(kOps), channel_(std::move(channel)) {} |
| |
| private: |
| static const zxio_ops_t kOps; |
| |
| void Destroy(); |
| zx_status_t Close(); |
| zx_status_t Clone(zx_handle_t* out_handle); |
| zx_status_t Release(zx_handle_t* out_handle); |
| zx_status_t AttrGet(zxio_node_attributes_t* inout_attr); |
| zx_status_t FlagsGetDeprecated(uint32_t* out_flags); |
| zx_status_t FlagsSetDeprecated(uint32_t flags); |
| zx_status_t FlagsGet(uint64_t* out_flags); |
| zx_status_t FlagsSet(uint64_t flags); |
| |
| zx::channel channel_; |
| }; |
| |
| constexpr zxio_ops_t Transferable::kOps = []() { |
| using Adaptor = Adaptor<Transferable>; |
| zxio_ops_t ops = zxio_default_ops; |
| ops.destroy = Adaptor::From<&Transferable::Destroy>; |
| ops.close = Adaptor::From<&Transferable::Close>; |
| ops.clone = Adaptor::From<&Transferable::Clone>; |
| ops.release = Adaptor::From<&Transferable::Release>; |
| ops.attr_get = Adaptor::From<&Transferable::AttrGet>; |
| ops.flags_get_deprecated = Adaptor::From<&Transferable::FlagsGetDeprecated>; |
| ops.flags_set_deprecated = Adaptor::From<&Transferable::FlagsSetDeprecated>; |
| ops.flags_get = Adaptor::From<&Transferable::FlagsGet>; |
| ops.flags_set = Adaptor::From<&Transferable::FlagsSet>; |
| return ops; |
| }(); |
| |
| void Transferable::Destroy() { this->~Transferable(); } |
| |
| zx_status_t Transferable::Close() { |
| if (channel_.is_valid()) { |
| auto client = fidl::UnownedClientEnd<funknown::Closeable>(channel_.get()); |
| |
| const fidl::WireResult result = fidl::WireCall(client)->Close(); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| const auto& response = result.value(); |
| if (response.is_error()) { |
| return response.error_value(); |
| } |
| } |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::Clone(zx_handle_t* out_handle) { |
| if (!channel_.is_valid()) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| auto client = fidl::UnownedClientEnd<funknown::Cloneable>(channel_.get()); |
| auto [client_end, server_end] = fidl::Endpoints<funknown::Cloneable>::Create(); |
| const fidl::Status result = fidl::WireCall(client)->Clone(std::move(server_end)); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| *out_handle = client_end.TakeChannel().release(); |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::Release(zx_handle_t* out_handle) { |
| *out_handle = channel_.release(); |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::AttrGet(zxio_node_attributes_t* inout_attr) { |
| if (inout_attr->has.abilities) { |
| ZXIO_NODE_ATTR_SET(*inout_attr, abilities, ZXIO_OPERATION_GET_ATTRIBUTES); |
| } |
| if (inout_attr->has.object_type) { |
| ZXIO_NODE_ATTR_SET(*inout_attr, object_type, ZXIO_OBJECT_TYPE_TRANSFERABLE); |
| } |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::FlagsGetDeprecated(uint32_t* out_flags) { |
| // By default a transferable is readable and writeable - zxio doesn't know. |
| fuchsia_io::wire::OpenFlags flags{}; |
| flags |= fuchsia_io::wire::OpenFlags::kRightReadable; |
| flags |= fuchsia_io::wire::OpenFlags::kRightWritable; |
| *out_flags = static_cast<uint32_t>(flags); |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::FlagsSetDeprecated(uint32_t flags) { return ZX_OK; } |
| |
| zx_status_t Transferable::FlagsGet(uint64_t* out_flags) { |
| // By default a transferable is readable and writeable. |
| constexpr fuchsia_io::wire::Flags kFlags = |
| fuchsia_io::wire::Flags::kPermReadBytes | fuchsia_io::wire::Flags::kPermWriteBytes; |
| *out_flags = uint64_t{kFlags}; |
| return ZX_OK; |
| } |
| |
| zx_status_t Transferable::FlagsSet(uint64_t flags) { return ZX_OK; } |
| |
| } // namespace |
| |
| zx_status_t zxio_transferable_init(zxio_storage_t* storage, zx::channel channel) { |
| new (storage) Transferable(std::move(channel)); |
| return ZX_OK; |
| } |