blob: f09d7c8176e37200e11c6e477ab3643b3046df6e [file] [log] [blame]
// Copyright 2018 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/zxio/inception.h>
#include <lib/zxio/null.h>
#include <lib/zxio/ops.h>
#include <sys/socket.h>
#include <zircon/syscalls.h>
#include "private.h"
namespace fio = ::llcpp::fuchsia::io;
static zx_status_t zxio_socket_close(zxio_t* io) {
auto zs = reinterpret_cast<zxio_socket_t*>(io);
// N.B. we don't call zs->control.Close() because such a call would block
// until all bytes are drained zs->pipe.socket. Closing the channel (via the
// destructor) is semantically equivalent and doesn't block.
//
// These semantics are not quite in accordance with POSIX, but this is the
// best we can do given the double buffering inherent in the use of a zircon
// socket as the transport. In the case of us backing a blocking socket, we
// might want to block here, but the knowledge of blocking-or-not is not
// available in this context, and the consequence of this deviation is judged
// (by me - tamird@) to be minor.
zs->~zxio_socket_t();
return ZX_OK;
}
static zx_status_t zxio_socket_release(zxio_t* io, zx_handle_t* out_handle) {
auto zs = reinterpret_cast<zxio_socket_t*>(io);
*out_handle = zs->control.mutable_channel()->release();
zs->~zxio_socket_t();
return ZX_OK;
}
static zx_status_t zxio_socket_clone(zxio_t* io, zx_handle_t* out_handle) {
auto zs = reinterpret_cast<zxio_socket_t*>(io);
zx::channel local, remote;
zx_status_t status = zx::channel::create(0, &local, &remote);
if (status != ZX_OK) {
return status;
}
status = zs->control.Clone(fio::CLONE_FLAG_SAME_RIGHTS, std::move(remote)).status();
if (status != ZX_OK) {
return status;
}
*out_handle = local.release();
return ZX_OK;
}
static constexpr zxio_ops_t zxio_socket_ops = []() {
zxio_ops_t ops = zxio_default_ops;
ops.close = zxio_socket_close;
ops.release = zxio_socket_release;
ops.clone = zxio_socket_clone;
return ops;
}();
static constexpr zxio_ops_t zxio_datagram_socket_ops = []() {
zxio_ops_t ops = zxio_socket_ops;
ops.read_vector = zxio_datagram_pipe_read_vector;
ops.write_vector = zxio_datagram_pipe_write_vector;
return ops;
}();
static constexpr zxio_ops_t zxio_stream_socket_ops = []() {
zxio_ops_t ops = zxio_socket_ops;
ops.read_vector = zxio_stream_pipe_read_vector;
ops.write_vector = zxio_stream_pipe_write_vector;
return ops;
}();
zx_status_t zxio_socket_init(zxio_storage_t* storage,
::llcpp::fuchsia::posix::socket::Control::SyncClient control,
zx::socket socket, zx_info_socket_t info) {
auto zs = new (storage) zxio_socket_t{
.pipe =
{
.io = storage->io,
.socket = std::move(socket),
},
.control = std::move(control),
};
zxio_init(&zs->pipe.io, info.options & ZX_SOCKET_DATAGRAM ? &zxio_datagram_socket_ops
: &zxio_stream_socket_ops);
return ZX_OK;
}