blob: e05e8dcd953b20e760742c0a8b14054e7fb4e348 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Epitaph support for Channel and AsyncChannel.
use {
crate::{
encoding::{
self, DynamicFlags, EpitaphBody, TransactionHeader, TransactionMessage,
TransactionMessageType,
},
error::Error,
AsyncChannel, Channel, HandleDisposition,
},
fuchsia_zircon_status as zx_status,
};
/// Extension trait that provides Channel-like objects with the ability to send a FIDL epitaph.
pub trait ChannelEpitaphExt {
/// Consumes the channel and writes an epitaph.
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error>;
}
impl ChannelEpitaphExt for Channel {
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
write_epitaph_impl(&self, status)
}
}
impl ChannelEpitaphExt for AsyncChannel {
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
write_epitaph_impl(&self, status)
}
}
pub(crate) trait ChannelLike {
fn write_etc(
&self,
bytes: &[u8],
handles: &mut Vec<HandleDisposition<'_>>,
) -> Result<(), zx_status::Status>;
}
impl ChannelLike for Channel {
fn write_etc(
&self,
bytes: &[u8],
handles: &mut Vec<HandleDisposition<'_>>,
) -> Result<(), zx_status::Status> {
self.write_etc(bytes, handles)
}
}
impl ChannelLike for AsyncChannel {
fn write_etc(
&self,
bytes: &[u8],
handles: &mut Vec<HandleDisposition<'_>>,
) -> Result<(), zx_status::Status> {
self.write_etc(bytes, handles)
}
}
pub(crate) fn write_epitaph_impl<T: ChannelLike>(
channel: &T,
status: zx_status::Status,
) -> Result<(), Error> {
let msg = TransactionMessage {
header: TransactionHeader::new(0, encoding::EPITAPH_ORDINAL, DynamicFlags::empty()),
body: &EpitaphBody { error: status },
};
encoding::with_tls_encoded::<TransactionMessageType<EpitaphBody>, ()>(msg, |bytes, handles| {
match channel.write_etc(bytes, handles) {
Ok(()) | Err(zx_status::Status::PEER_CLOSED) => Ok(()),
Err(e) => Err(Error::ServerEpitaphWrite(e)),
}
})
}