archivist_lib/logs/servers/
log_freeze.rs1use anyhow::Error;
6use fidl_fuchsia_diagnostics_system as ftarget;
7use futures::StreamExt;
8use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
9use futures::channel::oneshot;
10use log::warn;
11
12#[derive(Clone)]
13pub struct LogFreezeServer {
14 freezer: UnboundedSender<oneshot::Sender<zx::EventPair>>,
15}
16
17impl LogFreezeServer {
18 pub fn new() -> (Self, UnboundedReceiver<oneshot::Sender<zx::EventPair>>) {
19 let (freezer, rx) = unbounded();
20 (Self { freezer }, rx)
21 }
22
23 pub async fn handle_requests(
25 &self,
26 mut stream: ftarget::SerialLogControlRequestStream,
27 ) -> Result<(), Error> {
28 while let Some(request) = stream.next().await {
29 match request? {
30 fidl_fuchsia_diagnostics_system::SerialLogControlRequest::FreezeSerialForwarding { responder } => {
31 let (tx, rx) = oneshot::channel();
32 self.freezer.unbounded_send(tx)?;
33 let _ = responder.send(rx.await?);
35 },
36 ftarget::SerialLogControlRequest::_UnknownMethod {
37 ordinal,
38 method_type,
39 control_handle,
40 ..
41 } => {
42 warn!(ordinal, method_type:?; "Unknown request. Closing connection");
43 control_handle.shutdown_with_epitaph(zx::Status::UNAVAILABLE);
44 }
45 }
46 }
47 Ok(())
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use assert_matches::assert_matches;
55 use fidl::endpoints::{Proxy, create_proxy_and_stream};
56
57 #[fuchsia::test]
58 async fn freeze_serial_forwarding_success() {
59 let (server, mut rx) = LogFreezeServer::new();
60 let (proxy, stream) = create_proxy_and_stream::<ftarget::SerialLogControlMarker>();
61
62 let server_task = fuchsia_async::Task::spawn(async move {
63 server.handle_requests(stream).await.unwrap();
64 });
65
66 let freeze_fut = proxy.freeze_serial_forwarding();
67
68 let (p1, p2) = zx::EventPair::create();
69 let tx = rx.next().await.expect("received freezer channel");
70 tx.send(p1).expect("send eventpair to server");
71
72 let received_p2 = freeze_fut.await.expect("freeze response received");
73 assert_eq!(p2.basic_info().unwrap().related_koid, received_p2.koid().unwrap());
74
75 drop(proxy);
76 server_task.await;
77 }
78
79 #[fuchsia::test]
80 async fn unknown_method_closes_with_unavailable_epitaph() {
81 let (server, _rx) = LogFreezeServer::new();
82 let (proxy, stream) = create_proxy_and_stream::<ftarget::SerialLogControlMarker>();
83
84 let server_task = fuchsia_async::Task::spawn(async move {
85 server.handle_requests(stream).await.unwrap();
86 });
87
88 let header = fidl::encoding::TransactionHeader::new(
90 0,
91 0x1234_5678,
92 fidl::encoding::DynamicFlags::FLEXIBLE,
93 );
94 let bytes = unsafe {
95 std::slice::from_raw_parts(
96 &header as *const _ as *const u8,
97 std::mem::size_of_val(&header),
98 )
99 };
100 proxy.as_channel().write(bytes, &mut []).expect("write raw unknown method header");
101
102 let mut event_stream = proxy.take_event_stream();
103 let event = event_stream.next().await;
104 assert_matches!(
105 event,
106 Some(Err(fidl::Error::ClientChannelClosed {
107 epitaph: fidl::Epitaph::Explicit(Err(zx::Status::UNAVAILABLE)),
108 ..
109 }))
110 );
111
112 server_task.await;
113 }
114
115 #[fuchsia::test]
116 async fn client_closes_channel() {
117 let (server, _rx) = LogFreezeServer::new();
118 let (proxy, stream) = create_proxy_and_stream::<ftarget::SerialLogControlMarker>();
119
120 drop(proxy);
121 assert!(server.handle_requests(stream).await.is_ok());
122 }
123
124 #[fuchsia::test]
125 async fn freezer_dropped_returns_error() {
126 let (server, rx) = LogFreezeServer::new();
127 drop(rx);
128
129 let (proxy, stream) = create_proxy_and_stream::<ftarget::SerialLogControlMarker>();
130
131 let server_task =
132 fuchsia_async::Task::spawn(async move { server.handle_requests(stream).await });
133
134 let freeze_fut = proxy.freeze_serial_forwarding();
135 let (result, _) = futures::join!(server_task, freeze_fut);
136 assert!(result.is_err());
137 }
138}