blob: 6b740f1c1518cbf78940380a7b06c226dd620cf6 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ipcz/parcel_wrapper.h"
#include "ipcz/driver_object.h"
#include "ipcz/driver_transport.h"
#include "ipcz/ipcz.h"
#include "ipcz/node.h"
#include "ipcz/node_link.h"
#include "util/ref_counted.h"
namespace ipcz {
ParcelWrapper::ParcelWrapper(Parcel parcel) : parcel_(std::move(parcel)) {}
ParcelWrapper::~ParcelWrapper() = default;
IpczResult ParcelWrapper::Close() {
return IPCZ_RESULT_OK;
}
IpczResult ParcelWrapper::Reject(uintptr_t context) {
const Ref<NodeLink>& remote_source = parcel_.remote_source();
if (!remote_source) {
return IPCZ_RESULT_FAILED_PRECONDITION;
}
const IpczDriver& driver = remote_source->node()->driver();
const Ref<DriverTransport>& transport = remote_source->transport();
driver.ReportBadTransportActivity(transport->driver_object().handle(),
context, IPCZ_NO_FLAGS, nullptr);
return IPCZ_RESULT_OK;
}
IpczResult ParcelWrapper::Get(IpczGetFlags flags,
void* data,
size_t* num_bytes,
IpczHandle* handles,
size_t* num_handles) {
if (in_two_phase_get_) {
return IPCZ_RESULT_ALREADY_EXISTS;
}
const bool allow_partial = (flags & IPCZ_GET_PARTIAL) != 0;
const size_t data_capacity = num_bytes ? *num_bytes : 0;
const size_t handles_capacity = num_handles ? *num_handles : 0;
if ((data_capacity && !data) || (handles_capacity && !handles)) {
return IPCZ_RESULT_INVALID_ARGUMENT;
}
const size_t data_size = allow_partial
? std::min(parcel_.data_size(), data_capacity)
: parcel_.data_size();
const size_t handles_size =
allow_partial ? std::min(parcel_.num_objects(), handles_capacity)
: parcel_.num_objects();
if (num_bytes) {
*num_bytes = data_size;
}
if (num_handles) {
*num_handles = handles_size;
}
const bool consuming_whole_parcel =
(data_capacity >= data_size && handles_capacity >= handles_size);
if (!consuming_whole_parcel && !allow_partial) {
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
}
memcpy(data, parcel_.data_view().data(), data_size);
parcel_.Consume(data_size, absl::MakeSpan(handles, handles_size));
return IPCZ_RESULT_OK;
}
IpczResult ParcelWrapper::BeginGet(const void** data,
size_t* num_data_bytes,
size_t* num_handles) {
if (in_two_phase_get_) {
return IPCZ_RESULT_ALREADY_EXISTS;
}
if (data) {
*data = parcel_.data_view().data();
}
if (num_data_bytes) {
*num_data_bytes = parcel_.data_size();
}
if (num_handles) {
*num_handles = parcel_.num_objects();
}
if ((parcel_.data_size() && (!data || !num_data_bytes)) ||
(parcel_.num_objects() && !num_handles)) {
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
}
in_two_phase_get_ = true;
return IPCZ_RESULT_OK;
}
IpczResult ParcelWrapper::CommitGet(size_t num_data_bytes_consumed,
absl::Span<IpczHandle> handles) {
if (!in_two_phase_get_) {
return IPCZ_RESULT_FAILED_PRECONDITION;
}
if (num_data_bytes_consumed > parcel_.data_size() ||
handles.size() > parcel_.num_objects()) {
return IPCZ_RESULT_OUT_OF_RANGE;
}
parcel_.Consume(num_data_bytes_consumed, handles);
in_two_phase_get_ = false;
return IPCZ_RESULT_OK;
}
IpczResult ParcelWrapper::AbortGet() {
if (!in_two_phase_get_) {
return IPCZ_RESULT_FAILED_PRECONDITION;
}
in_two_phase_get_ = false;
return IPCZ_RESULT_OK;
}
} // namespace ipcz