| # zx_channel_call | 
 |  | 
 | ## NAME | 
 |  | 
 | <!-- Contents of this heading updated by update-docs-from-fidl, do not edit. --> | 
 |  | 
 | Send a message to a channel and await a reply. | 
 |  | 
 | ## SYNOPSIS | 
 |  | 
 | <!-- Contents of this heading updated by update-docs-from-fidl, do not edit. --> | 
 |  | 
 | ```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 | 
 |  | 
 | <!-- Contents of this heading updated by update-docs-from-fidl, do not edit. --> | 
 |  | 
 | *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()`] | 
 |  | 
 | <!-- References updated by update-docs-from-fidl, do not edit. --> | 
 |  | 
 | [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 |