overnet_core/proxy/handle/
signals.rs

1// Copyright 2021 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::ReadValue;
6use fidl::{HandleRef, Signals};
7use fidl_fuchsia_overnet_protocol::{SignalUpdate, Signals as WireSignals};
8use fuchsia_async::OnSignalsRef;
9use futures::FutureExt;
10use std::task::{Context, Poll};
11use zx_status;
12
13const POLLED_SIGNALS: Signals = Signals::from_bits_truncate(
14    Signals::USER_0.bits()
15        | Signals::USER_1.bits()
16        | Signals::USER_2.bits()
17        | Signals::USER_3.bits()
18        | Signals::USER_4.bits()
19        | Signals::USER_5.bits()
20        | Signals::USER_6.bits()
21        | Signals::USER_7.bits(),
22);
23
24#[derive(Default)]
25pub(crate) struct Collector<'a> {
26    on_signals: Option<OnSignalsRef<'a>>,
27    shutdown: bool,
28}
29
30impl<'h> Collector<'h> {
31    pub(crate) fn after_read<'ctx>(
32        &mut self,
33        ctx: &mut Context<'ctx>,
34        hdl: HandleRef<'h>,
35        read_result: Poll<Result<(), zx_status::Status>>,
36        do_peer_closed: bool,
37    ) -> Poll<Result<ReadValue, zx_status::Status>> {
38        match read_result {
39            Poll::Ready(Ok(())) => Poll::Ready(Ok(ReadValue::Message)),
40            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
41            Poll::Pending => {
42                if self.shutdown {
43                    return Poll::Ready(Err(zx_status::Status::PEER_CLOSED));
44                }
45
46                let signals = if do_peer_closed {
47                    POLLED_SIGNALS | Signals::OBJECT_PEER_CLOSED
48                } else {
49                    POLLED_SIGNALS
50                };
51
52                let mut on_signals = self
53                    .on_signals
54                    .take()
55                    .unwrap_or_else(|| OnSignalsRef::new(hdl.clone(), signals));
56                match on_signals.poll_unpin(ctx) {
57                    Poll::Ready(Ok(mut signals)) => {
58                        self.shutdown =
59                            self.shutdown || signals.contains(Signals::OBJECT_PEER_CLOSED);
60                        signals.remove(Signals::OBJECT_PEER_CLOSED);
61                        if signals.is_empty() {
62                            Poll::Ready(Err(zx_status::Status::PEER_CLOSED))
63                        } else {
64                            hdl.signal(signals & POLLED_SIGNALS, Signals::empty()).inspect_err(
65                                |e| log::warn!("failed to clear signals in handle {e:?}"),
66                            )?;
67                            Poll::Ready(Ok(ReadValue::SignalUpdate(SignalUpdate {
68                                assert_signals: Some(to_wire_signals(signals)),
69                                ..Default::default()
70                            })))
71                        }
72                    }
73                    Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
74                    Poll::Pending => {
75                        self.on_signals = Some(on_signals);
76                        Poll::Pending
77                    }
78                }
79            }
80        }
81    }
82}
83
84fn to_wire_signals(signals: Signals) -> WireSignals {
85    let mut out = WireSignals::empty();
86    if signals.contains(Signals::USER_0) {
87        out.insert(WireSignals::USER_0);
88    }
89    if signals.contains(Signals::USER_1) {
90        out.insert(WireSignals::USER_1);
91    }
92    if signals.contains(Signals::USER_2) {
93        out.insert(WireSignals::USER_2);
94    }
95    if signals.contains(Signals::USER_3) {
96        out.insert(WireSignals::USER_3);
97    }
98    if signals.contains(Signals::USER_4) {
99        out.insert(WireSignals::USER_4);
100    }
101    if signals.contains(Signals::USER_5) {
102        out.insert(WireSignals::USER_5);
103    }
104    if signals.contains(Signals::USER_6) {
105        out.insert(WireSignals::USER_6);
106    }
107    if signals.contains(Signals::USER_7) {
108        out.insert(WireSignals::USER_7);
109    }
110    out
111}
112
113pub(crate) fn from_wire_signals(signals: WireSignals) -> Signals {
114    let mut out = Signals::empty();
115    if signals.contains(WireSignals::USER_0) {
116        out.insert(Signals::USER_0);
117    }
118    if signals.contains(WireSignals::USER_1) {
119        out.insert(Signals::USER_1);
120    }
121    if signals.contains(WireSignals::USER_2) {
122        out.insert(Signals::USER_2);
123    }
124    if signals.contains(WireSignals::USER_3) {
125        out.insert(Signals::USER_3);
126    }
127    if signals.contains(WireSignals::USER_4) {
128        out.insert(Signals::USER_4);
129    }
130    if signals.contains(WireSignals::USER_5) {
131        out.insert(Signals::USER_5);
132    }
133    if signals.contains(WireSignals::USER_6) {
134        out.insert(Signals::USER_6);
135    }
136    if signals.contains(WireSignals::USER_7) {
137        out.insert(Signals::USER_7);
138    }
139    out
140}