fdomain_client/
responder.rs

1// Copyright 2024 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
5use crate::{ordinals, Error};
6use fidl_fuchsia_fdomain as proto;
7use futures::channel::oneshot::Sender;
8
9/// Sum type over oneshot senders which carry the responses to FDomain FIDL
10/// requests back to the requesting code.
11///
12/// A couple of the variants also carry the HID the original operation was
13/// performed on. This is used when we get a write error in response to those
14/// operations and need to clear it by sending an AcknowledgeWriteError message.
15pub(crate) enum Responder {
16    Namespace(Sender<Result<(), Error>>),
17    CreateChannel(Sender<Result<(), Error>>),
18    CreateSocket(Sender<Result<(), Error>>),
19    CreateEventPair(Sender<Result<(), Error>>),
20    CreateEvent(Sender<Result<(), Error>>),
21    SetSocketDisposition(Sender<Result<(), Error>>),
22    WriteSocket(Sender<Result<proto::SocketWriteSocketResponse, Error>>),
23    WriteChannel(Sender<Result<(), Error>>),
24    Close(Sender<Result<(), Error>>),
25    Duplicate(Sender<Result<(), Error>>),
26    Replace(Sender<Result<(), Error>>),
27    Signal(Sender<Result<(), Error>>),
28    SignalPeer(Sender<Result<(), Error>>),
29    WaitForSignals(Sender<Result<proto::FDomainWaitForSignalsResponse, Error>>),
30
31    // Read channel/socket is a little different. We just need the handle ID as we're
32    // going to ask the client to handle the transaction for us.
33    ReadChannel(proto::HandleId),
34    ReadSocket(proto::HandleId),
35
36    // We always use the Ignore variant for these, but implementation is here
37    // for posterity.
38    _ReadChannelStreamingStart(Sender<Result<(), Error>>),
39    _ReadChannelStreamingStop(Sender<Result<(), Error>>),
40    _ReadSocketStreamingStart(Sender<Result<(), Error>>),
41    _ReadSocketStreamingStop(Sender<Result<(), Error>>),
42
43    /// Used when we want to ignore the reply to a request.
44    Ignore,
45}
46
47impl Responder {
48    /// Feed this responder a still-encoded FIDL request.
49    pub(crate) fn handle(
50        self,
51        client_inner: &mut crate::ClientInner,
52        result: Result<(fidl_message::TransactionHeader, &[u8]), crate::InnerError>,
53    ) -> fidl::Result<()> {
54        match self {
55            Responder::Namespace(sender) => {
56                Responder::dispatch_handle("namespace", ordinals::GET_NAMESPACE, sender, result)
57            }
58            Responder::CreateChannel(sender) => Responder::dispatch_handle(
59                "create_channel",
60                ordinals::CREATE_CHANNEL,
61                sender,
62                result,
63            ),
64            Responder::CreateSocket(sender) => {
65                Responder::dispatch_handle("create_socket", ordinals::CREATE_SOCKET, sender, result)
66            }
67            Responder::CreateEventPair(sender) => Responder::dispatch_handle(
68                "create_event_pair",
69                ordinals::CREATE_EVENT_PAIR,
70                sender,
71                result,
72            ),
73            Responder::CreateEvent(sender) => {
74                Responder::dispatch_handle("create_event", ordinals::CREATE_EVENT, sender, result)
75            }
76            Responder::SetSocketDisposition(sender) => Responder::dispatch_handle(
77                "set_socket_disposition",
78                ordinals::SET_SOCKET_DISPOSITION,
79                sender,
80                result,
81            ),
82            Responder::ReadSocket(id) => {
83                Responder::dispatch_handle_etc::<proto::SocketData, proto::Error>(
84                    "read_channel",
85                    ordinals::READ_SOCKET,
86                    move |msg| {
87                        client_inner.handle_socket_read_response(msg, id);
88                    },
89                    result,
90                )
91            }
92            Responder::ReadChannel(id) => Responder::dispatch_handle_etc::<_, proto::Error>(
93                "read_channel",
94                ordinals::READ_CHANNEL,
95                move |msg| {
96                    client_inner.handle_channel_read_response(msg, id);
97                },
98                result,
99            ),
100            Responder::WriteSocket(sender) => {
101                Responder::dispatch_handle_etc::<_, proto::WriteSocketError>(
102                    "write_socket",
103                    ordinals::WRITE_SOCKET,
104                    move |m| {
105                        let _ = sender.send(m);
106                    },
107                    result,
108                )
109            }
110            Responder::WriteChannel(sender) => {
111                Responder::dispatch_handle_etc::<_, proto::WriteChannelError>(
112                    "write_channel",
113                    ordinals::WRITE_CHANNEL,
114                    move |m| {
115                        let _ = sender.send(m);
116                    },
117                    result,
118                )
119            }
120            Responder::WaitForSignals(sender) => Responder::dispatch_handle(
121                "wait_for_signals",
122                ordinals::WAIT_FOR_SIGNALS,
123                sender,
124                result,
125            ),
126            Responder::Close(sender) => {
127                Responder::dispatch_handle("close", ordinals::CLOSE, sender, result)
128            }
129            Responder::Duplicate(sender) => {
130                Responder::dispatch_handle("duplicate", ordinals::DUPLICATE, sender, result)
131            }
132            Responder::Replace(sender) => {
133                Responder::dispatch_handle("replace", ordinals::REPLACE, sender, result)
134            }
135            Responder::Signal(sender) => {
136                Responder::dispatch_handle("signal", ordinals::SIGNAL, sender, result)
137            }
138            Responder::SignalPeer(sender) => {
139                Responder::dispatch_handle("signal_peer", ordinals::SIGNAL_PEER, sender, result)
140            }
141            Responder::_ReadChannelStreamingStart(sender) => Responder::dispatch_handle(
142                "read_channel_streaming_start",
143                ordinals::READ_CHANNEL_STREAMING_START,
144                sender,
145                result,
146            ),
147            Responder::_ReadChannelStreamingStop(sender) => Responder::dispatch_handle(
148                "read_channel_streaming_stop",
149                ordinals::READ_CHANNEL_STREAMING_STOP,
150                sender,
151                result,
152            ),
153            Responder::_ReadSocketStreamingStart(sender) => Responder::dispatch_handle(
154                "read_socket_streaming_start",
155                ordinals::READ_SOCKET_STREAMING_START,
156                sender,
157                result,
158            ),
159            Responder::_ReadSocketStreamingStop(sender) => Responder::dispatch_handle(
160                "read_socket_streaming_stop",
161                ordinals::READ_SOCKET_STREAMING_STOP,
162                sender,
163                result,
164            ),
165            Responder::Ignore => Ok(()),
166        }
167    }
168
169    /// Complete the `handle` method for a `Responder`. Does not take the
170    /// responder itself; when this is called the responder has been unwrapped,
171    /// and the type arguments to this method encode what was learned from the
172    /// variant.
173    fn dispatch_handle<R: fidl_message::Body>(
174        method_name: &'static str,
175        ordinal: u64,
176        sender: Sender<Result<R, Error>>,
177        result: Result<(fidl_message::TransactionHeader, &[u8]), crate::InnerError>,
178    ) -> fidl::Result<()> {
179        Self::dispatch_handle_etc::<R, proto::Error>(
180            method_name,
181            ordinal,
182            move |m| {
183                let _ = sender.send(m);
184            },
185            result,
186        )
187    }
188
189    /// Same as `dispatch_handle` except the error type is generic, whereas it
190    /// may only be `proto::Error` for `dispatch_handle`.
191    fn dispatch_handle_etc<R: fidl_message::Body, S: Into<Error> + fidl_message::ErrorType>(
192        method_name: &'static str,
193        ordinal: u64,
194        send_fn: impl FnOnce(Result<R, Error>),
195        result: Result<(fidl_message::TransactionHeader, &[u8]), crate::InnerError>,
196    ) -> fidl::Result<()> {
197        match result {
198            Ok((header, body)) => {
199                if header.ordinal != ordinal {
200                    return Err(fidl::Error::InvalidResponseTxid);
201                }
202                let (res, ret) = match fidl_message::decode_response_flexible_result::<R, S>(
203                    header, body,
204                ) {
205                    Ok(fidl_message::MaybeUnknown::Known(x)) => {
206                        (x.map_err(Into::into), Ok(()))
207                    },
208                    Ok(fidl_message::MaybeUnknown::Unknown) => {
209                        (Err(Error::Protocol(fidl::Error::UnsupportedMethod {
210                            method_name,
211                            protocol_name:
212                            <proto::FDomainMarker as fidl::endpoints::ProtocolMarker>::DEBUG_NAME
213                        })), Ok(()))
214                    }
215                    Err(e) => {
216                        (Err(Error::Protocol(e.clone())), Err(e))
217                    }
218                };
219                send_fn(res);
220                ret
221            }
222            Err(e) => {
223                send_fn(Err(e.into()));
224                Ok(())
225            }
226        }
227    }
228}