fdomain_client/fidl_next/
codec.rs

1// Copyright 2025 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 super::wire_handle::WireHandle;
6use crate::responder::Responder;
7use crate::{AsHandleRef, Channel, ChannelMessageStream, ChannelWriter, Error, Handle};
8use fidl_fuchsia_fdomain as proto;
9use fidl_next_codec::decoder::InternalHandleDecoder;
10use fidl_next_codec::encoder::InternalHandleEncoder;
11use fidl_next_codec::{CHUNK_SIZE, Chunk, DecodeError, Decoder, EncodeError, Encoder};
12use fidl_next_protocol::Transport;
13use futures::channel::oneshot;
14use futures::{FutureExt, StreamExt};
15
16use std::pin::Pin;
17use std::ptr::NonNull;
18use std::task::{Context, Poll, ready};
19
20/// A decoder which supports FDomain handles.
21pub trait HandleDecoder {
22    /// Takes the next raw handle from the decoder.
23    ///
24    /// The returned raw handle must not be considered owned until the decoder is committed.
25    fn take_raw_handle(&mut self) -> Result<u32, DecodeError>;
26
27    /// Returns the number of handles remaining in the decoder.
28    fn handles_remaining(&mut self) -> usize;
29}
30
31/// An encoder which supports FDomain handles.
32pub trait HandleEncoder {
33    /// Pushes a handle into the encoder.
34    fn push_handle(&mut self, handle: Handle) -> Result<(), EncodeError>;
35
36    /// Returns the number of handles added to the encoder.
37    fn handles_pushed(&self) -> usize;
38}
39
40/// Send buffer for an FDomain channel.
41#[derive(Default)]
42pub struct SendBuffer {
43    handles: Vec<Handle>,
44    chunks: Vec<Chunk>,
45}
46
47impl SendBuffer {
48    /// New buffer.
49    pub fn new() -> Self {
50        Self::default()
51    }
52
53    /// Retrieve the handles.
54    pub fn handles(&self) -> &[Handle] {
55        &self.handles
56    }
57}
58
59impl InternalHandleEncoder for SendBuffer {
60    #[inline]
61    fn __internal_handle_count(&self) -> usize {
62        self.handles.len()
63    }
64}
65
66impl Encoder for SendBuffer {
67    #[inline]
68    fn bytes_written(&self) -> usize {
69        Encoder::bytes_written(&self.chunks)
70    }
71
72    #[inline]
73    fn write_zeroes(&mut self, len: usize) {
74        Encoder::write_zeroes(&mut self.chunks, len)
75    }
76
77    #[inline]
78    fn write(&mut self, bytes: &[u8]) {
79        Encoder::write(&mut self.chunks, bytes)
80    }
81
82    #[inline]
83    fn rewrite(&mut self, pos: usize, bytes: &[u8]) {
84        Encoder::rewrite(&mut self.chunks, pos, bytes)
85    }
86}
87
88impl HandleEncoder for SendBuffer {
89    fn push_handle(&mut self, handle: Handle) -> Result<(), EncodeError> {
90        self.handles.push(handle.into());
91        Ok(())
92    }
93
94    fn handles_pushed(&self) -> usize {
95        self.handles.len()
96    }
97}
98
99/// A receive buffer for an FDomain channel.
100pub struct RecvBuffer {
101    handles: Vec<WireHandle>,
102    chunks: Vec<Chunk>,
103    chunks_taken: usize,
104    handles_taken: usize,
105}
106
107unsafe impl Decoder for RecvBuffer {
108    fn take_chunks_raw(&mut self, count: usize) -> Result<NonNull<Chunk>, DecodeError> {
109        if count > self.chunks.len() - self.chunks_taken {
110            return Err(DecodeError::InsufficientData);
111        }
112
113        let chunks = unsafe { self.chunks.as_mut_ptr().add(self.chunks_taken) };
114        self.chunks_taken += count;
115
116        unsafe { Ok(NonNull::new_unchecked(chunks)) }
117    }
118
119    fn commit(&mut self) {
120        for handle in &mut self.handles[0..self.handles_taken] {
121            handle.invalidate();
122        }
123    }
124
125    fn finish(&self) -> Result<(), DecodeError> {
126        if self.chunks_taken != self.chunks.len() {
127            return Err(DecodeError::ExtraBytes {
128                num_extra: (self.chunks.len() - self.chunks_taken) * CHUNK_SIZE,
129            });
130        }
131
132        if self.handles_taken != self.handles.len() {
133            return Err(DecodeError::ExtraHandles {
134                num_extra: self.handles.len() - self.handles_taken,
135            });
136        }
137
138        Ok(())
139    }
140}
141
142impl InternalHandleDecoder for RecvBuffer {
143    fn __internal_take_handles(&mut self, count: usize) -> Result<(), DecodeError> {
144        if count > self.handles.len() - self.handles_taken {
145            return Err(DecodeError::InsufficientHandles);
146        }
147
148        for i in self.handles_taken..self.handles_taken + count {
149            drop(self.handles[i].take_handle());
150        }
151        self.handles_taken += count;
152
153        Ok(())
154    }
155
156    fn __internal_handles_remaining(&self) -> usize {
157        self.handles.len() - self.handles_taken
158    }
159}
160
161impl HandleDecoder for RecvBuffer {
162    fn take_raw_handle(&mut self) -> Result<u32, DecodeError> {
163        if self.handles_taken >= self.handles.len() {
164            return Err(DecodeError::InsufficientHandles);
165        }
166
167        let handle = self.handles[self.handles_taken].as_raw_handle();
168        self.handles_taken += 1;
169
170        Ok(handle)
171    }
172
173    fn handles_remaining(&mut self) -> usize {
174        self.handles.len() - self.handles_taken
175    }
176}
177
178/// Sender for an FDomain channel.
179#[derive(Clone)]
180pub struct Shared {
181    writer: ChannelWriter,
182}
183
184/// The state for a channel send future.
185pub enum SendFutureState {
186    /// The message was too big to fit in a channel.
187    BadGeometry,
188    Wait(oneshot::Receiver<Result<(), Error>>),
189}
190
191/// A channel receiver.
192pub struct Exclusive {
193    stream: ChannelMessageStream,
194}
195
196impl Transport for Channel {
197    type Error = Error;
198
199    fn split(self) -> (Self::Shared, Self::Exclusive) {
200        let (stream, writer) = self.stream().expect("could not split channel");
201        (Shared { writer }, Exclusive { stream })
202    }
203
204    type Shared = Shared;
205    type SendBuffer = SendBuffer;
206    type SendFutureState = SendFutureState;
207
208    fn acquire(_: &Self::Shared) -> Self::SendBuffer {
209        SendBuffer::new()
210    }
211
212    fn begin_send(sender: &Self::Shared, buffer: Self::SendBuffer) -> Self::SendFutureState {
213        let client = sender.writer.as_channel().as_handle_ref().client();
214        let handle = sender.writer.as_channel().as_handle_ref().proto();
215        let data = buffer.chunks;
216        let handles = buffer.handles;
217
218        // SAFETY: It should be safe to byte-cast from chunks always.
219        let data = unsafe {
220            std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * CHUNK_SIZE).to_vec()
221        };
222
223        if data.len() > zx_types::ZX_CHANNEL_MAX_MSG_BYTES as usize
224            || handles.len() > zx_types::ZX_CHANNEL_MAX_MSG_HANDLES as usize
225        {
226            SendFutureState::BadGeometry
227        } else {
228            let handles =
229                proto::Handles::Handles(handles.into_iter().map(|x| x.take_proto()).collect());
230            let (sender, receiver) = oneshot::channel();
231            let mut client = client.0.lock().unwrap();
232            client.request(
233                crate::ordinals::WRITE_CHANNEL,
234                proto::ChannelWriteChannelRequest { handle, data, handles },
235                Responder::WriteChannel(sender),
236            );
237
238            SendFutureState::Wait(receiver)
239        }
240    }
241
242    fn poll_send(
243        mut future_state: Pin<&mut Self::SendFutureState>,
244        ctx: &mut Context<'_>,
245        _: &Self::Shared,
246    ) -> Poll<Result<(), Option<Self::Error>>> {
247        match &mut *future_state {
248            SendFutureState::BadGeometry => Poll::Ready(Err(Some(Error::FDomain(
249                proto::Error::TargetError(fidl::Status::OUT_OF_RANGE.into_raw()),
250            )))),
251            SendFutureState::Wait(receiver) => receiver.poll_unpin(ctx).map(|x| {
252                match x.expect("Receiver disappeared with no reply") {
253                    Ok(x) => Ok(x),
254                    Err(Error::FDomain(proto::Error::TargetError(e)))
255                        if e == fidl::Status::PEER_CLOSED.into_raw() =>
256                    {
257                        Err(None)
258                    }
259                    Err(e) => Err(Some(e)),
260                }
261            }),
262        }
263    }
264
265    type Exclusive = Exclusive;
266    type RecvFutureState = ();
267    type RecvBuffer = RecvBuffer;
268
269    fn begin_recv(_: &Self::Shared, _: &mut Self::Exclusive) -> Self::RecvFutureState {}
270
271    fn poll_recv(
272        _: Pin<&mut Self::RecvFutureState>,
273        ctx: &mut Context<'_>,
274        _: &Self::Shared,
275        exclusive: &mut Self::Exclusive,
276    ) -> Poll<Result<Self::RecvBuffer, Option<Self::Error>>> {
277        let poll_stream = exclusive.stream.poll_next_unpin(ctx);
278
279        let Some(msg) = ready!(poll_stream).transpose().map_err(Some)? else {
280            return Poll::Ready(Err(None));
281        };
282
283        // SAFETY: It should be safe to byte-cast to a chunk always.
284        let chunks = unsafe {
285            std::slice::from_raw_parts(
286                msg.bytes.as_ptr() as *const Chunk,
287                msg.bytes.len() / CHUNK_SIZE,
288            )
289            .to_vec()
290        };
291        let handles = msg.handles.into_iter().map(|x| Handle::from(x.handle).into()).collect();
292
293        Poll::Ready(Ok(RecvBuffer { handles, chunks, chunks_taken: 0, handles_taken: 0 }))
294    }
295}