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