diff --git a/mobile/library/cc/engine_builder.cc b/mobile/library/cc/engine_builder.cc index a59e6c3c7b8b..fd377107b3ab 100644 --- a/mobile/library/cc/engine_builder.cc +++ b/mobile/library/cc/engine_builder.cc @@ -240,8 +240,13 @@ EngineBuilder& EngineBuilder::setUseGroIfAvailable(bool use_gro_if_available) { return *this; } -EngineBuilder& EngineBuilder::setSocketReceiveBufferSize(int32_t size) { - socket_receive_buffer_size_ = size; +EngineBuilder& EngineBuilder::setUdpSocketReceiveBufferSize(int32_t size) { + udp_socket_receive_buffer_size_ = size; + return *this; +} + +EngineBuilder& EngineBuilder::setUdpSocketSendBufferSize(int32_t size) { + udp_socket_send_buffer_size_ = size; return *this; } @@ -721,19 +726,27 @@ std::unique_ptr EngineBuilder::generate ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"] .PackFrom(alpn_options); - // Set the upstream connections socket receive buffer size. The operating system defaults are - // usually too small for QUIC. - // NOTE: An H3 cluster can also establish H2 connections (for example, if the H3 connection is - // marked as broken in the ConnectivityGrid). This option would apply to all connections in the - // cluster, meaning H2 TCP connections buffer size would also be set to 1MB. On the platforms - // we've tested, IPPROTO_UDP cannot be used as a level for the SO_RCVBUF option. - envoy::config::core::v3::SocketOption* rcv_buf_sock_opt = + // Set the upstream connections UDP socket receive buffer size. The operating system defaults + // are usually too small for QUIC. + envoy::config::core::v3::SocketOption* udp_rcv_buf_sock_opt = + base_cluster->mutable_upstream_bind_config()->add_socket_options(); + udp_rcv_buf_sock_opt->set_name(SO_RCVBUF); + udp_rcv_buf_sock_opt->set_level(SOL_SOCKET); + udp_rcv_buf_sock_opt->set_int_value(udp_socket_receive_buffer_size_); + // Only apply the socket option to the datagram socket. + udp_rcv_buf_sock_opt->mutable_type()->mutable_datagram(); + udp_rcv_buf_sock_opt->set_description( + absl::StrCat("UDP SO_RCVBUF = ", udp_socket_receive_buffer_size_, " bytes")); + + envoy::config::core::v3::SocketOption* udp_snd_buf_sock_opt = base_cluster->mutable_upstream_bind_config()->add_socket_options(); - rcv_buf_sock_opt->set_name(SO_RCVBUF); - rcv_buf_sock_opt->set_level(SOL_SOCKET); - rcv_buf_sock_opt->set_int_value(socket_receive_buffer_size_); - rcv_buf_sock_opt->set_description( - absl::StrCat("SO_RCVBUF = ", socket_receive_buffer_size_, " bytes")); + udp_snd_buf_sock_opt->set_name(SO_SNDBUF); + udp_snd_buf_sock_opt->set_level(SOL_SOCKET); + udp_snd_buf_sock_opt->set_int_value(udp_socket_send_buffer_size_); + // Only apply the socket option to the datagram socket. + udp_snd_buf_sock_opt->mutable_type()->mutable_datagram(); + udp_snd_buf_sock_opt->set_description( + absl::StrCat("UDP SO_SNDBUF = ", udp_socket_send_buffer_size_, " bytes")); // Set the network service type on iOS, if supplied. #if defined(__APPLE__) if (ios_network_service_type_ > 0) { diff --git a/mobile/library/cc/engine_builder.h b/mobile/library/cc/engine_builder.h index 5d94d71aee6c..174a57a8b2df 100644 --- a/mobile/library/cc/engine_builder.h +++ b/mobile/library/cc/engine_builder.h @@ -68,7 +68,8 @@ class EngineBuilder { EngineBuilder& enableDrainPostDnsRefresh(bool drain_post_dns_refresh_on); // Sets whether to use GRO for upstream UDP sockets (QUIC/HTTP3). EngineBuilder& setUseGroIfAvailable(bool use_gro_if_available); - EngineBuilder& setSocketReceiveBufferSize(int32_t size); + EngineBuilder& setUdpSocketReceiveBufferSize(int32_t size); + EngineBuilder& setUdpSocketSendBufferSize(int32_t size); EngineBuilder& enforceTrustChainVerification(bool trust_chain_verification_on); EngineBuilder& setUpstreamTlsSni(std::string sni); EngineBuilder& enablePlatformCertificatesValidation(bool platform_certificates_validation_on); @@ -182,7 +183,11 @@ class EngineBuilder { // This is the same value Cronet uses for QUIC: // https://source.chromium.org/chromium/chromium/src/+/main:net/quic/quic_context.h;drc=ccfe61524368c94b138ddf96ae8121d7eb7096cf;l=87 - int32_t socket_receive_buffer_size_ = 1024 * 1024; // 1MB + int32_t udp_socket_receive_buffer_size_ = 1024 * 1024; // 1MB + // This is the same value Cronet uses for QUIC: + // https://source.chromium.org/chromium/chromium/src/+/main:net/quic/quic_session_pool.cc;l=790-793;drc=7f04a8e033c23dede6beae129cd212e6d4473d72 + // https://source.chromium.org/chromium/chromium/src/+/main:net/third_party/quiche/src/quiche/quic/core/quic_constants.h;l=43-47;drc=34ad7f3844f882baf3d31a6bc6e300acaa0e3fc8 + int32_t udp_socket_send_buffer_size_ = 1452 * 20; }; using EngineBuilderSharedPtr = std::shared_ptr; diff --git a/mobile/test/cc/unit/envoy_config_test.cc b/mobile/test/cc/unit/envoy_config_test.cc index 9fabb192676a..376ba54d7591 100644 --- a/mobile/test/cc/unit/envoy_config_test.cc +++ b/mobile/test/cc/unit/envoy_config_test.cc @@ -331,7 +331,7 @@ TEST(TestConfig, DisableHttp3) { } #ifdef ENVOY_ENABLE_QUIC -TEST(TestConfig, SocketReceiveBufferSize) { +TEST(TestConfig, UdpSocketReceiveBufferSize) { EngineBuilder engine_builder; engine_builder.enableHttp3(true); @@ -358,8 +358,40 @@ TEST(TestConfig, SocketReceiveBufferSize) { // When using an H3 cluster, the UDP receive buffer size option should always be set. ASSERT_THAT(rcv_buf_option, NotNull()); EXPECT_EQ(rcv_buf_option->level(), SOL_SOCKET); + EXPECT_TRUE(rcv_buf_option->type().has_datagram()); EXPECT_EQ(rcv_buf_option->int_value(), 1024 * 1024 /* 1 MB */); } + +TEST(TestConfig, UdpSocketSendBufferSize) { + EngineBuilder engine_builder; + engine_builder.enableHttp3(true); + + std::unique_ptr bootstrap = engine_builder.generateBootstrap(); + Cluster const* base_cluster = nullptr; + for (const Cluster& cluster : bootstrap->static_resources().clusters()) { + if (cluster.name() == "base") { + base_cluster = &cluster; + break; + } + } + + // The base H3 cluster should always be found. + ASSERT_THAT(base_cluster, NotNull()); + + SocketOption const* snd_buf_option = nullptr; + for (const SocketOption& sock_opt : base_cluster->upstream_bind_config().socket_options()) { + if (sock_opt.name() == SO_SNDBUF) { + snd_buf_option = &sock_opt; + break; + } + } + + // When using an H3 cluster, the UDP send buffer size option should always be set. + ASSERT_THAT(snd_buf_option, NotNull()); + EXPECT_EQ(snd_buf_option->level(), SOL_SOCKET); + EXPECT_TRUE(snd_buf_option->type().has_datagram()); + EXPECT_EQ(snd_buf_option->int_value(), 1452 * 20); +} #endif TEST(TestConfig, EnablePlatformCertificatesValidation) {