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, Signals::empty())?;
65                            Poll::Ready(Ok(ReadValue::SignalUpdate(SignalUpdate {
66                                assert_signals: Some(to_wire_signals(signals)),
67                                ..Default::default()
68                            })))
69                        }
70                    }
71                    Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
72                    Poll::Pending => {
73                        self.on_signals = Some(on_signals);
74                        Poll::Pending
75                    }
76                }
77            }
78        }
79    }
80}
81
82fn to_wire_signals(signals: Signals) -> WireSignals {
83    let mut out = WireSignals::empty();
84    if signals.contains(Signals::USER_0) {
85        out.insert(WireSignals::USER_0);
86    }
87    if signals.contains(Signals::USER_1) {
88        out.insert(WireSignals::USER_1);
89    }
90    if signals.contains(Signals::USER_2) {
91        out.insert(WireSignals::USER_2);
92    }
93    if signals.contains(Signals::USER_3) {
94        out.insert(WireSignals::USER_3);
95    }
96    if signals.contains(Signals::USER_4) {
97        out.insert(WireSignals::USER_4);
98    }
99    if signals.contains(Signals::USER_5) {
100        out.insert(WireSignals::USER_5);
101    }
102    if signals.contains(Signals::USER_6) {
103        out.insert(WireSignals::USER_6);
104    }
105    if signals.contains(Signals::USER_7) {
106        out.insert(WireSignals::USER_7);
107    }
108    out
109}
110
111pub(crate) fn from_wire_signals(signals: WireSignals) -> Signals {
112    let mut out = Signals::empty();
113    if signals.contains(WireSignals::USER_0) {
114        out.insert(Signals::USER_0);
115    }
116    if signals.contains(WireSignals::USER_1) {
117        out.insert(Signals::USER_1);
118    }
119    if signals.contains(WireSignals::USER_2) {
120        out.insert(Signals::USER_2);
121    }
122    if signals.contains(WireSignals::USER_3) {
123        out.insert(Signals::USER_3);
124    }
125    if signals.contains(WireSignals::USER_4) {
126        out.insert(Signals::USER_4);
127    }
128    if signals.contains(WireSignals::USER_5) {
129        out.insert(Signals::USER_5);
130    }
131    if signals.contains(WireSignals::USER_6) {
132        out.insert(Signals::USER_6);
133    }
134    if signals.contains(WireSignals::USER_7) {
135        out.insert(Signals::USER_7);
136    }
137    out
138}