folly/folly/net/TcpInfo.h

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <chrono>
#include <system_error>

#include <folly/Expected.h>
#include <folly/Optional.h>
#include <folly/String.h>
#include <folly/net/NetOpsDispatcher.h>
#include <folly/net/NetworkSocket.h>
#include <folly/net/TcpInfoTypes.h>

namespace folly {

/**
 * Abstraction layer for capturing current TCP and congestion control state.
 *
 * Fetches information from four different resources:
 *   - TCP_INFO (state of TCP)
 *   - TCP_CONGESTION (name of congestion control algorithm)
 *   - TCP_CC_INFO (details for a given congestion control algorithm)
 *   - SIOCOUTQ/SIOCINQ (socket buffers)
 *
 * To save space, the structure only allocates fields for which the underlying
 * platform supports lookups. For instance, if TCP_CONGESTION is not supported,
 * then the TcpInfo structure will not have fields to store the CC name / type.
 *
 * This abstraction layer solves two problems:
 *
 *   1. It unblocks use of the latest tcp_info structs and related structs.
 *
 *      As of 2020, the tcp_info struct shipped with glibc
 *      (sysdeps/gnu/netinet/tcp.h) has not been updated since 2007 due to
 *      compatibility concerns; see commit titled "Update netinet/tcp.h from
 *      Linux 4.18" in glibc repository. This creates scenarios where fields
 *      that have long been available in the kernel ABI cannot be accessed.
 *      Even if glibc does eventually update the tcp_info shipped, we don't
 *      want to be limited to their update cycle.
 *
 *      folly::TcpInfo solves this in two ways:
 *         - First, TcpInfoTypes.h contains a copy of the latest tcp_info struct
 *           for Linux, and folly::TcpInfo always uses this struct for lookups;
 *           this decouples TcpInfo from glibc's / the platform's tcp_info.
 *
 *         - Second, folly::TcpInfo determines which fields in the struct the
 *           kernel ABI populated (and thus which fields are valid) based on the
 *           number of bytes the kernel ABI copies into the struct during the
 *           corresponding getsockopt operation. When a field is accessed
 *           through getFieldAsOptUInt64 or through an accessor, folly::TcpInfo
 *           returns an empty optional if the field is unavailable at run-time.
 *           In this manner, folly::TcpInfo enables the latest struct to always
 *           be used while ensuring that programs can determine at run-time
 *           which fields are available for use --- there's no risk of a program
 *           assuming that a field is valid when it in fact was never
 *           initialized/set by the ABI.
 *
 *   2. Eliminates platform differences while still retaining details.
 *
 *      The tcp_info structure varies significantly between Apple and Linux.
 *      folly::TcpInfo exposes a subset of tcp_info and other fields through
 *      accessors that abstract these differences, and reduce potential errors
 *      (e.g., Apple stores srtt in milliseconds, Linux stores in microseconds).
 *      When a field is unavailable on a platform, the accessor returns an empty
 *      optional.
 *
 *      In parallel, the underlying structures remain accessible and can be
 *      safely accessed through the appropriate getFieldAsOptUInt64(...). This
 *      enables platform-specific code to have full access to the structure
 *      while also benefiting from folly::TcpInfo's knowledge of whether a
 *      given field was populated by the ABI at run-time.
 */
struct TcpInfo {};

} // namespace folly