fidl/
epitaph.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//! Epitaph support for Channel and AsyncChannel.
6
7use crate::encoding::{
8    self, DynamicFlags, EpitaphBody, NoHandleResourceDialect, TransactionHeader,
9    TransactionMessage, TransactionMessageType,
10};
11use crate::error::Error;
12use crate::{AsyncChannel, Channel, TransportError};
13use zx_status;
14
15/// Extension trait that provides Channel-like objects with the ability to send a FIDL epitaph.
16pub trait ChannelEpitaphExt {
17    /// Consumes the channel and writes an epitaph.
18    fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error>;
19}
20
21impl<T: ChannelLike> ChannelEpitaphExt for T {
22    fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
23        write_epitaph_impl(&self, status)
24    }
25}
26
27/// Indicates an object is "channel-like" in that it can receive epitaphs.
28pub trait ChannelLike {
29    /// Write an epitaph to a channel. Same as write_etc but is never fed handles.
30    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError>;
31}
32
33impl ChannelLike for Channel {
34    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
35        self.write_etc(bytes, &mut []).map_err(Into::into)
36    }
37}
38
39impl ChannelLike for AsyncChannel {
40    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
41        self.write_etc(bytes, &mut []).map_err(Into::into)
42    }
43}
44
45pub(crate) fn write_epitaph_impl<T: ChannelLike>(
46    channel: &T,
47    status: zx_status::Status,
48) -> Result<(), Error> {
49    let msg = TransactionMessage {
50        header: TransactionHeader::new(0, encoding::EPITAPH_ORDINAL, DynamicFlags::empty()),
51        body: &EpitaphBody { error: status },
52    };
53    encoding::with_tls_encoded::<TransactionMessageType<EpitaphBody>, NoHandleResourceDialect, ()>(
54        msg,
55        |bytes, handles| {
56            assert!(handles.is_empty(), "Epitaph should not have handles!");
57            match channel.write_epitaph(bytes) {
58                Ok(()) | Err(TransportError::Status(zx_status::Status::PEER_CLOSED)) => Ok(()),
59                Err(e) => Err(Error::ServerEpitaphWrite(e)),
60            }
61        },
62    )
63}