1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6 
7 use crate::{
8     client_events::Http3ClientEvents,
9     settings::{HSettingType, HSettings},
10 };
11 use neqo_common::qtrace;
12 use std::fmt::Debug;
13 use std::mem;
14 
15 pub mod extended_connect;
16 
17 /// States:
18 /// - `Disable` - it is not turned on for this connection.
19 /// - `Negotiating` - the feature is enabled locally, but settings from the peer
20 ///                  have not been received yet.
21 /// - `Negotiated` - the settings have been received and both sides support the feature.
22 /// - `NegotiationFailed` - the settings have been received and the peer does not
23 ///                         support the feature.
24 #[derive(Debug)]
25 pub enum NegotiationState {
26     Disabled,
27     Negotiating {
28         feature_type: HSettingType,
29         listener: Option<Http3ClientEvents>,
30     },
31     Negotiated,
32     NegotiationFailed,
33 }
34 
35 impl NegotiationState {
36     #[must_use]
new(enable: bool, feature_type: HSettingType) -> Self37     pub fn new(enable: bool, feature_type: HSettingType) -> Self {
38         if enable {
39             Self::Negotiating {
40                 feature_type,
41                 listener: None,
42             }
43         } else {
44             Self::Disabled
45         }
46     }
47 
set_listener(&mut self, new_listener: Http3ClientEvents)48     pub fn set_listener(&mut self, new_listener: Http3ClientEvents) {
49         if let Self::Negotiating { listener, .. } = self {
50             *listener = Some(new_listener);
51         }
52     }
53 
handle_settings(&mut self, settings: &HSettings)54     pub fn handle_settings(&mut self, settings: &HSettings) {
55         if !self.locally_enabled() {
56             return;
57         }
58 
59         if let Self::Negotiating {
60             feature_type,
61             listener,
62         } = self
63         {
64             qtrace!(
65                 "set_negotiated {:?} to {}",
66                 feature_type,
67                 settings.get(*feature_type)
68             );
69             let cb = mem::take(listener);
70             let ft = *feature_type;
71             *self = if settings.get(ft) == 1 {
72                 Self::Negotiated
73             } else {
74                 Self::NegotiationFailed
75             };
76             if let Some(l) = cb {
77                 l.negotiation_done(ft, self.enabled());
78             }
79         }
80     }
81 
82     #[must_use]
enabled(&self) -> bool83     pub fn enabled(&self) -> bool {
84         matches!(self, &Self::Negotiated)
85     }
86 
87     #[must_use]
locally_enabled(&self) -> bool88     pub fn locally_enabled(&self) -> bool {
89         !matches!(self, &Self::Disabled)
90     }
91 }
92