Skip to main content

vector/sources/util/net/tcp/
mod.rs

1pub mod request_limiter;
2
3use std::{io, mem::drop, net::SocketAddr, num::NonZeroU64, time::Duration};
4
5use bytes::Bytes;
6use futures::{FutureExt, StreamExt, future::BoxFuture};
7use futures_util::future::OptionFuture;
8use ipnet::IpNet;
9use listenfd::ListenFd;
10use smallvec::SmallVec;
11use socket2::SockRef;
12use tokio::{
13    io::AsyncWriteExt,
14    net::{TcpListener, TcpStream},
15    time::sleep,
16};
17use tokio_util::codec::Decoder;
18use tracing::Instrument;
19use vector_lib::{
20    EstimatedJsonEncodedSizeOf,
21    codecs::{ReadyFrames, StreamDecodingError, internal_events::DecoderFramingError},
22    config::{LegacyKey, LogNamespace, SourceAcknowledgementsConfig},
23    event::{BatchNotifier, BatchStatus, Event},
24    finalization::AddBatchNotifier,
25    lookup::{OwnedValuePath, path},
26    shutdown::ShutdownSignal,
27    source_sender::SourceSender,
28    tcp::TcpKeepaliveConfig,
29    tls::{
30        CertificateMetadata, MaybeTlsIncomingStream, MaybeTlsListener, MaybeTlsSettings,
31        TlsAcceptorReloader,
32    },
33};
34use vrl::value::ObjectMap;
35
36use self::request_limiter::RequestLimiter;
37use super::SocketListenAddr;
38use crate::{
39    config::SourceContext,
40    internal_events::{
41        ConnectionOpen, OpenGauge, SocketBindError, SocketEventsReceived, SocketMode,
42        SocketReceiveError, StreamClosedError, TcpBytesReceived, TcpSendAckError,
43        TcpSocketTlsConnectionError, TcpSocketTlsHandshakeTimeout, TcpSourceConnectionClosed,
44    },
45    net::is_graceful_tls_shutdown,
46    sources::util::{AfterReadExt, LenientFramedRead},
47};
48
49pub const MAX_IN_FLIGHT_EVENTS_TARGET: usize = 100_000;
50
51pub async fn try_bind_tcp_listener(
52    addr: SocketListenAddr,
53    mut listenfd: ListenFd,
54    tls: &MaybeTlsSettings,
55    tls_reloader: Option<TlsAcceptorReloader>,
56    allowlist: Option<Vec<IpNet>>,
57) -> crate::Result<MaybeTlsListener> {
58    match addr {
59        SocketListenAddr::SocketAddr(addr) => tls
60            .bind_reloadable(&addr, tls_reloader)
61            .await
62            .map_err(Into::into),
63        SocketListenAddr::SystemdFd(offset) => match listenfd.take_tcp_listener(offset)? {
64            Some(listener) => TcpListener::from_std(listener)
65                .map(Into::into)
66                .map_err(Into::into),
67            None => {
68                Err(io::Error::new(io::ErrorKind::AddrInUse, "systemd fd already consumed").into())
69            }
70        },
71    }
72    .map(|listener| listener.with_allowlist(allowlist))
73}
74
75#[derive(Clone, Copy, Eq, PartialEq)]
76pub enum TcpSourceAck {
77    Ack,
78    Error,
79    Reject,
80}
81
82pub trait TcpSourceAcker {
83    fn build_ack(self, ack: TcpSourceAck) -> Option<Bytes>;
84}
85
86pub struct TcpNullAcker;
87
88impl TcpSourceAcker for TcpNullAcker {
89    // This function builds an acknowledgement from the source data in
90    // the acker and the given acknowledgement code.
91    fn build_ack(self, _ack: TcpSourceAck) -> Option<Bytes> {
92        None
93    }
94}
95
96pub trait TcpSource: Clone + Send + Sync + 'static
97where
98    <<Self as TcpSource>::Decoder as tokio_util::codec::Decoder>::Item: std::marker::Send,
99{
100    // Should be default: `std::io::Error`.
101    // Right now this is unstable: https://github.com/rust-lang/rust/issues/29661
102    type Error: From<io::Error>
103        + StreamDecodingError
104        + std::fmt::Debug
105        + std::fmt::Display
106        + Send
107        + Unpin;
108    type Item: Into<SmallVec<[Event; 1]>> + Send + Unpin;
109    type Decoder: Decoder<Item = (Self::Item, usize), Error = Self::Error> + Send + 'static;
110    type Acker: TcpSourceAcker + Send;
111
112    fn decoder(&self) -> Self::Decoder;
113
114    fn handle_events(&self, _events: &mut [Event], _host: std::net::SocketAddr) {}
115
116    fn build_acker(&self, item: &[Self::Item]) -> Self::Acker;
117
118    #[allow(clippy::too_many_arguments)]
119    fn run(
120        self,
121        addr: SocketListenAddr,
122        keepalive: Option<TcpKeepaliveConfig>,
123        shutdown_timeout_secs: Duration,
124        tls: MaybeTlsSettings,
125        tls_reloader: Option<TlsAcceptorReloader>,
126        tls_client_metadata_key: Option<OwnedValuePath>,
127        receive_buffer_bytes: Option<usize>,
128        max_connection_duration_secs: Option<u64>,
129        tls_handshake_timeout_secs: Option<NonZeroU64>,
130        cx: SourceContext,
131        acknowledgements: SourceAcknowledgementsConfig,
132        max_connections: Option<u32>,
133        allowlist: Option<Vec<IpNet>>,
134        source_name: &'static str,
135        log_namespace: LogNamespace,
136    ) -> crate::Result<crate::sources::Source> {
137        let acknowledgements = cx.do_acknowledgements(acknowledgements);
138
139        Ok(Box::pin(async move {
140            let listenfd = ListenFd::from_env();
141            let listener = try_bind_tcp_listener(addr, listenfd, &tls, tls_reloader, allowlist)
142                .await
143                .map_err(|error| {
144                    emit!(SocketBindError {
145                        mode: SocketMode::Tcp,
146                        error: &error,
147                    })
148                })?;
149
150            info!(
151                message = "Listening.",
152                addr = %listener
153                    .local_addr()
154                    .map(SocketListenAddr::SocketAddr)
155                    .unwrap_or(addr)
156            );
157
158            let tripwire = cx.shutdown.clone();
159            let tripwire = async move {
160                _ = tripwire.await;
161                sleep(shutdown_timeout_secs).await;
162            }
163            .shared();
164
165            let connection_gauge = OpenGauge::new();
166            let shutdown_clone = cx.shutdown.clone();
167
168            let request_limiter =
169                RequestLimiter::new(MAX_IN_FLIGHT_EVENTS_TARGET, crate::num_threads());
170
171            listener
172                .accept_stream_limited(max_connections)
173                .take_until(shutdown_clone)
174                .for_each(move |(connection, tcp_connection_permit)| {
175                    let shutdown_signal = cx.shutdown.clone();
176                    let tripwire = tripwire.clone();
177                    let source = self.clone();
178                    let out = cx.out.clone();
179                    let connection_gauge = connection_gauge.clone();
180                    let request_limiter = request_limiter.clone();
181                    let tls_client_metadata_key = tls_client_metadata_key.clone();
182
183                    async move {
184                        let socket = match connection {
185                            Ok(socket) => socket,
186                            Err(error) => {
187                                emit!(SocketReceiveError {
188                                    mode: SocketMode::Tcp,
189                                    error: &error
190                                });
191                                return;
192                            }
193                        };
194
195                        let peer_addr = socket.peer_addr();
196                        let span = info_span!("connection", %peer_addr);
197
198                        let tripwire = tripwire
199                            .map(move |_| {
200                                info!(
201                                    message = "Resetting connection (still open after seconds).",
202                                    seconds = ?shutdown_timeout_secs
203                                );
204                            })
205                            .boxed();
206
207                        span.clone().in_scope(|| {
208                            debug!(message = "Accepted a new connection.", peer_addr = %peer_addr);
209
210                            let open_token =
211                                connection_gauge.open(|count| emit!(ConnectionOpen { count }));
212
213                            let fut = handle_stream(
214                                shutdown_signal,
215                                socket,
216                                keepalive,
217                                receive_buffer_bytes,
218                                max_connection_duration_secs,
219                                tls_handshake_timeout_secs,
220                                source,
221                                tripwire,
222                                peer_addr,
223                                out,
224                                acknowledgements,
225                                request_limiter,
226                                tls_client_metadata_key.clone(),
227                                source_name,
228                                log_namespace,
229                            );
230
231                            tokio::spawn(
232                                fut.map(move |()| {
233                                    drop(open_token);
234                                    // Paired with the ConnectionOpen emit above:
235                                    // fires exactly once per accepted connection,
236                                    // including paths that return early from
237                                    // handle_stream (TLS handshake failure,
238                                    // shutdown during handshake).
239                                    emit!(TcpSourceConnectionClosed);
240                                    drop(tcp_connection_permit);
241                                })
242                                .instrument(span.or_current()),
243                            );
244                        });
245                    }
246                })
247                .map(Ok)
248                .await
249        }))
250    }
251}
252
253#[allow(clippy::too_many_arguments)]
254async fn handle_stream<T>(
255    mut shutdown_signal: ShutdownSignal,
256    mut socket: MaybeTlsIncomingStream<TcpStream>,
257    keepalive: Option<TcpKeepaliveConfig>,
258    receive_buffer_bytes: Option<usize>,
259    max_connection_duration_secs: Option<u64>,
260    tls_handshake_timeout_secs: Option<NonZeroU64>,
261    source: T,
262    mut tripwire: BoxFuture<'static, ()>,
263    peer_addr: SocketAddr,
264    mut out: SourceSender,
265    acknowledgements: bool,
266    request_limiter: RequestLimiter,
267    tls_client_metadata_key: Option<OwnedValuePath>,
268    source_name: &'static str,
269    log_namespace: LogNamespace,
270) where
271    <<T as TcpSource>::Decoder as tokio_util::codec::Decoder>::Item: std::marker::Send,
272    T: TcpSource,
273{
274    let handshake_timeout = OptionFuture::from(
275        tls_handshake_timeout_secs.map(|secs| tokio::time::sleep(Duration::from_secs(secs.get()))),
276    );
277    tokio::pin!(handshake_timeout);
278
279    tokio::select! {
280        result = socket.handshake() => {
281            if let Err(error) = result {
282                emit!(TcpSocketTlsConnectionError { error });
283                return;
284            }
285        },
286        Some(_) = &mut handshake_timeout => {
287            emit!(TcpSocketTlsHandshakeTimeout {
288                peer_addr,
289                timeout: Duration::from_secs(
290                    tls_handshake_timeout_secs.map_or(0, NonZeroU64::get),
291                ),
292            });
293            return;
294        },
295        _ = &mut shutdown_signal => {
296            return;
297        }
298    };
299
300    if let Some(keepalive) = keepalive
301        && let Err(error) = socket.set_keepalive(keepalive)
302    {
303        warn!(message = "Failed configuring TCP keepalive.", %error);
304    }
305
306    if let Some(receive_buffer_bytes) = receive_buffer_bytes
307        && let Err(error) = socket.set_receive_buffer_bytes(receive_buffer_bytes)
308    {
309        warn!(message = "Failed configuring receive buffer size on TCP socket.", %error);
310    }
311
312    let socket = socket.after_read(move |byte_size| {
313        emit!(TcpBytesReceived {
314            byte_size,
315            peer_addr
316        });
317    });
318
319    let certificate_metadata = socket
320        .get_ref()
321        .ssl_stream()
322        .and_then(|stream| stream.ssl().peer_certificate())
323        .map(CertificateMetadata::from);
324
325    let reader = LenientFramedRead::new(socket, source.decoder());
326
327    let mut reader = ReadyFrames::new(reader);
328
329    let connection_close_timeout = OptionFuture::from(
330        max_connection_duration_secs
331            .map(|timeout_secs| tokio::time::sleep(Duration::from_secs(timeout_secs))),
332    );
333
334    tokio::pin!(connection_close_timeout);
335
336    loop {
337        let mut permit = tokio::select! {
338            _ = &mut tripwire => break,
339            Some(_) = &mut connection_close_timeout  => {
340                if close_socket(reader.get_ref().get_ref().get_ref()) {
341                    break;
342                }
343                None
344            },
345            _ = &mut shutdown_signal => {
346                if close_socket(reader.get_ref().get_ref().get_ref()) {
347                    break;
348                }
349                None
350            },
351            permit = request_limiter.acquire() => {
352                Some(permit)
353            }
354            else => break,
355        };
356
357        let timeout = tokio::time::sleep(Duration::from_millis(10));
358        tokio::pin!(timeout);
359
360        tokio::select! {
361            _ = &mut tripwire => break,
362            _ = &mut shutdown_signal => {
363                if close_socket(reader.get_ref().get_ref().get_ref()) {
364                    break;
365                }
366            },
367            _ = &mut timeout => {
368                // This connection is currently holding a permit, but has not received data for some time. Release
369                // the permit to let another connection try
370                continue;
371            }
372            res = reader.next() => {
373                match res {
374                    Some(Ok((frames, _byte_size))) => {
375                        let _num_frames = frames.len();
376                        let acker = source.build_acker(&frames);
377                        let (batch, receiver) = BatchNotifier::maybe_new_with_receiver(acknowledgements);
378
379                        let mut events = frames.into_iter().flat_map(Into::into).collect::<Vec<Event>>();
380                        let count = events.len();
381
382                        emit!(SocketEventsReceived {
383                            mode: SocketMode::Tcp,
384                            byte_size: events.estimated_json_encoded_size_of(),
385                            count,
386                        });
387
388                        if let Some(permit) = &mut permit {
389                            // Note that this is intentionally not the "number of events in a single request", but rather
390                            // the "number of events currently available". This may contain events from multiple events,
391                            // but it should always contain all events from each request.
392                            permit.decoding_finished(events.len());
393                        }
394
395                        if let Some(batch) = batch {
396                            for event in &mut events {
397                                event.add_batch_notifier(batch.clone());
398                            }
399                        }
400
401
402                        if let Some(certificate_metadata) = &certificate_metadata {
403                            let mut metadata = ObjectMap::new();
404                            metadata.insert("subject".into(), certificate_metadata.subject().into());
405                            for event in &mut events {
406                                let log = event.as_mut_log();
407
408                                log_namespace.insert_source_metadata(
409                                    source_name,
410                                    log,
411                                    tls_client_metadata_key.as_ref().map(LegacyKey::Overwrite),
412                                    path!("tls_client_metadata"),
413                                    metadata.clone()
414                                );
415                            }
416                        }
417
418                        source.handle_events(&mut events, peer_addr);
419                        match out.send_batch(events).await {
420                            Ok(_) => {
421                                let ack = match receiver {
422                                    None => TcpSourceAck::Ack,
423                                    Some(receiver) =>
424                                        match receiver.await {
425                                            BatchStatus::Delivered => TcpSourceAck::Ack,
426                                            BatchStatus::Errored => {TcpSourceAck::Error},
427                                            BatchStatus::Rejected => {
428                                                // Sinks are responsible for emitting ComponentEventsDropped.
429                                                TcpSourceAck::Reject
430                                            }
431                                        }
432                                };
433                                if let Some(ack_bytes) = acker.build_ack(ack){
434                                    let stream = reader.get_mut().get_mut();
435                                    if let Err(error) = stream.write_all(&ack_bytes).await {
436                                        // Per spec, `*Error` events MUST only be
437                                        // emitted on real errors. A peer-initiated
438                                        // graceful TLS shutdown during the ack
439                                        // write is a lifecycle event, not an error
440                                        // — log at warn and skip the emit.
441                                        if is_graceful_tls_shutdown(&error) {
442                                            warn!(
443                                                message = "Connection closed by peer before acknowledgement could be sent.",
444                                                error = %error,
445                                            );
446                                        } else {
447                                            emit!(TcpSendAckError { error });
448                                        }
449                                        break;
450                                    }
451                                }
452                                if ack != TcpSourceAck::Ack {
453                                    break;
454                                }
455                            }
456                            Err(_) => {
457                                emit!(StreamClosedError { count });
458                                break;
459                            }
460                        }
461                    }
462                    Some(Err(error)) => {
463                        if !<<T as TcpSource>::Error as StreamDecodingError>::can_continue(&error) {
464                            emit!(DecoderFramingError { error });
465                            break;
466                        }
467                    }
468                    None => {
469                        debug!("Connection closed.");
470                        break
471                    },
472                }
473            }
474            else => break,
475        }
476
477        drop(permit);
478    }
479}
480
481fn close_socket(socket: &MaybeTlsIncomingStream<TcpStream>) -> bool {
482    debug!("Start graceful shutdown.");
483    // Close our write part of TCP socket to signal the other side
484    // that it should stop writing and close the channel.
485    if let Some(stream) = socket.get_ref() {
486        let socket = SockRef::from(stream);
487        if let Err(error) = socket.shutdown(std::net::Shutdown::Write) {
488            warn!(message = "Failed in signalling to the other side to close the TCP channel.", %error);
489        }
490        false
491    } else {
492        // Connection hasn't yet been established so we are done here.
493        debug!("Closing connection that hasn't yet been fully established.");
494        true
495    }
496}