1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <lib/fdio/limits.h>
8 #include <stdint.h>
9
10 #include <type_traits>
11
12 #include <fbl/function.h>
13 #include <zircon/compiler.h>
14 #include <zircon/fidl.h>
15 #include <zircon/types.h>
16
17 // Fuchsia-io limits.
18 //
19 // TODO(FIDL-127): Compute these values with the "union of all fuchsia-io"
20 // messages.
21 #define ZXFIDL_MAX_MSG_BYTES (FDIO_CHUNK_SIZE * 2)
22 #define ZXFIDL_MAX_MSG_HANDLES (16)
23
24 // indicates the callback is taking responsibility for the
25 // channel receiving incoming messages.
26 //
27 // Unlike ERR_DISPATCHER_INDIRECT, this callback is propagated
28 // through ReadMessage.
29 #define ERR_DISPATCHER_ASYNC ZX_ERR_ASYNC
30
31 // indicates that this was a close message and that no further
32 // callbacks should be made to the dispatcher
33 #define ERR_DISPATCHER_DONE ZX_ERR_STOP
34
35 namespace fs {
36
37 // FidlConnection contains enough context to respond to a FIDL message.
38 //
39 // It contains both the underlying fidl transaction, as well as the channel and txid,
40 // which are necessary for responding to fidl messages.
41 class FidlConnection {
42 public:
43 // TODO(smklein): convert channel to a zx::unowned_channel.
FidlConnection(fidl_txn_t txn,zx_handle_t channel,zx_txid_t txid)44 FidlConnection(fidl_txn_t txn, zx_handle_t channel, zx_txid_t txid)
45 : txn_(std::move(txn)), channel_(std::move(channel)), txid_(std::move(txid)) {}
46
Txn()47 fidl_txn_t* Txn() {
48 return &txn_;
49 }
50
Txid()51 zx_txid_t Txid() const {
52 return txid_;
53 }
54
Channel()55 zx_handle_t Channel() const {
56 return channel_;
57 }
58
59 // Utilizes a |fidl_txn_t| object as a wrapped FidlConnection.
60 //
61 // Only safe to call if |txn| was previously returned by |FidlConnection.Txn()|.
62 static const FidlConnection* FromTxn(const fidl_txn_t* txn);
63
64 // Copies txn into a new FidlConnection.
65 //
66 // This may be useful for copying a FidlConnection out of stack-allocated scope,
67 // so a response may be generated asynchronously.
68 //
69 // Only safe to call if |txn| was previously returned by |FidlConnection.Txn()|.
70 static FidlConnection CopyTxn(const fidl_txn_t* txn);
71
72 private:
73 fidl_txn_t txn_;
74 zx_handle_t channel_;
75 zx_txid_t txid_;
76 };
77
FromTxn(const fidl_txn_t * txn)78 inline const FidlConnection* FidlConnection::FromTxn(const fidl_txn_t* txn) {
79 static_assert(std::is_standard_layout<FidlConnection>::value,
80 "Cannot cast from non-standard layout class");
81 static_assert(offsetof(FidlConnection, txn_) == 0,
82 "FidlConnection must be convertable to txn");
83 return reinterpret_cast<const FidlConnection*>(txn);
84 }
85
CopyTxn(const fidl_txn_t * txn)86 inline FidlConnection FidlConnection::CopyTxn(const fidl_txn_t* txn) {
87 static_assert(std::is_trivially_copyable<FidlConnection>::value, "Cannot trivially copy");
88 return *FromTxn(txn);
89 }
90
91 // callback to process a FIDL message.
92 // - |msg| is a decoded FIDL message.
93 // - return value of ERR_DISPATCHER_{INDIRECT,ASYNC} indicates that the reply is
94 // being handled by the callback (forwarded to another server, sent later,
95 // etc, and no reply message should be sent).
96 // - WARNING: Once this callback returns, usage of |msg| is no longer
97 // valid. If a client transmits ERR_DISPATCHER_{INDIRECT,ASYNC}, and intends
98 // to respond asynchronously, they must copy the fields of |msg| they
99 // wish to use at a later point in time.
100 // - otherwise, the return value is treated as the status to send
101 // in the rpc response, and msg.len indicates how much valid data
102 // to send. On error return msg.len will be set to 0.
103 using FidlDispatchFunction = fbl::Function<zx_status_t(fidl_msg_t* msg, FidlConnection* txn)>;
104
105 // Attempts to read and dispatch a FIDL message.
106 //
107 // If a message cannot be read, returns an error instead of blocking.
108 zx_status_t ReadMessage(zx_handle_t h, FidlDispatchFunction dispatch);
109
110 // Synthesizes a FIDL close message.
111 //
112 // This may be invoked when a channel is closed, to simulate dispatching
113 // to the same close function.
114 zx_status_t CloseMessage(FidlDispatchFunction dispatch);
115
116 } // namespace fs
117