blob: 313e47fed3336d0c12a19b36f4d8d1135cd5fbe9 [file] [log] [blame] [edit]
// Copyright 2025 The Fuchsia Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sdk/lib/zxio/handle_holder.h"
#include <lib/zxio/null.h>
#include <lib/zxio/ops.h>
#include <new>
#include <utility>
namespace zxio {
namespace {
// A zxio_handle_holder is a zxio object instance that holds on to a handle and
// allows it to be closed or released via zxio_destroy() / zxio_release(). It is
// useful for wrapping objects that zxio does not understand.
struct zxio_handle_holder {
zxio_t io;
zx::handle handle;
};
static_assert(sizeof(zxio_handle_holder) <= sizeof(zxio_storage_t),
"zxio_handle_holder must fit inside zxio_storage_t.");
zxio_handle_holder& zxio_get_handle_holder(zxio_t* io) {
return *reinterpret_cast<zxio_handle_holder*>(io);
}
constexpr zxio_ops_t zxio_handle_holder_ops = []() {
zxio_ops_t ops = zxio_default_ops;
ops.destroy = [](zxio_t* io) { zxio_get_handle_holder(io).~zxio_handle_holder(); };
ops.release = [](zxio_t* io, zx_handle_t* out_handle) {
const zx_handle_t handle = zxio_get_handle_holder(io).handle.release();
if (handle == ZX_HANDLE_INVALID) {
return ZX_ERR_BAD_HANDLE;
}
*out_handle = handle;
return ZX_OK;
};
ops.borrow = [](zxio_t* io, zx_handle_t* out_handle) {
*out_handle = zxio_get_handle_holder(io).handle.get();
return ZX_OK;
};
ops.clone = [](zxio_t* io, zx_handle_t* out_handle) {
zx::handle handle;
zx_status_t status = zxio_get_handle_holder(io).handle.duplicate(ZX_RIGHT_SAME_RIGHTS, &handle);
*out_handle = handle.release();
return status;
};
return ops;
}();
} // namespace
void handle_holder_init(zxio_storage_t* storage, zx::handle handle) {
auto holder = new (storage) zxio_handle_holder{
.handle = std::move(handle),
};
zxio_init(&holder->io, &zxio_handle_holder_ops);
}
} // namespace zxio