Skip to main content

fidl/
server.rs

1// Copyright 2019 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//! An implementation of a server for a fidl interface.
6
7use crate::encoding::{
8    DefaultFuchsiaResourceDialect, DynamicFlags, EmptyStruct, Encode, Encoder, Flexible,
9    FlexibleType, FrameworkErr, HandleFor, ProxyChannelBox, ProxyChannelFor, ResourceDialect,
10    TransactionHeader, TransactionMessage, TransactionMessageType, TypeMarker,
11};
12use crate::{Error, epitaph};
13use futures::task::{AtomicWaker, Context};
14use std::sync::atomic::{self, AtomicBool};
15use zx_status;
16
17/// A type used from the innards of server implementations.
18#[derive(Debug)]
19pub struct ServeInner<D: ResourceDialect = DefaultFuchsiaResourceDialect> {
20    waker: AtomicWaker,
21    shutdown: AtomicBool,
22    channel: <D::ProxyChannel as ProxyChannelFor<D>>::Boxed,
23}
24
25impl<D: ResourceDialect> ServeInner<D> {
26    /// Creates a new set of server innards.
27    pub fn new(channel: D::ProxyChannel) -> Self {
28        let waker = AtomicWaker::new();
29        let shutdown = AtomicBool::new(false);
30        ServeInner { waker, shutdown, channel: channel.boxed() }
31    }
32
33    /// Gets a reference to the inner channel.
34    pub fn channel(&self) -> &<D::ProxyChannel as ProxyChannelFor<D>>::Boxed {
35        &self.channel
36    }
37
38    /// Converts the [`ServerInner`] back into a channel.
39    ///
40    /// **Warning**: This operation is dangerous, since the returned channel
41    /// could have unread messages intended for this server. Use it carefully.
42    pub fn into_channel(self) -> D::ProxyChannel {
43        self.channel.unbox()
44    }
45
46    /// Sets the server to shutdown the next time the stream is polled.
47    ///
48    /// TODO(https://fxbug.dev/42153903): This should cause the channel to close on the
49    /// next poll, but in fact the channel won't close until the user of the
50    /// bindings drops their request stream, responders, and control handles.
51    pub fn shutdown(&self) {
52        self.shutdown.store(true, atomic::Ordering::Relaxed);
53        self.waker.wake();
54    }
55
56    /// Sets the server to shutdown with an epitaph the next time the stream is polled.
57    ///
58    /// TODO(https://fxbug.dev/42153903): This should cause the channel to close on the
59    /// next poll, but in fact the channel won't close until the user of the
60    /// bindings drops their request stream, responders, and control handles.
61    pub fn shutdown_with_epitaph(&self, status: impl Into<crate::Epitaph>) {
62        let already_shutting_down = self.shutdown.swap(true, atomic::Ordering::Relaxed);
63        if !already_shutting_down {
64            // Ignore the error, best effort sending an epitaph.
65            let status = match status.into() {
66                crate::Epitaph::Explicit(res) => res,
67                crate::Epitaph::PeerClosed => Err(zx_status::Status::PEER_CLOSED),
68            };
69            let _ = epitaph::write_epitaph_impl(self.channel.as_channel(), status);
70            self.waker.wake();
71        }
72    }
73
74    /// Checks if the server has been set to shutdown.
75    pub fn check_shutdown(&self, cx: &Context<'_>) -> bool {
76        if self.shutdown.load(atomic::Ordering::Relaxed) {
77            return true;
78        }
79        self.waker.register(cx.waker());
80        self.shutdown.load(atomic::Ordering::Relaxed)
81    }
82
83    /// Sends an encodable message to the client.
84    #[inline]
85    pub fn send<T: TypeMarker>(
86        &self,
87        body: impl Encode<T, D>,
88        tx_id: u32,
89        ordinal: u64,
90        dynamic_flags: DynamicFlags,
91    ) -> Result<(), Error> {
92        let msg = TransactionMessage {
93            header: TransactionHeader::new(tx_id, ordinal, dynamic_flags),
94            body,
95        };
96        crate::encoding::with_tls_encoded::<TransactionMessageType<T>, D, ()>(
97            msg,
98            |bytes, handles| self.send_raw_msg(bytes, handles),
99        )
100    }
101
102    /// Sends a framework error to the client.
103    ///
104    /// The caller must be inside a `with_tls_decode_buf` callback, and pass the
105    /// buffers used to decode the request as the `tls_decode_buf` parameter.
106    #[inline]
107    pub fn send_framework_err(
108        &self,
109        framework_err: FrameworkErr,
110        tx_id: u32,
111        ordinal: u64,
112        dynamic_flags: DynamicFlags,
113        tls_decode_buf: (&mut Vec<u8>, &mut Vec<<D::Handle as HandleFor<D>>::HandleInfo>),
114    ) -> Result<(), Error> {
115        type Msg = TransactionMessageType<FlexibleType<EmptyStruct>>;
116        let msg = TransactionMessage {
117            header: TransactionHeader::new(tx_id, ordinal, dynamic_flags),
118            body: Flexible::<()>::FrameworkErr(framework_err),
119        };
120
121        // RFC-0138 requires us to close handles in the incoming message before replying.
122        let (bytes, handle_infos) = tls_decode_buf;
123        handle_infos.clear();
124        // Reuse the request decoding byte buffer for encoding (we can't call
125        // `with_tls_encoded` as we're already inside `with_tls_decode_buf`).
126        let mut handle_dispositions = Vec::new();
127        Encoder::<D>::encode::<Msg>(bytes, &mut handle_dispositions, msg)?;
128        debug_assert!(handle_dispositions.is_empty());
129        self.send_raw_msg(&*bytes, &mut [])
130    }
131
132    /// Sends a raw message to the client.
133    fn send_raw_msg(
134        &self,
135        bytes: &[u8],
136        handles: &mut [<D::ProxyChannel as ProxyChannelFor<D>>::HandleDisposition],
137    ) -> Result<(), Error> {
138        match self.channel.write_etc(bytes, handles) {
139            Ok(()) | Err(None) => Ok(()),
140            Err(Some(e)) => Err(Error::ServerResponseWrite(e.into())),
141        }
142    }
143}