blob: 22dbff42920f74bcb9d8e680617ee5a9e2ecf9d7 [file] [log] [blame]
// Copyright 2016 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.
#pragma once
#include <lib/fdio/limits.h>
#include <stdint.h>
#include <type_traits>
#include <fbl/function.h>
#include <zircon/compiler.h>
#include <zircon/fidl.h>
#include <zircon/types.h>
// Fuchsia-io limits.
//
// TODO(FIDL-127): Compute these values with the "union of all fuchsia-io"
// messages.
#define ZXFIDL_MAX_MSG_BYTES (FDIO_CHUNK_SIZE * 2)
#define ZXFIDL_MAX_MSG_HANDLES (16)
// indicates the callback is taking responsibility for the
// channel receiving incoming messages.
//
// Unlike ERR_DISPATCHER_INDIRECT, this callback is propagated
// through ReadMessage.
#define ERR_DISPATCHER_ASYNC ZX_ERR_ASYNC
// indicates that this was a close message and that no further
// callbacks should be made to the dispatcher
#define ERR_DISPATCHER_DONE ZX_ERR_STOP
namespace fs {
// FidlConnection contains enough context to respond to a FIDL message.
//
// It contains both the underlying fidl transaction, as well as the channel and txid,
// which are necessary for responding to fidl messages.
class FidlConnection {
public:
// TODO(smklein): convert channel to a zx::unowned_channel.
FidlConnection(fidl_txn_t txn, zx_handle_t channel, zx_txid_t txid)
: txn_(std::move(txn)), channel_(std::move(channel)), txid_(std::move(txid)) {}
fidl_txn_t* Txn() {
return &txn_;
}
zx_txid_t Txid() const {
return txid_;
}
zx_handle_t Channel() const {
return channel_;
}
// Utilizes a |fidl_txn_t| object as a wrapped FidlConnection.
//
// Only safe to call if |txn| was previously returned by |FidlConnection.Txn()|.
static const FidlConnection* FromTxn(const fidl_txn_t* txn);
// Copies txn into a new FidlConnection.
//
// This may be useful for copying a FidlConnection out of stack-allocated scope,
// so a response may be generated asynchronously.
//
// Only safe to call if |txn| was previously returned by |FidlConnection.Txn()|.
static FidlConnection CopyTxn(const fidl_txn_t* txn);
private:
fidl_txn_t txn_;
zx_handle_t channel_;
zx_txid_t txid_;
};
inline const FidlConnection* FidlConnection::FromTxn(const fidl_txn_t* txn) {
static_assert(std::is_standard_layout<FidlConnection>::value,
"Cannot cast from non-standard layout class");
static_assert(offsetof(FidlConnection, txn_) == 0,
"FidlConnection must be convertable to txn");
return reinterpret_cast<const FidlConnection*>(txn);
}
inline FidlConnection FidlConnection::CopyTxn(const fidl_txn_t* txn) {
static_assert(std::is_trivially_copyable<FidlConnection>::value, "Cannot trivially copy");
return *FromTxn(txn);
}
// callback to process a FIDL message.
// - |msg| is a decoded FIDL message.
// - return value of ERR_DISPATCHER_{INDIRECT,ASYNC} indicates that the reply is
// being handled by the callback (forwarded to another server, sent later,
// etc, and no reply message should be sent).
// - WARNING: Once this callback returns, usage of |msg| is no longer
// valid. If a client transmits ERR_DISPATCHER_{INDIRECT,ASYNC}, and intends
// to respond asynchronously, they must copy the fields of |msg| they
// wish to use at a later point in time.
// - otherwise, the return value is treated as the status to send
// in the rpc response, and msg.len indicates how much valid data
// to send. On error return msg.len will be set to 0.
using FidlDispatchFunction = fbl::Function<zx_status_t(fidl_msg_t* msg, FidlConnection* txn)>;
// Attempts to read and dispatch a FIDL message.
//
// If a message cannot be read, returns an error instead of blocking.
zx_status_t ReadMessage(zx_handle_t h, FidlDispatchFunction dispatch);
// Synthesizes a FIDL close message.
//
// This may be invoked when a channel is closed, to simulate dispatching
// to the same close function.
zx_status_t CloseMessage(FidlDispatchFunction dispatch);
} // namespace fs