Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
959cd4c
everything build
danzh1989 Aug 7, 2024
4b969c9
Merge branch 'main' into networkchange
danzh1989 Aug 8, 2024
242dc5e
finish plumbing
danzh1989 Aug 8, 2024
28e805a
add tests
danzh1989 Aug 20, 2024
a582d79
comments
danzh1989 Aug 20, 2024
1e57860
add runtime guard
danzh1989 Aug 21, 2024
e3663b2
change log
danzh1989 Aug 21, 2024
ccd0dd2
fix build
danzh1989 Aug 21, 2024
7e8e3d3
fix build again
danzh1989 Aug 21, 2024
84eeb68
more fix
danzh1989 Aug 21, 2024
2337129
fix compile option build
danzh1989 Aug 22, 2024
9725172
Merge branch 'main' into networkchange
danzh1989 Aug 22, 2024
845c19d
test coverage
danzh1989 Aug 22, 2024
462e7bd
fix build
danzh1989 Aug 22, 2024
76e0894
fix compile option build
danzh1989 Aug 23, 2024
e47c408
Merge branch 'main' into networkchange
danzh1989 Aug 27, 2024
c239b59
Merge branch 'main' into networkchange
danzh1989 Sep 4, 2024
2bf31a3
more merge fix
danzh1989 Sep 4, 2024
27058bc
comment
danzh1989 Sep 4, 2024
fe5b171
Merge branch 'main' into networkchange
danzh1989 Sep 6, 2024
2d78be5
new callback interface
danzh1989 Sep 7, 2024
f883a1c
Merge branch 'main' into networkchange
danzh1989 Sep 7, 2024
2af5cfb
dedup dispatcher post
danzh1989 Sep 11, 2024
471b7bb
Merge branch 'main' into networkchange
danzh1989 Sep 11, 2024
5ad0e26
fix unit test
danzh1989 Sep 11, 2024
ddd3739
revert some changes
danzh1989 Sep 8, 2025
c2c3909
Merge branch 'main' into networkchange
danzh1989 Sep 9, 2025
225d362
revert release note
danzh1989 Sep 9, 2025
eae7c9e
Merge branch 'main' into networkchange
danzh1989 Sep 12, 2025
ee6a0b4
observer interface change
danzh1989 Sep 12, 2025
bd3fd65
more interface changes
danzh1989 Sep 12, 2025
6815335
Merge branch 'main' into networkchange
danzh1989 Oct 3, 2025
cdc290d
revert transient connect failure handling
danzh1989 Oct 3, 2025
f668a04
remove quic_network_connectivity_observer_impl_lib
danzh1989 Oct 3, 2025
73d0b0e
build target
danzh1989 Oct 3, 2025
47d708f
revert tests
danzh1989 Oct 9, 2025
8c576fa
revert upstream BUILD
danzh1989 Oct 9, 2025
6ab8b05
revert mobile changes
danzh1989 Oct 9, 2025
3dba5e6
a disconnect interface
danzh1989 Oct 9, 2025
809ee7e
revert runtime
danzh1989 Oct 9, 2025
7c31d1e
fix build
danzh1989 Oct 9, 2025
f22a3d9
test coverage
danzh1989 Oct 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ minor_behavior_changes:
change: |
HTTP/3 alt-svc headers will now be respected from IP-address-based hostnames. This change is
guarded by runtime guard ``envoy.reloadable_features.allow_alt_svc_for_ips``.
- area: http3
Comment thread
danzh2010 marked this conversation as resolved.
change: |
Make upstream connections respond to default network change on mobile devices. This change is guarded
by runtime guard ``envoy.reloadable_features.quic_upstream_connection_handle_network_change``.
- area: lua
change: |
When Lua script executes httpCall, backpressure is exercised when receiving body from downstream client. This behavior can be reverted
Expand Down
26 changes: 25 additions & 1 deletion envoy/upstream/cluster_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@
#include "absl/container/node_hash_map.h"

namespace Envoy {

namespace Quic {

#ifdef ENVOY_ENABLE_QUIC
class EnvoyQuicNetworkObserverRegistryFactory;
class EnvoyQuicNetworkObserverRegistry;
#else
// Dumb definitions of QUIC classes if QUICHE is compiled out.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: QUICHE is always compiled in, but the QUIC parts may or may not be. So probably s/QUICHE/QUIC/?

class EnvoyQuicNetworkObserverRegistryFactory {};
class EnvoyQuicNetworkObserverRegistry {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think we should handle this conditional definition at the place where these classes are defined. Perhaps instead of conditionally building the .h/.cc files, we could wrap their contents in #ifdef so that they are always defined and we can avoid this conditional logic outside of that class. WDYT?

#endif

} // namespace Quic

namespace Upstream {

/**
Expand Down Expand Up @@ -467,6 +481,13 @@ class ClusterManager {
* Returns an EdsResourcesCache that is unique for the cluster manager.
*/
virtual Config::EdsResourcesCacheOptRef edsResourcesCache() PURE;

/**
* Create a QUIC network observer registry for each worker thread using the given factory.
* @param factory used to create a registry object.
*/
virtual void createNetworkObserverRegistries(
Envoy::Quic::EnvoyQuicNetworkObserverRegistryFactory& factory) PURE;
};

using ClusterManagerPtr = std::unique_ptr<ClusterManager>;
Expand Down Expand Up @@ -515,6 +536,8 @@ class ClusterManagerFactory {
/**
* Allocate an HTTP connection pool for the host. Pools are separated by 'priority',
* 'protocol', and 'options->hashKey()', if any.
* @param network_observer_registry if not null all the QUIC connections created by this pool
* should register to it for network events.
*/
virtual Http::ConnectionPool::InstancePtr
allocateConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host,
Expand All @@ -524,7 +547,8 @@ class ClusterManagerFactory {
const Network::ConnectionSocket::OptionsSharedPtr& options,
const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options,
TimeSource& time_source, ClusterConnectivityState& state,
Http::PersistentQuicInfoPtr& quic_info) PURE;
Http::PersistentQuicInfoPtr& quic_info,
OptRef<Quic::EnvoyQuicNetworkObserverRegistry> network_observer_registry) PURE;

/**
* Allocate a TCP connection pool for the host. Pools are separated by 'priority' and
Expand Down
3 changes: 1 addition & 2 deletions mobile/library/common/internal_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,7 @@ envoy_status_t InternalEngine::resetConnectivityState() {

envoy_status_t InternalEngine::setPreferredNetwork(NetworkType network) {
return dispatcher_->post([&, network]() -> void {
envoy_netconf_t configuration_key =
Network::ConnectivityManagerImpl::setPreferredNetwork(network);
envoy_netconf_t configuration_key = connectivity_manager_->onNetworkMadeDefault(network);
if (Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.dns_cache_set_ip_version_to_remove")) {
// The IP version to remove flag must be set first before refreshing the DNS cache so that
Expand Down
19 changes: 17 additions & 2 deletions mobile/library/common/network/BUILD
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_library", "envoy_mobile_package")
load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_library", "envoy_mobile_package", "envoy_select_enable_http3")

licenses(["notice"]) # Apache 2

envoy_mobile_package()

envoy_cc_library(
name = "envoy_mobile_quic_network_observer_registry_factory_lib",
srcs = ["envoy_mobile_quic_network_observer_registry_factory.cc"],
hdrs = ["envoy_mobile_quic_network_observer_registry_factory.h"],
repository = "@envoy",
deps = [
"@envoy//source/common/quic:envoy_quic_client_session_lib",
],
)

envoy_cc_library(
name = "connectivity_manager_lib",
srcs = [
Expand All @@ -25,7 +35,12 @@ envoy_cc_library(
"@envoy//source/common/network:addr_family_aware_socket_option_lib",
"@envoy//source/common/network:socket_option_lib",
"@envoy//source/extensions/common/dynamic_forward_proxy:dns_cache_manager_impl",
],
] + envoy_select_enable_http3(
[
":envoy_mobile_quic_network_observer_registry_factory_lib",
],
"@envoy",
),
)

envoy_cc_library(
Expand Down
43 changes: 35 additions & 8 deletions mobile/library/common/network/connectivity_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ constexpr unsigned int InitialFaultThreshold = 1;
// L7 bytes) before switching socket mode.
constexpr unsigned int MaxFaultThreshold = 3;

ConnectivityManagerImpl::ConnectivityManagerImpl(Upstream::ClusterManager& cluster_manager,
DnsCacheManagerSharedPtr dns_cache_manager)
: cluster_manager_(cluster_manager), dns_cache_manager_(dns_cache_manager),
quic_upstream_connection_handle_network_change_(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.quic_upstream_connection_handle_network_change")) {
#ifdef ENVOY_ENABLE_QUIC
quic_observer_registry_factory_ =
std::make_unique<Quic::EnvoyMobileQuicNetworkObserverRegistryFactory>();
if (quic_upstream_connection_handle_network_change_) {
cluster_manager_.createNetworkObserverRegistries(*quic_observer_registry_factory_);
}
#endif
}

ConnectivityManagerImpl::NetworkState ConnectivityManagerImpl::network_state_{
1, NetworkType::Generic, MaxFaultThreshold, SocketMode::DefaultPreferredNetworkMode,
Thread::MutexBasicLockable{}};
Expand All @@ -102,6 +116,18 @@ envoy_netconf_t ConnectivityManagerImpl::setPreferredNetwork(NetworkType network
return network_state_.configuration_key_;
}

envoy_netconf_t ConnectivityManagerImpl::onNetworkMadeDefault(NetworkType network) {
ENVOY_LOG_MISC(trace, "Default network changed to {}", static_cast<int>(network));
envoy_netconf_t configuration_key = setPreferredNetwork(network);
#ifdef ENVOY_ENABLE_QUIC
for (std::reference_wrapper<Quic::EnvoyMobileQuicNetworkObserverRegistry> registry :
quic_observer_registry_factory_->getCreatedObserverRegistries()) {
registry.get().onNetworkMadeDefault();
}
#endif
return configuration_key;
}

void ConnectivityManagerImpl::setProxySettings(ProxySettingsConstSharedPtr new_proxy_settings) {
if (proxy_settings_ == nullptr && new_proxy_settings != nullptr) {
ENVOY_LOG_EVENT(info, "netconf_proxy_change", "{}", new_proxy_settings->asString());
Expand Down Expand Up @@ -305,16 +331,17 @@ Socket::OptionsSharedPtr ConnectivityManagerImpl::getUpstreamSocketOptions(Netwo
network != NetworkType::Generic) {
return getAlternateInterfaceSocketOptions(network);
}

// Envoy uses the hash signature of overridden socket options to choose a connection pool.
// Setting a dummy socket option is a hack that allows us to select a different
// connection pool without materially changing the socket configuration.
ASSERT(static_cast<int>(network) >= 0 && static_cast<int>(network) < 3);
int ttl_value = DEFAULT_IP_TTL + static_cast<int>(network);
auto options = std::make_shared<Socket::Options>();
options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_IP_TTL,
ENVOY_SOCKET_IPV6_UNICAST_HOPS, ttl_value));
if (!quic_upstream_connection_handle_network_change_) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not doing this when the runtime guard is true?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the old way of not reusing the existing connections for new request. It actually changes how a request is hashed to a connection pool. Since we are going away connections, we don't need to rely on this. And in the new world, we should still be able to reuse the old connection pools, just not the existing connection in it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Good point. Nice!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I agree with this as a long term plan but without marking H2 and H1 connections as draining won't this possibly be a regression for non-H3 traffic?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point! I think this feature needs to be enabled when both H2 and H3 support network change.

Adding network connectivity observers to H2 is another big change. I would prefer not to do it in this PR. The runtime guard is default false, do you think we can land the H3 support first and then change H2 and flip the runtime guard?

I didn't see how H1 is handled in Chromium. Is network change an issue in H1 at all?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For H1 in Chrome, I think the connections are simply abruptly terminated when the IP address changes:

https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_pool.cc;l=257;drc=8e948282d37c0e119e3102236878d6f4d5052c16

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #36059 for tracking and explanation.

// Envoy uses the hash signature of overridden socket options to choose a connection pool.
// Setting a dummy socket option is a hack that allows us to select a different
// connection pool without materially changing the socket configuration.
int ttl_value = DEFAULT_IP_TTL + static_cast<int>(network);
options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_IP_TTL,
ENVOY_SOCKET_IPV6_UNICAST_HOPS, ttl_value));
}
return options;
}

Expand Down
20 changes: 18 additions & 2 deletions mobile/library/common/network/connectivity_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#include "library/common/network/proxy_settings.h"
#include "library/common/types/c_types.h"

#ifdef ENVOY_ENABLE_QUIC
#include "library/common/network/envoy_mobile_quic_network_observer_registry_factory.h"
#endif

/**
* envoy_netconf_t identifies a snapshot of network configuration state. It's returned from calls
* that may alter current state, and passed back as a parameter to this API to determine if calls
Expand Down Expand Up @@ -186,6 +190,13 @@ class ConnectivityManager
* @returns the default DNS cache set up in base configuration or nullptr.
*/
virtual Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dnsCache() PURE;

/**
* Called when OS changes the preferred network.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "OS" => "the OS"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @param network, the OS-preferred network.
* @returns configuration key of the latest snapshot of network configuration state.
*/
virtual envoy_netconf_t onNetworkMadeDefault(NetworkType network) PURE;
};

class ConnectivityManagerImpl : public ConnectivityManager,
Expand All @@ -201,8 +212,7 @@ class ConnectivityManagerImpl : public ConnectivityManager,
static envoy_netconf_t setPreferredNetwork(NetworkType network);

ConnectivityManagerImpl(Upstream::ClusterManager& cluster_manager,
DnsCacheManagerSharedPtr dns_cache_manager)
: cluster_manager_(cluster_manager), dns_cache_manager_(dns_cache_manager) {}
DnsCacheManagerSharedPtr dns_cache_manager);

// Extensions::Common::DynamicForwardProxy::DnsCache::UpdateCallbacks
void onDnsHostAddOrUpdate(
Expand Down Expand Up @@ -232,6 +242,7 @@ class ConnectivityManagerImpl : public ConnectivityManager,
SocketMode socket_mode) override;
envoy_netconf_t addUpstreamSocketOptions(Socket::OptionsSharedPtr options) override;
Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dnsCache() override;
envoy_netconf_t onNetworkMadeDefault(NetworkType network) override;

private:
struct NetworkState {
Expand All @@ -252,9 +263,14 @@ class ConnectivityManagerImpl : public ConnectivityManager,
Extensions::Common::DynamicForwardProxy::DnsCache::AddUpdateCallbacksHandlePtr
dns_callbacks_handle_{nullptr};
Upstream::ClusterManager& cluster_manager_;
#ifdef ENVOY_ENABLE_QUIC
std::unique_ptr<Quic::EnvoyMobileQuicNetworkObserverRegistryFactory>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I looks like this is always created (when QUIC is compiled in). If so, consider making this a non-pointer member. That would avoid the need to explicitly construct it in the constructor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

quic_observer_registry_factory_;
#endif
DnsCacheManagerSharedPtr dns_cache_manager_;
ProxySettingsConstSharedPtr proxy_settings_;
static NetworkState network_state_;
const bool quic_upstream_connection_handle_network_change_;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: comment, please.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

};

using ConnectivityManagerSharedPtr = std::shared_ptr<ConnectivityManager>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "library/common/network/envoy_mobile_quic_network_observer_registry_factory.h"

#include "source/common/runtime/runtime_features.h"

namespace Envoy {
namespace Quic {

void EnvoyMobileQuicNetworkObserverRegistry::onNetworkMadeDefault() {
ENVOY_LOG_MISC(trace, "Default network changed.");
ASSERT(Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.quic_upstream_connection_handle_network_change"));
dispatcher_.post([this]() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why is this posted to the dispatcher instead of running on the current thread? Maybe add a comment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called on from Android API, so not necessarily on the network thread.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clue me in on where it's called unsafely? It looks like it's called from the connection manager's onnetworkmadedefault which is called from InternalEngine::onDefaultNetworkChanged which already switches to the dispatcher context.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I'm going to pause here because of quic-specific logic and wait for a discussion of general non-quic plans

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't notice that InternalEngine already post()'ed the callback. E-M only has one dispatcher, so probably we can omit post()'ing here. But theoretically the observer registry is one per worker thread (owned by ThreadLocalClusterManagerImpl), and its onNetworkMadeDefault() is called on the main thread even though InternalEngine already switches to the dispatcher context via post(). On the other hand, E-M only has one network thread and dispatcher. I'm wondering if it's clearer to explicitly do post() here to fit the threading model in Envoy core or skip doing post() given this is E-M code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the post() here and add assert on isThreadSafe(). instead

// Retain the existing observers in a list and iterate on the list.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to do this? Does the list get potentially mutated?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the conn pool may create new connections as a back fill if the connections on this list gets closed.

std::list<QuicNetworkConnectivityObserver*> existing_observers;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: a vector with reserve() tends to be more efficient than a list as it avoid allocations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

for (QuicNetworkConnectivityObserver* observer : registeredQuicObservers()) {
existing_observers.push_back(observer);
}
for (auto* observer : existing_observers) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: explicit type here (I think QuicNetworkConnectivityObserver, right?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

observer->onNetworkChanged();
}
});
}

EnvoyQuicNetworkObserverRegistryPtr
EnvoyMobileQuicNetworkObserverRegistryFactory::createQuicNetworkObserverRegistry(
Event::Dispatcher& dispatcher) {
auto result = std::make_unique<EnvoyMobileQuicNetworkObserverRegistry>(dispatcher);
thread_local_observer_registries_.emplace_back(*result);
return result;
}

} // namespace Quic
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "source/common/quic/envoy_quic_network_observer_registry_factory.h"
#include "source/common/quic/quic_network_connectivity_observer.h"

namespace Envoy {
namespace Quic {

// A mobile implementation that also handles network change events.
class EnvoyMobileQuicNetworkObserverRegistry : public EnvoyQuicNetworkObserverRegistry {
public:
explicit EnvoyMobileQuicNetworkObserverRegistry(Event::Dispatcher& dispatcher)
: dispatcher_(dispatcher) {}

void onNetworkMadeDefault();
Comment thread
danzh2010 marked this conversation as resolved.
Outdated

private:
Event::Dispatcher& dispatcher_;
};

class EnvoyMobileQuicNetworkObserverRegistryFactory
: public EnvoyQuicNetworkObserverRegistryFactory {
public:
EnvoyQuicNetworkObserverRegistryPtr
createQuicNetworkObserverRegistry(Event::Dispatcher& dispatcher) override;

std::list<std::reference_wrapper<EnvoyMobileQuicNetworkObserverRegistry>>&
getCreatedObserverRegistries() {
return thread_local_observer_registries_;
}

private:
std::list<std::reference_wrapper<EnvoyMobileQuicNetworkObserverRegistry>>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto about using a vector instead of a list.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

thread_local_observer_registries_;
};

using EnvoyMobileQuicNetworkObserverRegistryPtr =
std::unique_ptr<EnvoyMobileQuicNetworkObserverRegistry>;

} // namespace Quic
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MockConnectivityManager : public Network::ConnectivityManager {
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&,
Network::DnsResolver::ResolutionStatus));
MOCK_METHOD(Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr, dnsCache, ());
MOCK_METHOD(envoy_netconf_t, onNetworkMadeDefault, (NetworkType network));
};

class NetworkConfigurationFilterTest : public testing::Test {
Expand Down
8 changes: 6 additions & 2 deletions mobile/test/common/integration/client_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1337,12 +1337,16 @@ TEST_P(ClientIntegrationTest, TestProxyResolutionApi) {
// This test is simply to test the IPv6 connectivity check and DNS refresh and make sure the code
// doesn't crash. It doesn't really test the actual network change event.
TEST_P(ClientIntegrationTest, OnNetworkChanged) {
builder_.addRuntimeGuard("dns_cache_set_ip_version_to_remove", true);
builder_.addRuntimeGuard("quic_upstream_connection_handle_network_change", true);
initialize();
internalEngine()->setPreferredNetwork(NetworkType::WLAN);
basicTest();
internalEngine()->setPreferredNetwork(NetworkType::WLAN);
if (upstreamProtocol() == Http::CodecType::HTTP1) {
ASSERT_EQ(cc_.on_complete_received_byte_count_, 67);
} else if (upstreamProtocol() == Http::CodecType::HTTP3) {
ASSERT_TRUE(waitForCounterGe("http3.upstream.tx.quic_connection_close_error_code_QUIC_"
"CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS",
1));
}
}

Expand Down
21 changes: 21 additions & 0 deletions mobile/test/common/network/connectivity_manager_test.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <net/if.h>

#include "test/extensions/common/dynamic_forward_proxy/mocks.h"
#include "test/mocks/event/mocks.h"
#include "test/mocks/upstream/cluster_manager.h"

#include "gtest/gtest.h"
Expand Down Expand Up @@ -48,6 +49,26 @@ TEST_F(ConnectivityManagerTest,
EXPECT_EQ(original_key, connectivity_manager_->getConfigurationKey());
}

#ifdef ENVOY_ENABLE_QUIC
TEST_F(ConnectivityManagerTest, OnNetworkMadeDefault) {
Runtime::maybeSetRuntimeGuard(
"envoy.reloadable_features.quic_upstream_connection_handle_network_change", true);
Quic::EnvoyMobileQuicNetworkObserverRegistryPtr registry;
Event::MockDispatcher dispatcher;
EXPECT_CALL(cm_, createNetworkObserverRegistries(_))
.WillOnce(Invoke([&](Quic::EnvoyQuicNetworkObserverRegistryFactory& factory) {
registry.reset(static_cast<Quic::EnvoyMobileQuicNetworkObserverRegistry*>(
factory.createQuicNetworkObserverRegistry(dispatcher).release()));
}));
connectivity_manager_ = std::make_shared<ConnectivityManagerImpl>(cm_, dns_cache_manager_);
EXPECT_NE(nullptr, registry);
envoy_netconf_t original_key = connectivity_manager_->getConfigurationKey();
EXPECT_CALL(dispatcher, post(_));
envoy_netconf_t new_key = connectivity_manager_->onNetworkMadeDefault(NetworkType::WWAN);
EXPECT_NE(original_key, new_key);
}
#endif

TEST_F(ConnectivityManagerTest, RefreshDnsForCurrentConfigurationTriggersDnsRefresh) {
EXPECT_CALL(*dns_cache_, forceRefreshHosts());
envoy_netconf_t configuration_key = connectivity_manager_->getConfigurationKey();
Expand Down
Loading