/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 | 14.5k | pub(crate) fn new(local: frame::Settings) -> Self { |
32 | 14.5k | Settings { |
33 | 14.5k | // We assume the initial local SETTINGS were flushed during |
34 | 14.5k | // the handshake process. |
35 | 14.5k | local: Local::WaitingAck(local), |
36 | 14.5k | remote: None, |
37 | 14.5k | has_received_remote_initial_settings: false, |
38 | 14.5k | } |
39 | 14.5k | } |
40 | | |
41 | 6.64k | pub(crate) fn recv_settings<T, B, C, P>( |
42 | 6.64k | &mut self, |
43 | 6.64k | frame: frame::Settings, |
44 | 6.64k | codec: &mut Codec<T, B>, |
45 | 6.64k | streams: &mut Streams<C, P>, |
46 | 6.64k | ) -> Result<(), Error> |
47 | 6.64k | where |
48 | 6.64k | T: AsyncWrite + Unpin, |
49 | 6.64k | B: Buf, |
50 | 6.64k | C: Buf, |
51 | 6.64k | P: Peer, |
52 | | { |
53 | 6.64k | if frame.is_ack() { |
54 | 18 | match &self.local { |
55 | 17 | Local::WaitingAck(local) => { |
56 | 17 | tracing::debug!("received settings ACK; applying {:?}", local); |
57 | | |
58 | 17 | if let Some(max) = local.max_frame_size() { |
59 | 0 | codec.set_max_recv_frame_size(max as usize); |
60 | 17 | } |
61 | | |
62 | 17 | if let Some(max) = local.max_header_list_size() { |
63 | 0 | codec.set_max_recv_header_list_size(max as usize); |
64 | 17 | } |
65 | | |
66 | 17 | if let Some(val) = local.header_table_size() { |
67 | 0 | codec.set_recv_header_table_size(val as usize); |
68 | 17 | } |
69 | | |
70 | 17 | streams.apply_local_settings(local)?; |
71 | 17 | self.local = Local::Synced; |
72 | 17 | 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 | 6.62k | assert!(self.remote.is_none()); |
85 | 6.62k | self.remote = Some(frame); |
86 | 6.62k | Ok(()) |
87 | | } |
88 | 6.64k | } |
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 | 6.54k | fn mark_remote_initial_settings_as_received(&mut self) -> bool { |
106 | 6.54k | let has_received = self.has_received_remote_initial_settings; |
107 | 6.54k | self.has_received_remote_initial_settings = true; |
108 | 6.54k | !has_received |
109 | 6.54k | } |
110 | | |
111 | 590k | pub(crate) fn poll_send<T, B, C, P>( |
112 | 590k | &mut self, |
113 | 590k | cx: &mut Context, |
114 | 590k | dst: &mut Codec<T, B>, |
115 | 590k | streams: &mut Streams<C, P>, |
116 | 590k | ) -> Poll<Result<(), Error>> |
117 | 590k | where |
118 | 590k | T: AsyncWrite + Unpin, |
119 | 590k | B: Buf, |
120 | 590k | C: Buf, |
121 | 590k | P: Peer, |
122 | | { |
123 | 590k | if let Some(settings) = self.remote.clone() { |
124 | 9.02k | if !dst.poll_ready(cx)?.is_ready() { |
125 | 2.41k | return Poll::Pending; |
126 | 6.54k | } |
127 | | |
128 | | // Create an ACK settings frame |
129 | 6.54k | let frame = frame::Settings::ack(); |
130 | | |
131 | | // Buffer the settings frame |
132 | 6.54k | dst.buffer(frame.into()).expect("invalid settings frame"); |
133 | | |
134 | 6.54k | tracing::trace!("ACK sent; applying settings"); |
135 | | |
136 | 6.54k | let is_initial = self.mark_remote_initial_settings_as_received(); |
137 | 6.54k | streams.apply_remote_settings(&settings, is_initial)?; |
138 | | |
139 | 6.53k | if let Some(val) = settings.header_table_size() { |
140 | 1.53k | dst.set_send_header_table_size(val as usize); |
141 | 5.00k | } |
142 | | |
143 | 6.53k | if let Some(val) = settings.max_frame_size() { |
144 | 336 | dst.set_max_send_frame_size(val as usize); |
145 | 6.20k | } |
146 | 581k | } |
147 | | |
148 | 588k | self.remote = None; |
149 | | |
150 | 588k | 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 | 588k | Local::WaitingAck(..) | Local::Synced => {} |
164 | | } |
165 | | |
166 | 588k | Poll::Ready(Ok(())) |
167 | 590k | } |
168 | | } |