blob: 9f72231f496d2cf1f2055771f85f65efcd28c2dd [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 "reference_drivers/single_process_reference_driver_base.h"
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
#include "ipcz/ipcz.h"
#include "reference_drivers/object.h"
#include "reference_drivers/random.h"
#include "third_party/abseil-cpp/absl/base/macros.h"
#include "util/ref_counted.h"
namespace ipcz::reference_drivers {
namespace {
// Shared memory objects in single-process drivers are plain heap allocations.
class InProcessMemory : public ObjectImpl<InProcessMemory, Object::kMemory> {
public:
explicit InProcessMemory(size_t size)
: size_(size), data_(new uint8_t[size]) {
memset(&data_[0], 0, size_);
}
size_t size() const { return size_; }
void* address() const { return &data_[0]; }
private:
~InProcessMemory() override = default;
const size_t size_;
const std::unique_ptr<uint8_t[]> data_;
};
// As there's nothing to "map" from a heap allocation, single-process driver
// memory mappings simply hold an active reference to the underlying
// heap allocation.
class InProcessMapping : public ObjectImpl<InProcessMapping, Object::kMapping> {
public:
explicit InProcessMapping(Ref<InProcessMemory> memory)
: memory_(std::move(memory)) {}
size_t size() const { return memory_->size(); }
void* address() const { return memory_->address(); }
private:
~InProcessMapping() override = default;
const Ref<InProcessMemory> memory_;
};
BadTransportActivityCallback& GetBadTransportActivityCallback() {
static BadTransportActivityCallback* callback =
new BadTransportActivityCallback();
return *callback;
}
IpczResult IPCZ_API Close(IpczDriverHandle handle,
uint32_t flags,
const void* options) {
Ref<Object> object = Object::TakeFromHandle(handle);
if (!object) {
return IPCZ_RESULT_INVALID_ARGUMENT;
}
return object->Close();
}
IpczResult IPCZ_API Serialize(IpczDriverHandle handle,
IpczDriverHandle transport,
uint32_t flags,
const void* options,
volatile void* data,
size_t* num_bytes,
IpczDriverHandle* handles,
size_t* num_handles) {
Object* object = Object::FromHandle(handle);
if (!object) {
return IPCZ_RESULT_INVALID_ARGUMENT;
}
if (num_bytes) {
*num_bytes = 0;
}
// Since this is all in-process, all driver handles can be transmitted as-is.
const size_t handle_capacity = num_handles ? *num_handles : 0;
if (num_handles) {
*num_handles = 1;
}
if (handle_capacity < 1) {
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
}
handles[0] = handle;
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API Deserialize(const volatile void* data,
size_t num_bytes,
const IpczDriverHandle* handles,
size_t num_handles,
IpczDriverHandle transport,
uint32_t flags,
const void* options,
IpczDriverHandle* driver_handle) {
ABSL_ASSERT(num_bytes == 0);
ABSL_ASSERT(num_handles == 1);
*driver_handle = handles[0];
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API ReportBadTransportActivity(IpczDriverHandle transport,
uintptr_t context,
uint32_t flags,
const void* options) {
auto& callback = GetBadTransportActivityCallback();
if (callback) {
callback(transport, context);
}
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API AllocateSharedMemory(size_t num_bytes,
uint32_t flags,
const void* options,
IpczDriverHandle* driver_memory) {
if (num_bytes > std::numeric_limits<size_t>::max()) {
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
}
auto memory = MakeRefCounted<InProcessMemory>(static_cast<size_t>(num_bytes));
*driver_memory = Object::ReleaseAsHandle(std::move(memory));
return IPCZ_RESULT_OK;
}
IpczResult GetSharedMemoryInfo(IpczDriverHandle driver_memory,
uint32_t flags,
const void* options,
IpczSharedMemoryInfo* info) {
Object* object = Object::FromHandle(driver_memory);
if (!object || object->type() != Object::kMemory || !info ||
info->size < sizeof(IpczSharedMemoryInfo)) {
return IPCZ_RESULT_INVALID_ARGUMENT;
}
info->region_num_bytes = static_cast<InProcessMemory*>(object)->size();
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API DuplicateSharedMemory(IpczDriverHandle driver_memory,
uint32_t flags,
const void* options,
IpczDriverHandle* new_driver_memory) {
Ref<InProcessMemory> memory(InProcessMemory::FromHandle(driver_memory));
*new_driver_memory = Object::ReleaseAsHandle(std::move(memory));
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API MapSharedMemory(IpczDriverHandle driver_memory,
uint32_t flags,
const void* options,
volatile void** address,
IpczDriverHandle* driver_mapping) {
Ref<InProcessMemory> memory(InProcessMemory::FromHandle(driver_memory));
auto mapping = MakeRefCounted<InProcessMapping>(std::move(memory));
*address = mapping->address();
*driver_mapping = Object::ReleaseAsHandle(std::move(mapping));
return IPCZ_RESULT_OK;
}
IpczResult IPCZ_API GenerateRandomBytes(size_t num_bytes,
uint32_t flags,
const void* options,
void* buffer) {
RandomBytes(absl::MakeSpan(static_cast<uint8_t*>(buffer), num_bytes));
return IPCZ_RESULT_OK;
}
} // namespace
const IpczDriver kSingleProcessReferenceDriverBase = {
sizeof(kSingleProcessReferenceDriverBase),
Close,
Serialize,
Deserialize,
nullptr,
nullptr,
nullptr,
nullptr,
ReportBadTransportActivity,
AllocateSharedMemory,
GetSharedMemoryInfo,
DuplicateSharedMemory,
MapSharedMemory,
GenerateRandomBytes,
};
void SetBadTransportActivityCallback(BadTransportActivityCallback callback) {
GetBadTransportActivityCallback() = std::move(callback);
}
} // namespace ipcz::reference_drivers