| // Copyright 2022 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 <lib/fidl/cpp/wire/incoming_message.h> |
| #include <lib/fidl/cpp/wire/outgoing_message.h> |
| |
| #ifdef __Fuchsia__ |
| #include <lib/fidl/cpp/wire/internal/transport_channel.h> |
| #else |
| #include <lib/fidl/cpp/wire/internal/transport_channel_host.h> |
| #endif // __Fuchsia__ |
| |
| namespace fidl { |
| |
| OutgoingMessage::OutgoingMessage(const ::fidl::Status& failure) |
| : fidl::Status(failure), message_({}) { |
| ZX_DEBUG_ASSERT(failure.status() != ZX_OK); |
| } |
| |
| OutgoingMessage::OutgoingMessage(InternalIovecConstructorArgs args) |
| : fidl::Status(fidl::Status::Ok()), message_(args) {} |
| |
| OutgoingMessage::~OutgoingMessage() { |
| // We may not have a vtable when the |OutgoingMessage| represents an error. |
| if (message_.transport_vtable) { |
| message_.transport_vtable->encoding_configuration->close_many(handles(), handle_actual()); |
| } |
| } |
| |
| uint32_t OutgoingMessage::CountBytes() const { |
| uint32_t byte_count = 0; |
| for (uint32_t i = 0; i < iovec_actual(); ++i) { |
| byte_count += iovecs()[i].capacity; |
| } |
| return byte_count; |
| } |
| |
| bool OutgoingMessage::BytesMatch(const OutgoingMessage& other) const { |
| uint32_t iovec_index = 0, other_iovec_index = 0; |
| uint32_t byte_index = 0, other_byte_index = 0; |
| while (iovec_index < iovec_actual() && other_iovec_index < other.iovec_actual()) { |
| zx_channel_iovec_t cur_iovec = iovecs()[iovec_index]; |
| zx_channel_iovec_t other_cur_iovec = other.iovecs()[other_iovec_index]; |
| const uint8_t* cur_bytes = reinterpret_cast<const uint8_t*>(cur_iovec.buffer); |
| const uint8_t* other_cur_bytes = reinterpret_cast<const uint8_t*>(other_cur_iovec.buffer); |
| |
| uint32_t cmp_len = |
| std::min(cur_iovec.capacity - byte_index, other_cur_iovec.capacity - other_byte_index); |
| if (memcmp(&cur_bytes[byte_index], &other_cur_bytes[other_byte_index], cmp_len) != 0) { |
| return false; |
| } |
| |
| byte_index += cmp_len; |
| if (byte_index == cur_iovec.capacity) { |
| iovec_index++; |
| byte_index = 0; |
| } |
| other_byte_index += cmp_len; |
| if (other_byte_index == other_cur_iovec.capacity) { |
| other_iovec_index++; |
| other_byte_index = 0; |
| } |
| } |
| return iovec_index == iovec_actual() && other_iovec_index == other.iovec_actual() && |
| byte_index == 0 && other_byte_index == 0; |
| } |
| |
| void OutgoingMessage::EncodeImpl(fidl::internal::WireFormatVersion wire_format_version, void* data, |
| size_t inline_size, fidl::internal::TopLevelEncodeFn encode_fn) { |
| if (unlikely(!ok())) { |
| return; |
| } |
| if (unlikely(wire_format_version != fidl::internal::WireFormatVersion::kV2)) { |
| SetStatus(fidl::Status::EncodeError(ZX_ERR_INVALID_ARGS, "only v2 wire format supported")); |
| return; |
| } |
| |
| fit::result<fidl::Error, fidl::internal::WireEncoder::Result> result = fidl::internal::WireEncode( |
| inline_size, encode_fn, message_.transport_vtable->encoding_configuration, data, iovecs(), |
| iovec_capacity(), handles(), message_.handle_metadata, handle_capacity(), backing_buffer(), |
| backing_buffer_capacity()); |
| if (unlikely(!result.is_ok())) { |
| SetStatus(result.error_value()); |
| return; |
| } |
| message_.num_iovecs = static_cast<uint32_t>(result.value().iovec_actual); |
| message_.num_handles = static_cast<uint32_t>(result.value().handle_actual); |
| } |
| |
| void OutgoingMessage::Write(internal::AnyUnownedTransport transport, WriteOptions options) { |
| if (unlikely(!ok())) { |
| return; |
| } |
| ZX_ASSERT(transport_type() == transport.type()); |
| ZX_ASSERT(is_transactional()); |
| zx_status_t status = |
| transport.write(std::move(options), internal::WriteArgs{ |
| .data = iovecs(), |
| .handles = handles(), |
| .handle_metadata = message_.handle_metadata, |
| .data_count = iovec_actual(), |
| .handles_count = handle_actual(), |
| }); |
| ReleaseHandles(); |
| if (unlikely(status != ZX_OK)) { |
| SetStatus(fidl::Status::TransportError(status)); |
| } |
| } |
| |
| IncomingHeaderAndMessage OutgoingMessage::CallImpl(internal::AnyUnownedTransport transport, |
| internal::MessageStorageViewBase& storage, |
| CallOptions options) { |
| if (status() != ZX_OK) { |
| return IncomingHeaderAndMessage::Create(Status(*this)); |
| } |
| ZX_ASSERT(transport_type() == transport.type()); |
| ZX_ASSERT(is_transactional()); |
| |
| uint8_t* result_bytes; |
| fidl_handle_t* result_handles; |
| fidl_handle_metadata_t* result_handle_metadata; |
| uint32_t actual_num_bytes = 0u; |
| uint32_t actual_num_handles = 0u; |
| internal::CallMethodArgs args = { |
| .wr = |
| internal::WriteArgs{ |
| .data = iovecs(), |
| .handles = handles(), |
| .handle_metadata = message_.handle_metadata, |
| .data_count = iovec_actual(), |
| .handles_count = handle_actual(), |
| }, |
| .rd = |
| internal::ReadArgs{ |
| .storage_view = &storage, |
| .out_data = reinterpret_cast<void**>(&result_bytes), |
| .out_handles = &result_handles, |
| .out_handle_metadata = &result_handle_metadata, |
| .out_data_actual_count = &actual_num_bytes, |
| .out_handles_actual_count = &actual_num_handles, |
| }, |
| }; |
| |
| zx_status_t status = transport.call(std::move(options), args); |
| ReleaseHandles(); |
| if (status != ZX_OK) { |
| SetStatus(fidl::Status::TransportError(status)); |
| return IncomingHeaderAndMessage::Create(Status(*this)); |
| } |
| |
| return IncomingHeaderAndMessage(message_.transport_vtable, result_bytes, actual_num_bytes, |
| result_handles, result_handle_metadata, actual_num_handles); |
| } |
| |
| OutgoingMessage::CopiedBytes::CopiedBytes(const OutgoingMessage& msg) { |
| uint32_t byte_count = 0; |
| for (uint32_t i = 0; i < msg.iovec_actual(); ++i) { |
| byte_count += msg.iovecs()[i].capacity; |
| } |
| bytes_.reserve(byte_count); |
| for (uint32_t i = 0; i < msg.iovec_actual(); ++i) { |
| zx_channel_iovec_t iovec = msg.iovecs()[i]; |
| const uint8_t* buf_bytes = reinterpret_cast<const uint8_t*>(iovec.buffer); |
| bytes_.insert(bytes_.end(), buf_bytes, buf_bytes + iovec.capacity); |
| } |
| } |
| |
| } // namespace fidl |