blob: 774dc9677de8c102164ecc9d92c0c111e76500b8 [file] [log] [blame]
// Copyright 2019 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.
library zx;
alias HandleOp = uint32;
// TODO(scottmg): ZX_HANDLE_OP_xyz here.
type HandleInfo = resource struct {
handle handle;
type obj_type;
rights rights;
unused uint32;
};
// TODO(fxbug.dev/110021): We cannot yet conveniently express this.
type ChannelCallArgs = resource struct {};
type HandleDisposition = resource struct {
operation HandleOp;
handle handle;
type obj_type;
rights rights;
result status;
};
// TODO(fxbug.dev/110021): We cannot yet conveniently express this.
type ChannelCallEtcArgs = resource struct {};
@transport("Syscall")
protocol Channel {
/// ## Summary
///
/// Create a channel.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_create(uint32_t options,
/// zx_handle_t* out0,
/// zx_handle_t* out1);
/// ```
///
/// ## Description
///
/// `zx_channel_create()` creates a channel, a bi-directional
/// datagram-style message transport capable of sending raw data bytes
/// as well as handles from one side to the other.
///
/// Two handles are returned on success, providing access to both sides
/// of the channel. Messages written to one handle may be read from
/// the opposite.
///
/// The handles will have these rights:
///
/// - **ZX_RIGHT_TRANSFER**: allowing them to be sent to another process via
/// [`zx_channel_write()`].
/// - **ZX_RIGHT_WAIT**: allowing one to wait for its signals.
/// - **ZX_RIGHT_INSPECT**
/// - **ZX_RIGHT_READ**: allowing messages to be read from them.
/// - **ZX_RIGHT_WRITE**: allowing messages to be written to them.
/// - **ZX_RIGHT_SIGNAL**
/// - **ZX_RIGHT_SIGNAL_PEER**
///
/// ## Rights
///
/// Caller job policy must allow **ZX_POL_NEW_CHANNEL**.
///
/// ## Return value
///
/// `zx_channel_create()` returns **ZX_OK** on success. In the event
/// of failure, a negative error value is returned.
///
/// ## Errors
///
/// **ZX_ERR_INVALID_ARGS** *out0* or *out1* is an invalid pointer or NULL or
/// *options* is any value other than 0.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// ## See also
///
/// - [`zx_channel_call()`]
/// - [`zx_channel_read()`]
/// - [`zx_channel_write()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
Create(struct {
options uint32;
}) -> (resource struct {
out0 handle;
out1 handle;
}) error status;
/// ## Summary
///
/// Read a message from a channel.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_read(zx_handle_t handle,
/// uint32_t options,
/// void* bytes,
/// zx_handle_t* handles,
/// uint32_t num_bytes,
/// uint32_t num_handles,
/// uint32_t* actual_bytes,
/// uint32_t* actual_handles);
/// ```
///
/// ## Description
///
/// `zx_channel_read()` attempts to read the first message from the channel
/// specified by *handle* into the provided *bytes* and/or *handles* buffers.
///
/// The parameters *num_bytes* and *num_handles* are used to specify the size of the
/// respective read buffers. *num_bytes* is a count of bytes, and
/// *num_handles* is a count of elements of type `zx_handle_t`.
///
/// The length of *bytes*, in bytes, is stored in the location pointed to by
/// *actual_bytes*. The number of handles is stored in the location pointed to by
/// *actual_handles*. Either *actual_bytes* or *actual_handles* may be NULL, in
/// which case they will be ignored.
///
/// Channel messages may contain both byte data and handle payloads and may
/// only be read in their entirety. Partial reads are not possible.
///
/// The *bytes* buffer is written before the *handles* buffer. In the event of
/// overlap between these two buffers, the contents written to *handles*
/// will overwrite the portion of *bytes* it overlaps.
///
/// When communicating to an untrusted party over a channel, it is recommended that
/// the [`zx_channel_read_etc()`] form is used and each handle type
/// and rights are validated against the expected values.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_READ**.
///
/// ## Return value
///
/// Returns **ZX_OK** on success. If non-NULL, the locations pointed to by
/// *actual_bytes* and *actual_handles* contain the exact number of bytes and count
/// of handles read.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** *handle* is not a valid handle.
///
/// **ZX_ERR_WRONG_TYPE** *handle* is not a channel handle.
///
/// **ZX_ERR_INVALID_ARGS** If any of *bytes*, *handles*, *actual_bytes*, or
/// *actual_handles* are non-NULL and an invalid pointer.
///
/// **ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_READ**.
///
/// **ZX_ERR_SHOULD_WAIT** The channel contained no messages to read.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel is closed.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_BUFFER_TOO_SMALL** The provided *bytes* or *handles* buffers
/// are too small (in which case, the minimum sizes necessary to receive
/// the message will be written to *actual_bytes* and *actual_handles*,
/// provided they are non-NULL). If *options* has **ZX_CHANNEL_READ_MAY_DISCARD**
/// set, then the message is discarded.
///
/// ## See also
///
/// - [`zx_channel_call()`]
/// - [`zx_channel_create()`]
/// - [`zx_channel_read_etc()`]
/// - [`zx_channel_write()`]
/// - [`zx_channel_write_etc()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read_etc()`]: channel_read_etc.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_channel_write_etc()`]: channel_write_etc.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
@handle_unchecked
Read(resource struct {
handle handle:CHANNEL;
options uint32;
@out
@voidptr
bytes experimental_pointer<byte>;
@out
handles experimental_pointer<handle>;
num_bytes uint32;
num_handles uint32;
}) -> (resource struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
/// ## Summary
///
/// Read a message from a channel.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_read_etc(zx_handle_t handle,
/// uint32_t options,
/// void* bytes,
/// zx_handle_info_t* handles,
/// uint32_t num_bytes,
/// uint32_t num_handles,
/// uint32_t* actual_bytes,
/// uint32_t* actual_handles);
/// ```
///
/// ## Description
///
/// See [`zx_channel_read()`] for a full description.
///
/// Both forms of read behave the same except that [`zx_channel_read()`] returns an
/// array of raw `zx_handle_t` handle values while `zx_channel_read_etc()` returns
/// an array of `zx_handle_info_t` structures of the form:
///
/// ```
/// typedef struct {
/// zx_handle_t handle; // handle value
/// zx_obj_type_t type; // type of object, see ZX_OBJ_TYPE_
/// zx_rights_t rights; // handle rights
/// uint32_t unused; // set to zero
/// } zx_handle_info_t;
/// ```
///
/// When communicating to an untrusted party over a channel, it is recommended
/// that the `zx_channel_read_etc()` form is used and each handle type and rights
/// are validated against the expected values.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_READ**.
///
/// ## Return value
///
/// Both forms of read return **ZX_OK** on success, if *actual_bytes*
/// and *actual_handles* (if non-NULL), contain the exact number of bytes
/// and count of handles read.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** *handle* is not a valid handle.
///
/// **ZX_ERR_WRONG_TYPE** *handle* is not a channel handle.
///
/// **ZX_ERR_INVALID_ARGS** If any of *bytes*, *handles*, *actual_bytes*, or
/// *actual_handles* are non-NULL and an invalid pointer.
///
/// **ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_READ**.
///
/// **ZX_ERR_SHOULD_WAIT** The channel contained no messages to read.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel is closed.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_BUFFER_TOO_SMALL** The provided *bytes* or *handles* buffers
/// are too small (in which case, the minimum sizes necessary to receive
/// the message will be written to *actual_bytes* and *actual_handles*,
/// provided they are non-NULL). If *options* has **ZX_CHANNEL_READ_MAY_DISCARD**
/// set, then the message is discarded.
///
/// ## Notes
///
/// *num_handles* and *actual_handles* are counts of the number of elements
/// in the *handles* array, not its size in bytes.
///
/// ## See also
///
/// - [`zx_channel_call()`]
/// - [`zx_channel_create()`]
/// - [`zx_channel_read()`]
/// - [`zx_channel_write()`]
/// - [`zx_channel_write_etc()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_channel_write_etc()`]: channel_write_etc.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
ReadEtc(resource struct {
handle handle:CHANNEL;
options uint32;
@out
@voidptr
bytes experimental_pointer<byte>;
@out
handles experimental_pointer<HandleInfo>;
num_bytes uint32;
num_handles uint32;
}) -> (resource struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
/// ## Summary
///
/// Write a message to a channel.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_write(zx_handle_t handle,
/// uint32_t options,
/// const void* bytes,
/// uint32_t num_bytes,
/// const zx_handle_t* handles,
/// uint32_t num_handles);
/// ```
///
/// ## Description
///
/// `zx_channel_write()` attempts to write a message of *num_bytes*
/// bytes and *num_handles* handles to the channel specified by
/// *handle*. The pointers *handles* and *bytes* may be NULL if their
/// respective sizes are zero.
///
/// On success, all *num_handles* of the handles in the *handles* array
/// are attached to the message and will become available to the reader
/// of that message from the opposite end of the channel.
///
/// All handles are discarded and no longer available to the caller, on
/// success or failure. Use [`zx_channel_write_etc()`] if handles need
/// to be preserved by the sender.
///
/// It is invalid to include *handle* (the handle of the channel being written
/// to) in the *handles* array (the handles being sent in the message).
///
/// The maximum number of handles that may be sent in a message is
/// **ZX_CHANNEL_MAX_MSG_HANDLES**, which is 64.
///
/// The maximum number of bytes that may be sent in a message is
/// **ZX_CHANNEL_MAX_MSG_BYTES**, which is 65536.
///
/// Messages are drained by [`zx_channel_read()`] or [`zx_channel_read_etc()`].
/// Failure to drain the messages in a timely fashion can cause excessive kernel
/// memory to be used, which might generate an exception. See
/// [ipc limits](/docs/concepts/kernel/ipc_limits.md) for details.
///
/// ### ZX_CHANNEL_WRITE_USE_IOVEC option
///
/// When the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified, `bytes` is
/// interpreted as an array of `zx_channel_iovec_t`, specifying slices of bytes to
/// sequentially copy to the message in order. `num_bytes` specifies the number of
/// `zx_channel_iovec_t` array elements in `bytes`.
///
/// ```c
/// typedef struct zx_channel_iovec {
/// const void* buffer; // User-space bytes.
/// uint32_t capacity; // Number of bytes.
/// uint32_t reserved; // Reserved.
/// } zx_channel_iovec_t;
/// ```
///
/// There can be at most **ZX_CHANNEL_MAX_MSG_IOVEC** or `8192`
/// `zx_channel_iovec_t` elements of the `bytes` array with the sum of `capacity`
/// across all `zx_channel_iovec_t` not exceeding **ZX_CHANNEL_MAX_MSG_BYTES** or
/// `65536` bytes. `buffer` need not be aligned and it may only be `NULL` if
/// `capacity` is zero. `reserved` must be set to zero.
///
/// Either all `zx_channel_iovec_t` are copied and the message is sent, or none
/// are copied and the message is not sent. Usage for sending handles is unchanged.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_WRITE**.
///
/// Every entry of *handles* must have **ZX_RIGHT_TRANSFER**.
///
/// ## Return value
///
/// `zx_channel_write()` returns **ZX_OK** on success.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** `handle` is not a valid handle, any element in
/// `handles` is not a valid handle, or there are repeated handles among the
/// handles in the `handles` array.
///
/// **ZX_ERR_WRONG_TYPE** `handle` is not a channel handle.
///
/// **ZX_ERR_INVALID_ARGS** `bytes` is an invalid pointer, `handles`
/// is an invalid pointer, or `options` contains an invalid option bit.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_INVALID_ARGS** will be produced if the `buffer` field contains an
/// invalid pointer or if the reserved field is non-zero.
///
/// **ZX_ERR_NOT_SUPPORTED** `handle` was found in the `handles` array.
/// A handle to the channel performing the write cannot be included in the
/// `handles` array. In other words a channel handle cannot be written to its own channel.
/// Fix the error by making sure that `handle` is not in the `handles` array.
///
/// **ZX_ERR_ACCESS_DENIED** `handle` does not have **ZX_RIGHT_WRITE** or
/// any element in `handles` does not have **ZX_RIGHT_TRANSFER**.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel is closed.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_OUT_OF_RANGE** `num_bytes` or `num_handles` are larger than
/// **ZX_CHANNEL_MAX_MSG_BYTES** or **ZX_CHANNEL_MAX_MSG_HANDLES** respectively.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_OUT_OF_RANGE** will be produced if `num_bytes` is larger than
/// **ZX_CHANNEL_MAX_MSG_IOVEC** or the sum of the iovec capacities exceeds
/// **ZX_CHANNEL_MAX_MSG_BYTES**.
///
/// ## Notes
///
/// *num_handles* is a count of the number of elements in the *handles*
/// array, not its size in bytes.
///
/// The byte size limitation on messages is not yet finalized.
///
/// ## See also
///
/// - [`zx_channel_call()`]
/// - [`zx_channel_create()`]
/// - [`zx_channel_read()`]
/// - [`zx_channel_read_etc()`]
/// - [`zx_channel_write_etc()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_read_etc()`]: channel_read_etc.md
/// [`zx_channel_write_etc()`]: channel_write_etc.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
Write(resource struct {
handle handle:CHANNEL;
options uint32;
@voidptr
@size32
bytes vector<byte>;
@release
@size32
handles vector<handle>;
}) -> () error status;
/// ## Summary
///
/// Write a message to a channel.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_write_etc(zx_handle_t handle,
/// uint32_t options,
/// const void* bytes,
/// uint32_t num_bytes,
/// zx_handle_disposition_t* handles,
/// uint32_t num_handles);
/// ```
///
/// ## Description
///
/// Like [`zx_channel_write()`] it attempts to write a message of *num_bytes*
/// bytes and *num_handles* handles to the channel specified by *handle*, but in
/// addition it will perform operations for the handles that are being
/// transferred with *handles* being an array of `zx_handle_disposition_t`:
///
/// ```
/// typedef struct zx_handle_disposition {
/// zx_handle_op_t operation;
/// zx_handle_t handle;
/// zx_obj_type_t type;
/// zx_rights_t rights;
/// zx_status_t result;
/// } zx_handle_disposition_t;
/// ```
/// In zx_handle_disposition_t, *handle* is the source handle to be operated on,
/// *rights* is the desired final rights (not a mask) and *result* must be set
/// to **ZX_OK**. All source handles must have **ZX_RIGHT_TRANSFER**, but
/// it it can be removed in *rights* so that it is not available to the message
/// receiver.
///
/// *type* is used to perform validation of the object type that the caller
/// expects *handle* to be. It can be *ZX_OBJ_TYPE_NONE* to skip validation
/// checks or one of `zx_obj_type_t` defined types.
///
/// The operation applied to *handle* is one of:
///
/// * **ZX_HANDLE_OP_MOVE** This is equivalent to first issuing [`zx_handle_replace()`] then
/// [`zx_channel_write()`]. The source handle is always closed.
///
/// * **ZX_HANDLE_OP_DUPLICATE** This is equivalent to first issuing [`zx_handle_duplicate()`]
/// then [`zx_channel_write()`]. The source handle always remains open and accessible to the
/// caller.
///
/// *handle* will be transferred with capability *rights* which can be **ZX_RIGHT_SAME_RIGHTS**
/// or a reduced set of rights, or **ZX_RIGHT_NONE**. In addition, this operation allows removing
/// **ZX_RIGHT_TRANSFER** in *rights* so that capability is not available for the receiver.
///
/// If any operation fails, the error code for that source handle is written to *result*, and the
/// first failure is made available in the return value for `zx_channel_write_etc()`. All
/// operations in the *handles* array are attempted, even if one or more operations fail.
///
/// All operations for each entry must succeed for the message to be written. On success, handles
/// are attached to the message and will become available to the reader of that message from the
/// opposite end of the channel.
///
/// It is invalid to include *handle* (the handle of the channel being written to) in the
/// *handles* array (the handles being sent in the message).
///
/// The maximum number of handles that may be sent in a message is **ZX_CHANNEL_MAX_MSG_HANDLES**,
/// which is 64.
///
/// The maximum number of bytes that may be sent in a message is **ZX_CHANNEL_MAX_MSG_BYTES**,
/// which is 65536.
///
/// Messages are drained by [`zx_channel_read()`] or [`zx_channel_read_etc()`]. Failure to drain the
/// messages in a timely fashion can cause excessive kernel memory to be used, which might generate an
/// exception. See [ipc limits](/docs/concepts/kernel/ipc_limits.md) for details.
///
/// ### ZX_CHANNEL_WRITE_USE_IOVEC option
///
/// When the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified, `bytes` is
/// interpreted as an array of `zx_channel_iovec_t`, specifying slices of bytes to
/// sequentially copy to the message in order. `num_bytes` specifies the number of
/// `zx_channel_iovec_t` array elements in `bytes`.
///
/// ```c
/// typedef struct zx_channel_iovec {
/// const void* buffer; // User-space bytes.
/// uint32_t capacity; // Number of bytes.
/// uint32_t reserved; // Reserved.
/// } zx_channel_iovec_t;
/// ```
///
/// There can be at most **ZX_CHANNEL_MAX_MSG_IOVEC** or `8192`
/// `zx_channel_iovec_t` elements of the `bytes` array with the sum of `capacity`
/// across all `zx_channel_iovec_t` not exceeding **ZX_CHANNEL_MAX_MSG_BYTES** or
/// `65536` bytes. `buffer` need not be aligned and it may only be `NULL` if
/// `capacity` is zero. `reserved` must be set to zero.
///
/// Either all `zx_channel_iovec_t` are copied and the message is sent, or none
/// are copied and the message is not sent. Usage for sending handles is unchanged.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_WRITE**.
///
/// Every entry of *handles* must have **ZX_RIGHT_TRANSFER**.
///
/// ## Return value
///
/// `zx_channel_write_etc()` returns **ZX_OK** on success.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** *handle* is not a valid handle, any source handle in
/// *handles* is not a valid handle, or there are repeated handles
/// in the *handles* array if **ZX_HANDLE_OP_DUPLICATE** flags is not present.
///
/// **ZX_ERR_WRONG_TYPE** *handle* is not a channel handle, or any source handle
/// in *handles* did not match the object type *type*.
///
/// **ZX_ERR_INVALID_ARGS** *bytes* is an invalid pointer, *handles*
/// is an invalid pointer, or *options* is nonzero, or *operation* is not
/// one of ZX_HANDLE_OP_MOVE or ZX_HANDLE_OP_DUPLICATE, or any source
/// handle in *handles\[i\]->handle* did not have the rights specified in
/// *whandle\[i\]->rights*.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_INVALID_ARGS** will be produced if the *buffer* field contains an
/// invalid pointer or if the reserved field is non-zero.
///
/// **ZX_ERR_NOT_SUPPORTED** *handle* is included in the *handles* array.
///
/// **ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_WRITE** or
/// any source handle in *handles* does not have **ZX_RIGHT_TRANSFER**, or
/// any source handle in *handles* does not have **ZX_RIGHT_DUPLICATE** when
/// **ZX_HANDLE_OP_DUPLICATE** operation is specified.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel is closed.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_OUT_OF_RANGE** *num_bytes* or *num_handles* are larger than
/// **ZX_CHANNEL_MAX_MSG_BYTES** or **ZX_CHANNEL_MAX_MSG_HANDLES** respectively.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_OUT_OF_RANGE** will be produced if *num_bytes* is larger than
/// **ZX_CHANNEL_MAX_MSG_IOVEC** or the sum of the iovec capacities exceeds
/// **ZX_CHANNEL_MAX_MSG_BYTES**.
///
/// ## Notes
///
/// If the caller removes the **ZX_RIGHT_TRANSFER** to a handle attached
/// to a message, the reader of the message will receive a handle that cannot
/// be written to any other channel, but still can be using according to its
/// rights and can be closed if not needed.
///
/// ## See also
///
/// - [`zx_channel_call()`]
/// - [`zx_channel_create()`]
/// - [`zx_channel_read()`]
/// - [`zx_channel_read_etc()`]
/// - [`zx_channel_write()`]
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_read_etc()`]: channel_read_etc.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
WriteEtc(resource struct {
handle handle:CHANNEL;
options uint32;
@voidptr
@size32
bytes vector<byte>;
@inout
@size32
handles vector<HandleDisposition>;
}) -> () error status;
@internal
CallNoretry(resource struct {
handle handle:CHANNEL;
options uint32;
deadline time;
args ChannelCallArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
@internal
CallFinish(resource struct {
deadline time;
args ChannelCallArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
// TODO(scottmg): Express "All wr_handles of args must have ZX_RIGHT_TRANSFER."
/// ## Summary
///
/// Send a message to a channel and await a reply.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_call(zx_handle_t handle,
/// uint32_t options,
/// zx_time_t deadline,
/// const zx_channel_call_args_t* args,
/// uint32_t* actual_bytes,
/// uint32_t* actual_handles);
/// ```
///
/// ## Description
///
/// `zx_channel_call()` is like a combined [`zx_channel_write()`], [`zx_object_wait_one()`],
/// and [`zx_channel_read()`], with the addition of a feature where a transaction id at
/// the front of the message payload *bytes* is used to match reply messages with send
/// messages, enabling multiple calling threads to share a channel without any additional
/// userspace bookkeeping.
///
/// The write and read phases of this operation behave like [`zx_channel_write()`] and
/// [`zx_channel_read()`] with the difference that their parameters are provided via the
/// `zx_channel_call_args_t` structure.
///
/// The first four bytes of the written and read back messages are treated as a
/// transaction ID of type `zx_txid_t`. The kernel generates a txid for the
/// written message, replacing that part of the message as read from userspace.
/// The kernel generated txid will be between 0x80000000 and 0xFFFFFFFF, and will
/// not collide with any txid from any other `zx_channel_call()` in progress against
/// this channel endpoint. If the written message has a length of fewer than four
/// bytes, an error is reported.
///
/// When the outbound message is written, simultaneously an interest is registered
/// for inbound messages of the matching txid.
///
/// *deadline* may be automatically adjusted according to the job's [timer slack]
/// policy.
///
/// While the slack-adjusted *deadline* has not passed, if an inbound message
/// arrives with a matching txid, instead of being added to the tail of the general
/// inbound message queue, it is delivered directly to the thread waiting in
/// `zx_channel_call()`.
///
/// If such a reply arrives after the slack-adjusted *deadline* has passed, it will
/// arrive in the general inbound message queue, cause **ZX_CHANNEL_READABLE** to be
/// signaled, etc.
///
/// Inbound messages that are too large to fit in *rd_num_bytes* and *rd_num_handles*
/// are discarded and **ZX_ERR_BUFFER_TOO_SMALL** is returned in that case.
///
/// As with [`zx_channel_write()`], the handles in *handles* are always consumed by
/// `zx_channel_call()` and no longer exist in the calling process.
///
/// ### ZX_CHANNEL_WRITE_USE_IOVEC option
///
/// When the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified, `wr_bytes` is
/// interpreted as an array of `zx_channel_iovec_t`, specifying slices of bytes to
/// sequentially copy to the message in order. `num_wr_bytes` specifies the number
/// of `zx_channel_iovec_t` array elements in `wr_bytes`.
///
/// ```c
/// typedef struct zx_channel_iovec {
/// const void* buffer; // User-space bytes.
/// uint32_t capacity; // Number of bytes.
/// uint32_t reserved; // Reserved.
/// } zx_channel_iovec_t;
/// ```
///
/// There can be at most **ZX_CHANNEL_MAX_MSG_IOVEC** or `8192`
/// `zx_channel_iovec_t` elements of the `wr_bytes` array with the sum of
/// `capacity` across all `zx_channel_iovec_t` not exceeding
/// **ZX_CHANNEL_MAX_MSG_BYTES** or `65536` bytes. `buffer` need not be aligned and
/// it may only be `NULL` if `capacity` is zero. `reserved` must be set to zero.
///
/// Either all `zx_channel_iovec_t` are copied and the message is sent, or none
/// are copied and the message is not sent. Usage for sending handles is unchanged.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_READ** and have **ZX_RIGHT_WRITE**.
///
/// All wr_handles of *args* must have **ZX_RIGHT_TRANSFER**.
///
/// ## Return value
///
/// `zx_channel_call()` returns **ZX_OK** on success and the number of bytes and
/// count of handles in the reply message are returned via *actual_bytes* and
/// *actual_handles*, respectively.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** *handle* is not a valid handle, any element in
/// *handles* is not a valid handle, or there are duplicates among the handles
/// in the *handles* array.
///
/// **ZX_ERR_WRONG_TYPE** *handle* is not a channel handle.
///
/// **ZX_ERR_INVALID_ARGS** any of the provided pointers are invalid or null,
/// or *wr_num_bytes* is less than four, or *options* is nonzero.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_INVALID_ARGS** will be produced if the *buffer* field contains an
/// invalid pointer or if the reserved field is non-zero.
///
/// **ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_WRITE** or
/// any element in *handles* does not have **ZX_RIGHT_TRANSFER**.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel was closed or became
/// closed while waiting for the reply.
///
/// **ZX_ERR_CANCELED** *handle* was closed while waiting for a reply. TODO(fxbug.dev/34013):
/// Transferring a channel with pending calls currently leads to undefined behavior. With
/// the current implementation, transferring such a channel does not interrupt the
/// pending calls, as it does not close the underlying channel endpoint. Programs should
/// be aware of this behavior, but they **must not** rely on it.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_OUT_OF_RANGE** *wr_num_bytes* or *wr_num_handles* are larger than the
/// largest allowable size for channel messages.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_OUT_OF_RANGE** will be produced if *num_bytes* is larger than
/// **ZX_CHANNEL_MAX_MSG_IOVEC** or the sum of the iovec capacities exceeds
/// **ZX_CHANNEL_MAX_MSG_BYTES**.
///
/// **ZX_ERR_BUFFER_TOO_SMALL** *rd_num_bytes* or *rd_num_handles* are too small
/// to contain the reply message.
///
/// **ZX_ERR_NOT_SUPPORTED** one of the handles in *handles* was *handle*
/// (the handle to the channel being written to).
///
/// ## Notes
///
/// The facilities provided by `zx_channel_call()` can interoperate with message dispatchers
/// using [`zx_channel_read()`] and [`zx_channel_write()`] directly, provided the following rules
/// are observed:
///
/// 1. A server receiving synchronous messages via [`zx_channel_read()`] should ensure that the
/// txid of incoming messages is reflected back in outgoing responses via [`zx_channel_write()`]
/// so that clients using `zx_channel_call()` can correctly route the replies.
///
/// 2. A client sending messages via [`zx_channel_write()`] that will be replied to should ensure
/// that it uses txids between 0 and 0x7FFFFFFF only, to avoid colliding with other threads
/// communicating via `zx_channel_call()`.
///
/// If a `zx_channel_call()` returns due to **ZX_ERR_TIMED_OUT**, if the server eventually replies,
/// at some point in the future, the reply *could* match another outbound request (provided about
/// 2^31 `zx_channel_call()`s have happened since the original request. This syscall is designed
/// around the expectation that timeouts are generally fatal and clients do not expect to continue
/// communications on a channel that is timing out.
///
/// ## See also
///
/// - [timer slack]
/// - [`zx_channel_create()`]
/// - [`zx_channel_read()`]
/// - [`zx_channel_write()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
///
/// [timer slack]: /docs/concepts/kernel/timer_slack.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
@blocking
@vdsocall
Call(resource struct {
handle handle:CHANNEL;
options uint32;
deadline time;
args ChannelCallArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
@internal
CallEtcNoretry(resource struct {
handle handle:CHANNEL;
options uint32;
deadline time;
@inout
args ChannelCallEtcArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
@internal
CallEtcFinish(resource struct {
deadline time;
@inout
args ChannelCallEtcArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
/// ## Summary
///
/// Send a message to a channel and await a reply.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_channel_call_etc(zx_handle_t handle,
/// uint32_t options,
/// zx_time_t deadline,
/// zx_channel_call_etc_args_t* args,
/// uint32_t* actual_bytes,
/// uint32_t* actual_handles);
/// ```
///
/// ## Description
///
/// `zx_channel_call_etc()` writes a request to a channel and blocks until it
/// receives a response. It is an extension of [`zx_channel_call()`] that
/// incorporates the functionality of [`zx_channel_write_etc()`] and
/// [`zx_channel_read_etc()`] for write and read phases, instead of the more basic
/// [`zx_channel_write()`] and [`zx_channel_read()`]. See [`zx_channel_call()`] for
/// a full description of channel calls.
///
/// The effect of a call to `zx_channel_call_etc()` is similar to performing a
/// sequence of calls to [`zx_channel_write_etc()`], [`zx_object_wait_one()`] and
/// [`zx_channel_read_etc()`] in that order. However, a key difference is that
/// `zx_channel_call_etc()` will wait for an incoming message matches the outgoing
/// message's transaction id. The arguments that would be supplied to
/// `zx_channel_read_etc()` and `zx_channel_write_etc()` are instead specified with
/// `zx_channel_call_etc_args_t`:
///
/// ```
/// typedef struct {
/// const void* wr_bytes;
/// zx_handle_disposition_t* wr_handles;
/// void *rd_bytes;
/// zx_handle_info_t* rd_handles;
/// uint32_t wr_num_bytes;
/// uint32_t wr_num_handles;
/// uint32_t rd_num_bytes;
/// uint32_t rd_num_handles;
/// } zx_channel_call_etc_args_t;
/// ```
///
/// ### ZX_CHANNEL_WRITE_USE_IOVEC option
///
/// When the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified, `wr_bytes` is
/// interpreted as an array of `zx_channel_iovec_t`, specifying slices of bytes to
/// sequentially copy to the message in order. `num_wr_bytes` specifies the number
/// of `zx_channel_iovec_t` array elements in `wr_bytes`.
///
/// ```c
/// typedef struct zx_channel_iovec {
/// const void* buffer; // User-space bytes.
/// uint32_t capacity; // Number of bytes.
/// uint32_t reserved; // Reserved.
/// } zx_channel_iovec_t;
/// ```
///
/// There can be at most **ZX_CHANNEL_MAX_MSG_IOVEC** or `8192`
/// `zx_channel_iovec_t` elements of the `wr_bytes` array with the sum of
/// `capacity` across all `zx_channel_iovec_t` not exceeding
/// **ZX_CHANNEL_MAX_MSG_BYTES** or `65536` bytes. `buffer` need not be aligned and
/// it may only be `NULL` if `capacity` is zero. `reserved` must be set to zero.
///
/// Either all `zx_channel_iovec_t` are copied and the message is sent, or none
/// are copied and the message is not sent. Usage for sending handles is unchanged.
///
/// ## Rights
///
/// *handle* must be of type **ZX_OBJ_TYPE_CHANNEL** and have **ZX_RIGHT_READ** and have **ZX_RIGHT_WRITE**.
///
/// All wr_handles of *args* must have **ZX_RIGHT_TRANSFER**.
///
/// ## Return value
///
/// `zx_channel_call_etc()` returns **ZX_OK** on success and the number of bytes and
/// count of handles in the reply message are returned via *actual_bytes* and
/// *actual_handles*, respectively.
///
/// ## Errors
///
/// **ZX_ERR_BAD_HANDLE** *handle* is not a valid handle, any element in
/// *handles* is not a valid handle, or there are duplicates among the handles
/// in the *handles* array.
///
/// **ZX_ERR_WRONG_TYPE** *handle* is not a channel handle, or any source
/// handle in *wr_handles* did not match the object type type.
///
/// **ZX_ERR_INVALID_ARGS** any of the provided pointers are invalid or null,
/// or *wr_num_bytes* is less than four, or *options* is nonzero, or any source
/// handle in *wr_handles\[i\]->handle* did not have the rights specified in
/// *wr_handle\[i\]->rights*.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_INVALID_ARGS** will be produced if the *buffer* field contains an
/// invalid pointer or if the reserved field is non-zero.
///
/// **ZX_ERR_ACCESS_DENIED** *handle* does not have **ZX_RIGHT_WRITE** or
/// any element in *handles* does not have **ZX_RIGHT_TRANSFER**.
///
/// **ZX_ERR_PEER_CLOSED** The other side of the channel was closed or became
/// closed while waiting for the reply.
///
/// **ZX_ERR_CANCELED** *handle* was closed while waiting for a reply. TODO(fxbug.dev/34013):
/// Transferring a channel with pending calls currently leads to undefined behavior. With
/// the current implementation, transferring such a channel does not interrupt the
/// pending calls, as it does not close the underlying channel endpoint. Programs should
/// be aware of this behavior, but they **must not** rely on it.
///
/// **ZX_ERR_NO_MEMORY** Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// **ZX_ERR_OUT_OF_RANGE** *wr_num_bytes* or *wr_num_handles* are larger than the
/// largest allowable size for channel messages.
/// If the **ZX_CHANNEL_WRITE_USE_IOVEC** option is specified,
/// **ZX_ERR_OUT_OF_RANGE** will be produced if *num_bytes* is larger than
/// **ZX_CHANNEL_MAX_MSG_IOVEC** or the sum of the iovec capacities exceeds
/// **ZX_CHANNEL_MAX_MSG_BYTES**.
///
/// **ZX_ERR_BUFFER_TOO_SMALL** *rd_num_bytes* or *rd_num_handles* are too small
/// to contain the reply message.
///
/// **ZX_ERR_NOT_SUPPORTED** one of the handles in *handles* was *handle*
/// (the handle to the channel being written to).
///
/// [`zx_channel_call()`]: channel_call.md
/// [`zx_channel_create()`]: channel_create.md
/// [`zx_channel_read()`]: channel_read.md
/// [`zx_channel_read_etc()`]: channel_read_etc.md
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_channel_write_etc()`]: channel_write_etc.md
/// [`zx_object_wait_one()`]: object_wait_one.md
@blocking
@vdsocall
// TODO(scottmg): Express "All wr_handles of args must have ZX_RIGHT_TRANSFER."
CallEtc(resource struct {
handle handle:CHANNEL;
options uint32;
deadline time;
@inout
args ChannelCallEtcArgs;
}) -> (struct {
actual_bytes uint32;
actual_handles uint32;
}) error status;
};