1 // Copyright 2018 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 #include <fs/handler.h>
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <fuchsia/io/c/fidl.h>
10 #include <zircon/assert.h>
11 #include <zircon/syscalls.h>
12 #include <zircon/types.h>
13 
14 namespace fs {
15 namespace {
16 
Reply(fidl_txn_t * txn,const fidl_msg_t * msg)17 zx_status_t Reply(fidl_txn_t* txn, const fidl_msg_t* msg) {
18     auto connection = FidlConnection::FromTxn(txn);
19     auto header = reinterpret_cast<fidl_message_header_t*>(msg->bytes);
20     header->txid = connection->Txid();
21     return zx_channel_write(connection->Channel(), 0, msg->bytes, msg->num_bytes,
22                             msg->handles, msg->num_handles);
23 };
24 
25 // Don't actually send anything on a channel when completing this operation.
26 // This is useful for mocking out "close" requests.
NullReply(fidl_txn_t * reply,const fidl_msg_t * msg)27 zx_status_t NullReply(fidl_txn_t* reply, const fidl_msg_t* msg) {
28     return ZX_OK;
29 }
30 
31 } // namespace
32 
ReadMessage(zx_handle_t h,FidlDispatchFunction dispatch)33 zx_status_t ReadMessage(zx_handle_t h, FidlDispatchFunction dispatch) {
34     ZX_ASSERT(zx_object_get_info(h, ZX_INFO_HANDLE_VALID, NULL, 0,
35                                  NULL, NULL) == ZX_OK);
36     uint8_t bytes[ZXFIDL_MAX_MSG_BYTES];
37     zx_handle_t handles[ZXFIDL_MAX_MSG_HANDLES];
38     fidl_msg_t msg = {
39         .bytes = bytes,
40         .handles = handles,
41         .num_bytes = 0,
42         .num_handles = 0,
43     };
44 
45     zx_status_t r = zx_channel_read(h, 0, bytes, handles, countof(bytes),
46                                     countof(handles), &msg.num_bytes,
47                                     &msg.num_handles);
48     if (r != ZX_OK) {
49         return r;
50     }
51 
52     if (msg.num_bytes < sizeof(fidl_message_header_t)) {
53         zx_handle_close_many(msg.handles, msg.num_handles);
54         return ZX_ERR_IO;
55     }
56 
57     auto header = reinterpret_cast<fidl_message_header_t*>(msg.bytes);
58     fidl_txn_t txn = {
59         .reply = Reply,
60     };
61     FidlConnection connection(std::move(txn), h, header->txid);
62 
63     // Callback is responsible for decoding the message, and closing
64     // any associated handles.
65     return dispatch(&msg, &connection);
66 }
67 
CloseMessage(FidlDispatchFunction dispatch)68 zx_status_t CloseMessage(FidlDispatchFunction dispatch) {
69     fuchsia_io_NodeCloseRequest request;
70     memset(&request, 0, sizeof(request));
71     request.hdr.ordinal = fuchsia_io_NodeCloseOrdinal;
72     fidl_msg_t msg = {
73         .bytes = &request,
74         .handles = NULL,
75         .num_bytes = sizeof(request),
76         .num_handles = 0u,
77     };
78 
79     fidl_txn_t txn = {
80         .reply = NullReply,
81     };
82     FidlConnection connection(std::move(txn), ZX_HANDLE_INVALID, 0);
83 
84     // Remote side was closed.
85     dispatch(&msg, &connection);
86     return ERR_DISPATCHER_DONE;
87 }
88 
89 } // namespace fs
90