/src/h2/src/proto/settings.rs
Line | Count | Source |
1 | | use crate::codec::UserError; |
2 | | use crate::error::Reason; |
3 | | use crate::proto::*; |
4 | | use std::task::{Context, Poll}; |
5 | | |
6 | | #[derive(Debug)] |
7 | | pub(crate) struct Settings { |
8 | | /// Our local SETTINGS sync state with the remote. |
9 | | local: Local, |
10 | | /// Received SETTINGS frame pending processing. The ACK must be written to |
11 | | /// the socket first then the settings applied **before** receiving any |
12 | | /// further frames. |
13 | | remote: Option<frame::Settings>, |
14 | | /// Whether the connection has received the initial SETTINGS frame from the |
15 | | /// remote peer. |
16 | | has_received_remote_initial_settings: bool, |
17 | | } |
18 | | |
19 | | #[derive(Debug)] |
20 | | enum Local { |
21 | | /// We want to send these SETTINGS to the remote when the socket is ready. |
22 | | ToSend(frame::Settings), |
23 | | /// We have sent these SETTINGS and are waiting for the remote to ACK |
24 | | /// before we apply them. |
25 | | WaitingAck(frame::Settings), |
26 | | /// Our local settings are in sync with the remote. |
27 | | Synced, |
28 | | } |
29 | | |
30 | | impl Settings { |
31 | 13.7k | pub(crate) fn new(local: frame::Settings) -> Self { |
32 | 13.7k | Settings { |
33 | 13.7k | // We assume the initial local SETTINGS were flushed during |
34 | 13.7k | // the handshake process. |
35 | 13.7k | local: Local::WaitingAck(local), |
36 | 13.7k | remote: None, |
37 | 13.7k | has_received_remote_initial_settings: false, |
38 | 13.7k | } |
39 | 13.7k | } |
40 | | |
41 | 7.12k | pub(crate) fn recv_settings<T, B, C, P>( |
42 | 7.12k | &mut self, |
43 | 7.12k | frame: frame::Settings, |
44 | 7.12k | codec: &mut Codec<T, B>, |
45 | 7.12k | streams: &mut Streams<C, P>, |
46 | 7.12k | ) -> Result<(), Error> |
47 | 7.12k | where |
48 | 7.12k | T: AsyncWrite + Unpin, |
49 | 7.12k | B: Buf, |
50 | 7.12k | C: Buf, |
51 | 7.12k | P: Peer, |
52 | | { |
53 | 7.12k | if frame.is_ack() { |
54 | 6 | match &self.local { |
55 | 5 | Local::WaitingAck(local) => { |
56 | 5 | tracing::debug!("received settings ACK; applying {:?}", local); |
57 | | |
58 | 5 | if let Some(max) = local.max_frame_size() { |
59 | 0 | codec.set_max_recv_frame_size(max as usize); |
60 | 5 | } |
61 | | |
62 | 5 | if let Some(max) = local.max_header_list_size() { |
63 | 0 | codec.set_max_recv_header_list_size(max as usize); |
64 | 5 | } |
65 | | |
66 | 5 | if let Some(val) = local.header_table_size() { |
67 | 0 | codec.set_recv_header_table_size(val as usize); |
68 | 5 | } |
69 | | |
70 | 5 | streams.apply_local_settings(local)?; |
71 | 5 | self.local = Local::Synced; |
72 | 5 | Ok(()) |
73 | | } |
74 | | Local::ToSend(..) | Local::Synced => { |
75 | | // We haven't sent any SETTINGS frames to be ACKed, so |
76 | | // this is very bizarre! Remote is either buggy or malicious. |
77 | 1 | proto_err!(conn: "received unexpected settings ack"); |
78 | 1 | Err(Error::library_go_away(Reason::PROTOCOL_ERROR)) |
79 | | } |
80 | | } |
81 | | } else { |
82 | | // We always ACK before reading more frames, so `remote` should |
83 | | // always be none! |
84 | 7.11k | assert!(self.remote.is_none()); |
85 | 7.11k | self.remote = Some(frame); |
86 | 7.11k | Ok(()) |
87 | | } |
88 | 7.12k | } |
89 | | |
90 | 0 | pub(crate) fn send_settings(&mut self, frame: frame::Settings) -> Result<(), UserError> { |
91 | 0 | assert!(!frame.is_ack()); |
92 | 0 | match &self.local { |
93 | 0 | Local::ToSend(..) | Local::WaitingAck(..) => Err(UserError::SendSettingsWhilePending), |
94 | | Local::Synced => { |
95 | 0 | tracing::trace!("queue to send local settings: {:?}", frame); |
96 | 0 | self.local = Local::ToSend(frame); |
97 | 0 | Ok(()) |
98 | | } |
99 | | } |
100 | 0 | } |
101 | | |
102 | | /// Sets `true` to `self.has_received_remote_initial_settings`. |
103 | | /// Returns `true` if this method is called for the first time. |
104 | | /// (i.e. it is the initial SETTINGS frame from the remote peer) |
105 | 7.03k | fn mark_remote_initial_settings_as_received(&mut self) -> bool { |
106 | 7.03k | let has_received = self.has_received_remote_initial_settings; |
107 | 7.03k | self.has_received_remote_initial_settings = true; |
108 | 7.03k | !has_received |
109 | 7.03k | } |
110 | | |
111 | 2.50M | pub(crate) fn poll_send<T, B, C, P>( |
112 | 2.50M | &mut self, |
113 | 2.50M | cx: &mut Context, |
114 | 2.50M | dst: &mut Codec<T, B>, |
115 | 2.50M | streams: &mut Streams<C, P>, |
116 | 2.50M | ) -> Poll<Result<(), Error>> |
117 | 2.50M | where |
118 | 2.50M | T: AsyncWrite + Unpin, |
119 | 2.50M | B: Buf, |
120 | 2.50M | C: Buf, |
121 | 2.50M | P: Peer, |
122 | | { |
123 | 2.50M | if let Some(settings) = self.remote.clone() { |
124 | 64.6k | if !dst.poll_ready(cx)?.is_ready() { |
125 | 57.5k | return Poll::Pending; |
126 | 7.03k | } |
127 | | |
128 | | // Create an ACK settings frame |
129 | 7.03k | let frame = frame::Settings::ack(); |
130 | | |
131 | | // Buffer the settings frame |
132 | 7.03k | dst.buffer(frame.into()).expect("invalid settings frame"); |
133 | | |
134 | 7.03k | tracing::trace!("ACK sent; applying settings"); |
135 | | |
136 | 7.03k | let is_initial = self.mark_remote_initial_settings_as_received(); |
137 | 7.03k | streams.apply_remote_settings(&settings, is_initial)?; |
138 | | |
139 | 7.02k | if let Some(val) = settings.header_table_size() { |
140 | 1.66k | dst.set_send_header_table_size(val as usize); |
141 | 5.36k | } |
142 | | |
143 | 7.02k | if let Some(val) = settings.max_frame_size() { |
144 | 322 | dst.set_max_send_frame_size(val as usize); |
145 | 6.70k | } |
146 | 2.43M | } |
147 | | |
148 | 2.44M | self.remote = None; |
149 | | |
150 | 2.44M | match &self.local { |
151 | 0 | Local::ToSend(settings) => { |
152 | 0 | if !dst.poll_ready(cx)?.is_ready() { |
153 | 0 | return Poll::Pending; |
154 | 0 | } |
155 | | |
156 | | // Buffer the settings frame |
157 | 0 | dst.buffer(settings.clone().into()) |
158 | 0 | .expect("invalid settings frame"); |
159 | 0 | tracing::trace!("local settings sent; waiting for ack: {:?}", settings); |
160 | | |
161 | 0 | self.local = Local::WaitingAck(settings.clone()); |
162 | | } |
163 | 2.44M | Local::WaitingAck(..) | Local::Synced => {} |
164 | | } |
165 | | |
166 | 2.44M | Poll::Ready(Ok(())) |
167 | 2.50M | } |
168 | | } |