conmonrs/streaming_server/port_forward/
requests.rs1use super::{
5 CLOSE_GRACE_PERIOD, Early, HALF_CLOSE_GRACE_PERIOD, PORT_HEADER, PortForward,
6 REQUEST_ID_HEADER, STREAM_TYPE_DATA, STREAM_TYPE_ERROR, namespace::Namespace,
7};
8use crate::streaming_server::{
9 spdy::{Connection, Headers, Stream, StreamReceiver, StreamSender},
10 stream_protocol::{ClientStr, STREAM_CREATION_TIMEOUT, STREAM_TYPE_HEADER},
11};
12use anyhow::{Context, Result, bail, ensure};
13use bytes::BytesMut;
14use futures::{StreamExt, stream::FuturesUnordered};
15use std::{
16 collections::HashMap,
17 future::Future,
18 pin::{Pin, pin},
19 sync::Arc,
20};
21use tokio::{io::AsyncWriteExt, net::TcpStream, select, task, time};
22use tokio_util::{
23 sync::{CancellationToken, DropGuard},
24 time::{DelayQueue, delay_queue::Key},
25};
26use tracing::debug;
27
28pub(super) struct PendingRequest {
30 data: Option<Waiting>,
31 error: Option<Waiting>,
32
33 deadline: Key,
35}
36
37struct Waiting {
40 stream: Stream,
41 _watch: DropGuard,
42}
43
44impl Waiting {
45 fn is_reset(&self) -> bool {
46 self.stream.is_reset()
47 }
48}
49
50type ResetWatch = Pin<Box<dyn Future<Output = Option<Arc<str>>> + Send>>;
53
54pub(super) struct Pending {
58 pub(super) requests: HashMap<Arc<str>, PendingRequest>,
59 pub(super) deadlines: DelayQueue<Arc<str>>,
60
61 pub(super) resets: FuturesUnordered<ResetWatch>,
67}
68
69impl Pending {
70 pub(super) fn new() -> Self {
72 Self {
73 requests: HashMap::new(),
74 deadlines: DelayQueue::new(),
75 resets: FuturesUnordered::new(),
76 }
77 }
78
79 fn wait(request_id: &Arc<str>, stream: Stream) -> (Waiting, ResetWatch) {
82 let waiting = CancellationToken::new();
83 let (reset, stopped) = (stream.reset_watch(), waiting.clone());
84 let request_id = request_id.clone();
85 let watch = Box::pin(async move {
86 select! {
87 biased;
88 () = stopped.cancelled() => None,
89 () = reset => Some(request_id),
90 }
91 });
92 let stream = Waiting {
93 stream,
94 _watch: waiting.drop_guard(),
95 };
96 (stream, watch)
97 }
98
99 pub(super) fn get_or_insert(&mut self, request_id: &Arc<str>) -> &mut PendingRequest {
101 let Self {
102 requests,
103 deadlines,
104 ..
105 } = self;
106 requests
107 .entry(request_id.clone())
108 .or_insert_with(|| PendingRequest {
109 data: None,
110 error: None,
111 deadline: deadlines.insert(request_id.clone(), STREAM_CREATION_TIMEOUT),
112 })
113 }
114
115 pub(super) fn remove(&mut self, request_id: &str) -> Option<PendingRequest> {
117 let request = self.requests.remove(request_id)?;
118 self.deadlines.remove(&request.deadline);
119 Some(request)
120 }
121
122 pub(super) fn remove_reset(&mut self, request_id: &str) {
125 let Some(request) = self.requests.get_mut(request_id) else {
126 return;
127 };
128 request.data.take_if(|stream| stream.is_reset());
129 request.error.take_if(|stream| stream.is_reset());
130 if request.data.is_none() && request.error.is_none() {
131 self.remove(request_id);
132 }
133 }
134}
135
136impl PortForward {
137 pub(crate) async fn serve_spdy<T>(self, io: T)
139 where
140 T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static,
141 {
142 let mut connection =
143 Connection::serve(io, self.idle_timeout, self.ping_interval, Self::accept);
144 let namespace = Namespace::new(self.netns_path);
145 let mut pending = Pending::new();
146
147 loop {
148 select! {
149 Some(reset) = pending.resets.next() => if let Some(request_id) = reset {
150 pending.remove_reset(&request_id);
151 },
152 stream = connection.accept() => match stream {
153 Some(stream) => Self::add(&mut pending, stream, &namespace),
154 None => break,
155 },
156 Some(expired) = pending.deadlines.next() => {
157 Self::expire(&mut pending, expired.into_inner());
158 }
159 }
160 }
161 debug!("Port forward connection ended");
162 }
163
164 pub(super) fn accept(headers: &Headers) -> Result<()> {
166 Self::port(headers)?;
167 match headers.get(STREAM_TYPE_HEADER) {
168 Some(STREAM_TYPE_DATA | STREAM_TYPE_ERROR) => Ok(()),
169 Some(typ) => bail!("invalid stream type {:?}", ClientStr(typ)),
170 None => bail!("{STREAM_TYPE_HEADER:?} header is required"),
171 }
172 }
173
174 fn port(headers: &Headers) -> Result<u16> {
175 let port = headers
176 .get(PORT_HEADER)
177 .with_context(|| format!("{PORT_HEADER:?} header is required"))?;
178 let port: u16 = port
179 .parse()
180 .with_context(|| format!("unable to parse {:?} as a port", ClientStr(port)))?;
181 ensure!(port > 0, "port {port} must be > 0");
182 Ok(port)
183 }
184
185 fn is_error_stream(stream: &Stream) -> bool {
186 stream.headers().get(STREAM_TYPE_HEADER) == Some(STREAM_TYPE_ERROR)
187 }
188
189 fn request_id(stream: &Stream) -> Arc<str> {
193 match stream.headers().get(REQUEST_ID_HEADER) {
194 Some(id) if !id.is_empty() => id.into(),
195 _ if Self::is_error_stream(stream) => stream.id().to_string().into(),
196 _ => (i64::from(stream.id()) - 2).to_string().into(),
200 }
201 }
202
203 pub(super) fn add(pending: &mut Pending, stream: Stream, namespace: &Arc<Namespace>) {
205 let request_id = Self::request_id(&stream);
206 let is_error = Self::is_error_stream(&stream);
207 let (stream, watch) = Pending::wait(&request_id, stream);
208 let request = pending.get_or_insert(&request_id);
209 request.data.take_if(|stream| stream.is_reset());
212 request.error.take_if(|stream| stream.is_reset());
213 let slot = if is_error {
214 &mut request.error
215 } else {
216 &mut request.data
217 };
218 if slot.is_some() {
219 debug!(
221 "Rejecting stream {} of port forward request {:?}, the request has one of its type already",
222 stream.stream.id(),
223 ClientStr(&request_id)
224 );
225 return;
226 }
227 *slot = Some(stream);
228
229 if request.data.is_none() || request.error.is_none() {
230 pending.resets.push(watch);
231 return;
232 }
233 if let Some(PendingRequest {
234 data: Some(data),
235 error: Some(error),
236 ..
237 }) = pending.remove(&request_id)
238 {
239 task::spawn(Self::forward(
240 request_id,
241 data.stream,
242 error.stream,
243 namespace.clone(),
244 ));
245 }
246 }
247
248 fn expire(pending: &mut Pending, request_id: Arc<str>) {
250 let Some(mut request) = pending.requests.remove(&request_id) else {
251 return;
252 };
253 debug!(
254 "Port forward request {:?} timed out waiting for streams",
255 ClientStr(&request_id)
256 );
257 if let Some((_, mut error)) = request.error.take().map(|error| error.stream.split()) {
258 let message = format!("request {request_id}: timed out waiting for streams");
259 task::spawn(async move {
260 let _ = error.send(message.into()).await;
261 let _ = error.close().await;
262 });
263 }
264 }
265
266 async fn forward(request_id: Arc<str>, data: Stream, error: Stream, namespace: Arc<Namespace>) {
268 let port = Self::port(data.headers()).unwrap_or_default();
269 let id = ClientStr(&request_id);
270 debug!("Forwarding port {port} for request {id:?}");
271 let (_, mut error) = error.split();
274
275 let (mut from_client, to_client) = data.split();
276 let result = match Self::establish(&namespace, port, &mut from_client).await {
277 Ok((connection, early)) => Self::copy(early, from_client, to_client, connection).await,
278 Err(e) => {
279 drop((from_client, to_client));
282 Err(e)
283 }
284 };
285 match result {
286 Ok(()) => debug!("Done forwarding port {port} for request {id:?}"),
287 Err(e) => {
288 let message = Self::forward_error(port, &e);
289 debug!("Port forward request {id:?}: {message}");
290 if let Err(e) = error.send(message.into()).await {
291 debug!("Unable to report port forward error: {e:#}");
292 }
293 }
294 }
295 if let Err(e) = error.close().await {
296 debug!("Unable to close port forward error stream: {e:#}");
297 }
298 }
299
300 async fn copy(
305 early: Early,
306 mut from_client: StreamReceiver,
307 mut to_client: StreamSender,
308 connection: TcpStream,
309 ) -> Result<()> {
310 let (mut from_container, mut to_container) = connection.into_split();
311
312 let upstream = async {
313 Self::write_input(early, &mut from_client, &mut to_container).await?;
314 if !from_client.is_reset() {
315 to_container
316 .shutdown()
317 .await
318 .context("close the connection to the pod")?;
319 }
320 anyhow::Ok(())
321 };
322
323 let downstream = async {
324 let mut buf = BytesMut::new();
325 loop {
326 let data = select! {
327 data = Self::read_pod(&mut from_container, &mut buf) => data?,
328 () = to_client.reset_by_peer() => return Ok(()),
330 };
331 let Some(data) = data else {
332 break;
333 };
334 if let Err(e) = to_client.send(data).await {
335 return Self::unless_reset(&to_client, e);
336 }
337 }
338 match to_client.close().await {
339 Ok(()) => Ok(()),
340 Err(e) => Self::unless_reset(&to_client, e),
341 }
342 };
343
344 let mut upstream = pin!(upstream);
345 let mut downstream = pin!(downstream);
346 select! {
347 result = &mut downstream => {
348 result?;
349 if time::timeout(CLOSE_GRACE_PERIOD, upstream).await.is_err() {
350 debug!("Client did not close its side of the connection");
351 }
352 Ok(())
353 }
354 result = &mut upstream => match result {
356 Ok(()) => {
357 match time::timeout(HALF_CLOSE_GRACE_PERIOD, downstream).await {
358 Ok(result) => result,
359 Err(_) => {
360 debug!("The pod did not close its side of the connection");
361 Ok(())
362 }
363 }
364 }
365 Err(e) => Self::upstream_failed(e, downstream).await,
366 }
367 }
368 }
369
370 fn unless_reset(sender: &StreamSender, e: anyhow::Error) -> Result<()> {
372 if sender.is_reset() { Ok(()) } else { Err(e) }
373 }
374}