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