Skip to main content

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

1pub mod request_limiter;
2
3use std::{io, mem::drop, net::SocketAddr, 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, 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        cx: SourceContext,
130        acknowledgements: SourceAcknowledgementsConfig,
131        max_connections: Option<u32>,
132        allowlist: Option<Vec<IpNet>>,
133        source_name: &'static str,
134        log_namespace: LogNamespace,
135    ) -> crate::Result<crate::sources::Source> {
136        let acknowledgements = cx.do_acknowledgements(acknowledgements);
137
138        Ok(Box::pin(async move {
139            let listenfd = ListenFd::from_env();
140            let listener = try_bind_tcp_listener(addr, listenfd, &tls, tls_reloader, allowlist)
141                .await
142                .map_err(|error| {
143                    emit!(SocketBindError {
144                        mode: SocketMode::Tcp,
145                        error: &error,
146                    })
147                })?;
148
149            info!(
150                message = "Listening.",
151                addr = %listener
152                    .local_addr()
153                    .map(SocketListenAddr::SocketAddr)
154                    .unwrap_or(addr)
155            );
156
157            let tripwire = cx.shutdown.clone();
158            let tripwire = async move {
159                _ = tripwire.await;
160                sleep(shutdown_timeout_secs).await;
161            }
162            .shared();
163
164            let connection_gauge = OpenGauge::new();
165            let shutdown_clone = cx.shutdown.clone();
166
167            let request_limiter =
168                RequestLimiter::new(MAX_IN_FLIGHT_EVENTS_TARGET, crate::num_threads());
169
170            listener
171                .accept_stream_limited(max_connections)
172                .take_until(shutdown_clone)
173                .for_each(move |(connection, tcp_connection_permit)| {
174                    let shutdown_signal = cx.shutdown.clone();
175                    let tripwire = tripwire.clone();
176                    let source = self.clone();
177                    let out = cx.out.clone();
178                    let connection_gauge = connection_gauge.clone();
179                    let request_limiter = request_limiter.clone();
180                    let tls_client_metadata_key = tls_client_metadata_key.clone();
181
182                    async move {
183                        let socket = match connection {
184                            Ok(socket) => socket,
185                            Err(error) => {
186                                emit!(SocketReceiveError {
187                                    mode: SocketMode::Tcp,
188                                    error: &error
189                                });
190                                return;
191                            }
192                        };
193
194                        let peer_addr = socket.peer_addr();
195                        let span = info_span!("connection", %peer_addr);
196
197                        let tripwire = tripwire
198                            .map(move |_| {
199                                info!(
200                                    message = "Resetting connection (still open after seconds).",
201                                    seconds = ?shutdown_timeout_secs
202                                );
203                            })
204                            .boxed();
205
206                        span.clone().in_scope(|| {
207                            debug!(message = "Accepted a new connection.", peer_addr = %peer_addr);
208
209                            let open_token =
210                                connection_gauge.open(|count| emit!(ConnectionOpen { count }));
211
212                            let fut = handle_stream(
213                                shutdown_signal,
214                                socket,
215                                keepalive,
216                                receive_buffer_bytes,
217                                max_connection_duration_secs,
218                                source,
219                                tripwire,
220                                peer_addr,
221                                out,
222                                acknowledgements,
223                                request_limiter,
224                                tls_client_metadata_key.clone(),
225                                source_name,
226                                log_namespace,
227                            );
228
229                            tokio::spawn(
230                                fut.map(move |()| {
231                                    drop(open_token);
232                                    // Paired with the ConnectionOpen emit above:
233                                    // fires exactly once per accepted connection,
234                                    // including paths that return early from
235                                    // handle_stream (TLS handshake failure,
236                                    // shutdown during handshake).
237                                    emit!(TcpSourceConnectionClosed);
238                                    drop(tcp_connection_permit);
239                                })
240                                .instrument(span.or_current()),
241                            );
242                        });
243                    }
244                })
245                .map(Ok)
246                .await
247        }))
248    }
249}
250
251#[allow(clippy::too_many_arguments)]
252async fn handle_stream<T>(
253    mut shutdown_signal: ShutdownSignal,
254    mut socket: MaybeTlsIncomingStream<TcpStream>,
255    keepalive: Option<TcpKeepaliveConfig>,
256    receive_buffer_bytes: Option<usize>,
257    max_connection_duration_secs: Option<u64>,
258    source: T,
259    mut tripwire: BoxFuture<'static, ()>,
260    peer_addr: SocketAddr,
261    mut out: SourceSender,
262    acknowledgements: bool,
263    request_limiter: RequestLimiter,
264    tls_client_metadata_key: Option<OwnedValuePath>,
265    source_name: &'static str,
266    log_namespace: LogNamespace,
267) where
268    <<T as TcpSource>::Decoder as tokio_util::codec::Decoder>::Item: std::marker::Send,
269    T: TcpSource,
270{
271    tokio::select! {
272        result = socket.handshake() => {
273            if let Err(error) = result {
274                emit!(TcpSocketTlsConnectionError { error });
275                return;
276            }
277        },
278        _ = &mut shutdown_signal => {
279            return;
280        }
281    };
282
283    if let Some(keepalive) = keepalive
284        && let Err(error) = socket.set_keepalive(keepalive)
285    {
286        warn!(message = "Failed configuring TCP keepalive.", %error);
287    }
288
289    if let Some(receive_buffer_bytes) = receive_buffer_bytes
290        && let Err(error) = socket.set_receive_buffer_bytes(receive_buffer_bytes)
291    {
292        warn!(message = "Failed configuring receive buffer size on TCP socket.", %error);
293    }
294
295    let socket = socket.after_read(move |byte_size| {
296        emit!(TcpBytesReceived {
297            byte_size,
298            peer_addr
299        });
300    });
301
302    let certificate_metadata = socket
303        .get_ref()
304        .ssl_stream()
305        .and_then(|stream| stream.ssl().peer_certificate())
306        .map(CertificateMetadata::from);
307
308    let reader = LenientFramedRead::new(socket, source.decoder());
309
310    let mut reader = ReadyFrames::new(reader);
311
312    let connection_close_timeout = OptionFuture::from(
313        max_connection_duration_secs
314            .map(|timeout_secs| tokio::time::sleep(Duration::from_secs(timeout_secs))),
315    );
316
317    tokio::pin!(connection_close_timeout);
318
319    loop {
320        let mut permit = tokio::select! {
321            _ = &mut tripwire => break,
322            Some(_) = &mut connection_close_timeout  => {
323                if close_socket(reader.get_ref().get_ref().get_ref()) {
324                    break;
325                }
326                None
327            },
328            _ = &mut shutdown_signal => {
329                if close_socket(reader.get_ref().get_ref().get_ref()) {
330                    break;
331                }
332                None
333            },
334            permit = request_limiter.acquire() => {
335                Some(permit)
336            }
337            else => break,
338        };
339
340        let timeout = tokio::time::sleep(Duration::from_millis(10));
341        tokio::pin!(timeout);
342
343        tokio::select! {
344            _ = &mut tripwire => break,
345            _ = &mut shutdown_signal => {
346                if close_socket(reader.get_ref().get_ref().get_ref()) {
347                    break;
348                }
349            },
350            _ = &mut timeout => {
351                // This connection is currently holding a permit, but has not received data for some time. Release
352                // the permit to let another connection try
353                continue;
354            }
355            res = reader.next() => {
356                match res {
357                    Some(Ok((frames, _byte_size))) => {
358                        let _num_frames = frames.len();
359                        let acker = source.build_acker(&frames);
360                        let (batch, receiver) = BatchNotifier::maybe_new_with_receiver(acknowledgements);
361
362                        let mut events = frames.into_iter().flat_map(Into::into).collect::<Vec<Event>>();
363                        let count = events.len();
364
365                        emit!(SocketEventsReceived {
366                            mode: SocketMode::Tcp,
367                            byte_size: events.estimated_json_encoded_size_of(),
368                            count,
369                        });
370
371                        if let Some(permit) = &mut permit {
372                            // Note that this is intentionally not the "number of events in a single request", but rather
373                            // the "number of events currently available". This may contain events from multiple events,
374                            // but it should always contain all events from each request.
375                            permit.decoding_finished(events.len());
376                        }
377
378                        if let Some(batch) = batch {
379                            for event in &mut events {
380                                event.add_batch_notifier(batch.clone());
381                            }
382                        }
383
384
385                        if let Some(certificate_metadata) = &certificate_metadata {
386                            let mut metadata = ObjectMap::new();
387                            metadata.insert("subject".into(), certificate_metadata.subject().into());
388                            for event in &mut events {
389                                let log = event.as_mut_log();
390
391                                log_namespace.insert_source_metadata(
392                                    source_name,
393                                    log,
394                                    tls_client_metadata_key.as_ref().map(LegacyKey::Overwrite),
395                                    path!("tls_client_metadata"),
396                                    metadata.clone()
397                                );
398                            }
399                        }
400
401                        source.handle_events(&mut events, peer_addr);
402                        match out.send_batch(events).await {
403                            Ok(_) => {
404                                let ack = match receiver {
405                                    None => TcpSourceAck::Ack,
406                                    Some(receiver) =>
407                                        match receiver.await {
408                                            BatchStatus::Delivered => TcpSourceAck::Ack,
409                                            BatchStatus::Errored => {TcpSourceAck::Error},
410                                            BatchStatus::Rejected => {
411                                                // Sinks are responsible for emitting ComponentEventsDropped.
412                                                TcpSourceAck::Reject
413                                            }
414                                        }
415                                };
416                                if let Some(ack_bytes) = acker.build_ack(ack){
417                                    let stream = reader.get_mut().get_mut();
418                                    if let Err(error) = stream.write_all(&ack_bytes).await {
419                                        // Per spec, `*Error` events MUST only be
420                                        // emitted on real errors. A peer-initiated
421                                        // graceful TLS shutdown during the ack
422                                        // write is a lifecycle event, not an error
423                                        // — log at warn and skip the emit.
424                                        if is_graceful_tls_shutdown(&error) {
425                                            warn!(
426                                                message = "Connection closed by peer before acknowledgement could be sent.",
427                                                error = %error,
428                                            );
429                                        } else {
430                                            emit!(TcpSendAckError { error });
431                                        }
432                                        break;
433                                    }
434                                }
435                                if ack != TcpSourceAck::Ack {
436                                    break;
437                                }
438                            }
439                            Err(_) => {
440                                emit!(StreamClosedError { count });
441                                break;
442                            }
443                        }
444                    }
445                    Some(Err(error)) => {
446                        if !<<T as TcpSource>::Error as StreamDecodingError>::can_continue(&error) {
447                            emit!(DecoderFramingError { error });
448                            break;
449                        }
450                    }
451                    None => {
452                        debug!("Connection closed.");
453                        break
454                    },
455                }
456            }
457            else => break,
458        }
459
460        drop(permit);
461    }
462}
463
464fn close_socket(socket: &MaybeTlsIncomingStream<TcpStream>) -> bool {
465    debug!("Start graceful shutdown.");
466    // Close our write part of TCP socket to signal the other side
467    // that it should stop writing and close the channel.
468    if let Some(stream) = socket.get_ref() {
469        let socket = SockRef::from(stream);
470        if let Err(error) = socket.shutdown(std::net::Shutdown::Write) {
471            warn!(message = "Failed in signalling to the other side to close the TCP channel.", %error);
472        }
473        false
474    } else {
475        // Connection hasn't yet been established so we are done here.
476        debug!("Closing connection that hasn't yet been fully established.");
477        true
478    }
479}