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