// 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.
#ifdef __Fuchsia__
#include <lib/fidl/transport.h>
#include <zircon/assert.h>
#include <zircon/syscalls.h>
zx_status_t fidl_socket_write_control(zx_handle_t socket, const void* buffer,
size_t capacity) {
for (;;) {
zx_status_t status = zx_socket_write(socket, ZX_SOCKET_CONTROL, buffer,
capacity, nullptr);
if (status != ZX_ERR_SHOULD_WAIT) {
return status;
}
zx_signals_t observed = ZX_SIGNAL_NONE;
status = zx_object_wait_one(socket, ZX_SOCKET_CONTROL_WRITABLE | ZX_SOCKET_PEER_CLOSED,
ZX_TIME_INFINITE, &observed);
if (status != ZX_OK) {
return status;
}
if (observed & ZX_SOCKET_PEER_CLOSED) {
return ZX_ERR_PEER_CLOSED;
}
ZX_ASSERT(observed & ZX_SOCKET_CONTROL_WRITABLE);
}
}
zx_status_t fidl_socket_read_control(zx_handle_t socket, void* buffer,
size_t capacity, size_t* out_actual) {
for (;;) {
zx_status_t status = zx_socket_read(socket, ZX_SOCKET_CONTROL, buffer,
capacity, out_actual);
if (status != ZX_ERR_SHOULD_WAIT) {
return status;
}
zx_signals_t observed = ZX_SIGNAL_NONE;
status = zx_object_wait_one(socket, ZX_SOCKET_CONTROL_READABLE | ZX_SOCKET_PEER_CLOSED,
ZX_TIME_INFINITE, &observed);
if (status != ZX_OK) {
return status;
}
if (observed & ZX_SOCKET_CONTROL_READABLE) {
continue;
}
ZX_ASSERT(observed & ZX_SOCKET_PEER_CLOSED);
return ZX_ERR_PEER_CLOSED;
}
}
zx_status_t fidl_socket_call_control(zx_handle_t socket, const void* buffer,
size_t capacity, void* out_buffer,
size_t out_capacity, size_t* out_actual) {
zx_status_t status = fidl_socket_write_control(socket, buffer, capacity);
if (status != ZX_OK) {
return status;
}
return fidl_socket_read_control(socket, out_buffer, out_capacity, out_actual);
}
#endif