blob: f78d78c153a1b194840fbbacf44fe05e763c1889 [file] [log] [blame]
// 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