Skip to content

Commit

Permalink
[mobile]Convert network type from enum to bitmap so that compound net…
Browse files Browse the repository at this point in the history
…work type can be represented (#37526)

Commit Message: Convert network type from enum to bitmap so that
compound network type can be represented
Additional Description: One example is a network can be both VPN and
WLAN.
Risk Level: low
Testing: existing tests
Docs Changes: n/a
Release Notes: n/a
Platform Specific Features: mobile only

---------

Signed-off-by: Renjie Tang <[email protected]>
  • Loading branch information
RenjieTang authored Dec 9, 2024
1 parent b71e049 commit a73835b
Show file tree
Hide file tree
Showing 20 changed files with 86 additions and 82 deletions.
5 changes: 1 addition & 4 deletions mobile/library/cc/engine.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "engine.h"

#include "library/common/engine_types.h"
#include "library/common/internal_engine.h"
#include "library/common/types/c_types.h"

Expand All @@ -27,9 +26,7 @@ std::string Engine::dumpStats() { return engine_->dumpStats(); }

envoy_status_t Engine::terminate() { return engine_->terminate(); }

void Engine::onDefaultNetworkChanged(NetworkType network) {
engine_->onDefaultNetworkChanged(network);
}
void Engine::onDefaultNetworkChanged(int network) { engine_->onDefaultNetworkChanged(network); }

void Engine::onDefaultNetworkUnavailable() { engine_->onDefaultNetworkUnavailable(); }

Expand Down
3 changes: 1 addition & 2 deletions mobile/library/cc/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <functional>

#include "library/cc/stream_client.h"
#include "library/common/engine_types.h"
#include "library/common/types/c_types.h"

namespace Envoy {
Expand All @@ -21,7 +20,7 @@ class Engine : public std::enable_shared_from_this<Engine> {

std::string dumpStats();
StreamClientSharedPtr streamClient();
void onDefaultNetworkChanged(NetworkType network);
void onDefaultNetworkChanged(int network);
void onDefaultNetworkUnavailable();
void onDefaultNetworkAvailable();

Expand Down
8 changes: 4 additions & 4 deletions mobile/library/common/engine_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ struct EnvoyStreamCallbacks {

/** Networks classified by the physical link. */
enum class NetworkType : int {
// This is the default and includes cases where network characteristics are unknown.
Generic = 0,
// This includes VPN or cases where network characteristics are unknown.
Generic = 1, // 001
// This includes WiFi and other local area wireless networks.
WLAN = 1,
WLAN = 2, // 010
// This includes all mobile phone networks.
WWAN = 2,
WWAN = 4, // 100
};

} // namespace Envoy
2 changes: 1 addition & 1 deletion mobile/library/common/internal_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ void InternalEngine::onDefaultNetworkAvailable() {
ENVOY_LOG_MISC(trace, "Calling the default network available callback");
}

void InternalEngine::onDefaultNetworkChanged(NetworkType network) {
void InternalEngine::onDefaultNetworkChanged(int network) {
ENVOY_LOG_MISC(trace, "Calling the default network changed callback");
dispatcher_->post([&, network]() -> void {
envoy_netconf_t configuration = Network::ConnectivityManagerImpl::setPreferredNetwork(network);
Expand Down
2 changes: 1 addition & 1 deletion mobile/library/common/internal_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class InternalEngine : public Logger::Loggable<Logger::Id::main> {
* - Force refresh the hosts in the DNS cache (will take `setIpVersionToRemove` into account).
* - Optionally (if configured) clear HTTP/3 broken status.
*/
void onDefaultNetworkChanged(NetworkType network);
void onDefaultNetworkChanged(int network);

/**
* This functions does the following when the default network is unavailable.
Expand Down
23 changes: 10 additions & 13 deletions mobile/library/common/network/connectivity_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ constexpr unsigned int InitialFaultThreshold = 1;
constexpr unsigned int MaxFaultThreshold = 3;

ConnectivityManagerImpl::NetworkState ConnectivityManagerImpl::network_state_{
1, NetworkType::Generic, MaxFaultThreshold, SocketMode::DefaultPreferredNetworkMode,
Thread::MutexBasicLockable{}};
1, 0, MaxFaultThreshold, SocketMode::DefaultPreferredNetworkMode, Thread::MutexBasicLockable{}};

envoy_netconf_t ConnectivityManagerImpl::setPreferredNetwork(NetworkType network) {
envoy_netconf_t ConnectivityManagerImpl::setPreferredNetwork(int network) {
Thread::LockGuard lock{network_state_.mutex_};

// TODO(goaway): Re-enable this guard. There's some concern that this will miss network updates
Expand Down Expand Up @@ -118,7 +117,7 @@ void ConnectivityManagerImpl::setProxySettings(ProxySettingsConstSharedPtr new_p

ProxySettingsConstSharedPtr ConnectivityManagerImpl::getProxySettings() { return proxy_settings_; }

NetworkType ConnectivityManagerImpl::getPreferredNetwork() {
int ConnectivityManagerImpl::getPreferredNetwork() {
Thread::LockGuard lock{network_state_.mutex_};
return network_state_.network_;
}
Expand Down Expand Up @@ -299,17 +298,16 @@ std::vector<InterfacePair> ConnectivityManagerImpl::enumerateV6Interfaces() {
return enumerateInterfaces(AF_INET6, 0, 0);
}

Socket::OptionsSharedPtr ConnectivityManagerImpl::getUpstreamSocketOptions(NetworkType network,
Socket::OptionsSharedPtr ConnectivityManagerImpl::getUpstreamSocketOptions(int network,
SocketMode socket_mode) {
if (enable_interface_binding_ && socket_mode == SocketMode::AlternateBoundInterfaceMode &&
network != NetworkType::Generic) {
network != 0) {
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>(
Expand All @@ -318,8 +316,7 @@ Socket::OptionsSharedPtr ConnectivityManagerImpl::getUpstreamSocketOptions(Netwo
return options;
}

Socket::OptionsSharedPtr
ConnectivityManagerImpl::getAlternateInterfaceSocketOptions(NetworkType network) {
Socket::OptionsSharedPtr ConnectivityManagerImpl::getAlternateInterfaceSocketOptions(int network) {
auto v4_pair = getActiveAlternateInterface(network, AF_INET);
auto v6_pair = getActiveAlternateInterface(network, AF_INET6);
ENVOY_LOG(debug, "found active alternate interface (ipv4): {} {}", std::get<0>(v4_pair),
Expand Down Expand Up @@ -357,7 +354,7 @@ ConnectivityManagerImpl::getAlternateInterfaceSocketOptions(NetworkType network)
envoy_netconf_t
ConnectivityManagerImpl::addUpstreamSocketOptions(Socket::OptionsSharedPtr options) {
envoy_netconf_t configuration_key;
NetworkType network;
int network;
SocketMode socket_mode;

{
Expand All @@ -372,10 +369,10 @@ ConnectivityManagerImpl::addUpstreamSocketOptions(Socket::OptionsSharedPtr optio
return configuration_key;
}

InterfacePair ConnectivityManagerImpl::getActiveAlternateInterface(NetworkType network,
InterfacePair ConnectivityManagerImpl::getActiveAlternateInterface(int network,
unsigned short family) {
// Attempt to derive an active interface that differs from the passed network parameter.
if (network == NetworkType::WWAN) {
if (network & static_cast<int>(NetworkType::WWAN)) {
// Network is cellular, so look for a WiFi interface.
// WiFi should always support multicast, and will not be point-to-point.
auto interfaces =
Expand All @@ -389,7 +386,7 @@ InterfacePair ConnectivityManagerImpl::getActiveAlternateInterface(NetworkType n
return interface;
}
}
} else if (network == NetworkType::WLAN) {
} else if (network & static_cast<int>(NetworkType::WLAN)) {
// Network is WiFi, so look for a cellular interface.
// Cellular networks should be point-to-point.
auto interfaces = enumerateInterfaces(family, IFF_UP | IFF_POINTOPOINT, IFF_LOOPBACK);
Expand Down
17 changes: 8 additions & 9 deletions mobile/library/common/network/connectivity_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class ConnectivityManager
/**
* @returns the current OS default/preferred network class.
*/
virtual NetworkType getPreferredNetwork() PURE;
virtual int getPreferredNetwork() PURE;

/**
* @returns the current mode used to determine upstream socket options.
Expand Down Expand Up @@ -169,7 +169,7 @@ class ConnectivityManager
/**
* @returns the current socket options that should be used for connections.
*/
virtual Socket::OptionsSharedPtr getUpstreamSocketOptions(NetworkType network,
virtual Socket::OptionsSharedPtr getUpstreamSocketOptions(int network,
SocketMode socket_mode) PURE;

/**
Expand Down Expand Up @@ -203,7 +203,7 @@ class ConnectivityManagerImpl : public ConnectivityManager,
* @param network, the OS-preferred network.
* @returns configuration key to associate with any related calls.
*/
static envoy_netconf_t setPreferredNetwork(NetworkType network);
static envoy_netconf_t setPreferredNetwork(int network);

ConnectivityManagerImpl(Upstream::ClusterManager& cluster_manager,
DnsCacheManagerSharedPtr dns_cache_manager)
Expand All @@ -225,7 +225,7 @@ class ConnectivityManagerImpl : public ConnectivityManager,
std::vector<InterfacePair> enumerateV6Interfaces() override;
std::vector<InterfacePair> enumerateInterfaces(unsigned short family, unsigned int select_flags,
unsigned int reject_flags) override;
NetworkType getPreferredNetwork() override;
int getPreferredNetwork() override;
SocketMode getSocketMode() override;
envoy_netconf_t getConfigurationKey() override;
Envoy::Network::ProxySettingsConstSharedPtr getProxySettings() override;
Expand All @@ -235,8 +235,7 @@ class ConnectivityManagerImpl : public ConnectivityManager,
void setInterfaceBindingEnabled(bool enabled) override;
void refreshDns(envoy_netconf_t configuration_key, bool drain_connections) override;
void resetConnectivityState() override;
Socket::OptionsSharedPtr getUpstreamSocketOptions(NetworkType network,
SocketMode socket_mode) override;
Socket::OptionsSharedPtr getUpstreamSocketOptions(int network, SocketMode socket_mode) override;
envoy_netconf_t addUpstreamSocketOptions(Socket::OptionsSharedPtr options) override;
Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dnsCache() override;
Upstream::ClusterManager& clusterManager() override { return cluster_manager_; }
Expand All @@ -246,13 +245,13 @@ class ConnectivityManagerImpl : public ConnectivityManager,
// The configuration key is passed through calls dispatched on the run loop to determine if
// they're still valid/relevant at time of execution.
envoy_netconf_t configuration_key_ ABSL_GUARDED_BY(mutex_);
NetworkType network_ ABSL_GUARDED_BY(mutex_);
int network_ ABSL_GUARDED_BY(mutex_);
uint8_t remaining_faults_ ABSL_GUARDED_BY(mutex_);
SocketMode socket_mode_ ABSL_GUARDED_BY(mutex_);
Thread::MutexBasicLockable mutex_;
};
Socket::OptionsSharedPtr getAlternateInterfaceSocketOptions(NetworkType network);
InterfacePair getActiveAlternateInterface(NetworkType network, unsigned short family);
Socket::OptionsSharedPtr getAlternateInterfaceSocketOptions(int network);
InterfacePair getActiveAlternateInterface(int network, unsigned short family);

bool enable_drain_post_dns_refresh_{false};
bool enable_interface_binding_{false};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io.envoyproxy.envoymobile.engine.types.EnvoyEventTracker;
import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks;
import io.envoyproxy.envoymobile.engine.types.EnvoyLogger;
import io.envoyproxy.envoymobile.engine.types.EnvoyNetworkType;
import io.envoyproxy.envoymobile.engine.types.EnvoyOnEngineRunning;
import io.envoyproxy.envoymobile.engine.types.EnvoyStringAccessor;
import io.envoyproxy.envoymobile.engine.types.EnvoyStatus;
Expand Down Expand Up @@ -86,7 +85,7 @@ public void onDefaultNetworkAvailable() {
}

@Override
public void onDefaultNetworkChanged(EnvoyNetworkType network) {
public void onDefaultNetworkChanged(int network) {
envoyEngine.onDefaultNetworkChanged(network);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,20 @@ private static List<Integer> getTransportTypes(NetworkCapabilities networkCapabi

private void onDefaultNetworkChanged(NetworkCapabilities networkCapabilities) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
int networkType = 0;
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
envoyEngine.onDefaultNetworkChanged(EnvoyNetworkType.WLAN);
networkType |= EnvoyNetworkType.WLAN.getValue();
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
envoyEngine.onDefaultNetworkChanged(EnvoyNetworkType.WWAN);
networkType |= EnvoyNetworkType.WWAN.getValue();
} else {
envoyEngine.onDefaultNetworkChanged(EnvoyNetworkType.GENERIC);
networkType |= EnvoyNetworkType.GENERIC.getValue();
}
// A network can be both VPN and another type, so we need to check for VPN separately.
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
networkType |= EnvoyNetworkType.GENERIC.getValue();
}
envoyEngine.onDefaultNetworkChanged(networkType);
}
previousTransportTypes = getTransportTypes(networkCapabilities);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.envoyproxy.envoymobile.engine;

import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks;
import io.envoyproxy.envoymobile.engine.types.EnvoyNetworkType;
import io.envoyproxy.envoymobile.engine.types.EnvoyStringAccessor;
import io.envoyproxy.envoymobile.engine.types.EnvoyStatus;

Expand Down Expand Up @@ -70,7 +69,7 @@ public interface EnvoyEngine {
/**
* A callback into the Envoy Engine when the default network type was changed.
*/
void onDefaultNetworkChanged(EnvoyNetworkType network);
void onDefaultNetworkChanged(int network);

/**
* A callback into the Envoy Engine when the default network is unavailable.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterFactory;
import io.envoyproxy.envoymobile.engine.types.EnvoyKeyValueStore;
import io.envoyproxy.envoymobile.engine.types.EnvoyLogger;
import io.envoyproxy.envoymobile.engine.types.EnvoyNetworkType;
import io.envoyproxy.envoymobile.engine.types.EnvoyOnEngineRunning;
import io.envoyproxy.envoymobile.engine.types.EnvoyStringAccessor;
import io.envoyproxy.envoymobile.engine.types.EnvoyStatus;
Expand Down Expand Up @@ -141,9 +140,9 @@ public void onDefaultNetworkAvailable() {
}

@Override
public void onDefaultNetworkChanged(EnvoyNetworkType network) {
public void onDefaultNetworkChanged(int network) {
checkIsTerminated();
JniLibrary.onDefaultNetworkChanged(engineHandle, network.getValue());
JniLibrary.onDefaultNetworkChanged(engineHandle, network);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

// Network interface type
public enum EnvoyNetworkType {
GENERIC(0),
WLAN(1),
WWAN(2),
GENERIC(1),
WLAN(2),
WWAN(4),
;

private final int value;
Expand Down
3 changes: 1 addition & 2 deletions mobile/library/jni/jni_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1375,8 +1375,7 @@ extern "C" JNIEXPORT void JNICALL
Java_io_envoyproxy_envoymobile_engine_JniLibrary_onDefaultNetworkChanged(JNIEnv*, jclass,
jlong engine,
jint network_type) {
reinterpret_cast<Envoy::InternalEngine*>(engine)->onDefaultNetworkChanged(
static_cast<Envoy::NetworkType>(network_type));
reinterpret_cast<Envoy::InternalEngine*>(engine)->onDefaultNetworkChanged(network_type);
}

extern "C" JNIEXPORT void JNICALL
Expand Down
23 changes: 17 additions & 6 deletions mobile/library/objective-c/EnvoyNetworkMonitor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ - (void)startPathMonitor {
dispatch_queue_create("io.envoyproxy.envoymobile.EnvoyNetworkMonitor", attrs);
nw_path_monitor_set_queue(_path_monitor, queue);

__block Envoy::NetworkType previousNetworkType = (Envoy::NetworkType)-1;
__block int previousNetworkType = 0;
Envoy::InternalEngine *engine = _engine;
nw_path_monitor_set_update_handler(_path_monitor, ^(nw_path_t _Nonnull path) {
BOOL isSatisfied = nw_path_get_status(path) == nw_path_status_satisfied;
Expand All @@ -58,10 +58,19 @@ - (void)startPathMonitor {
}

BOOL isCellular = nw_path_uses_interface_type(path, nw_interface_type_cellular);
Envoy::NetworkType network = Envoy::NetworkType::WWAN;
int network = 0;
if (!isCellular) {
BOOL isWifi = nw_path_uses_interface_type(path, nw_interface_type_wifi);
network = isWifi ? Envoy::NetworkType::WLAN : Envoy::NetworkType::Generic;
if (nw_path_uses_interface_type(path, nw_interface_type_wifi)) {
network |= static_cast<int>(Envoy::NetworkType::WLAN);
} else {
network |= static_cast<int>(Envoy::NetworkType::Generic);
}
} else {
network |= static_cast<int>(Envoy::NetworkType::WWAN);
}
// Check for VPN
if (nw_path_uses_interface_type(path, nw_interface_type_other)) {
network |= static_cast<int>(Envoy::NetworkType::Generic);
}

if (network != previousNetworkType) {
Expand Down Expand Up @@ -98,6 +107,7 @@ - (void)startPathMonitor {
nw_path_monitor_start(_path_monitor);
}

// TODO(renjietang): API is deprecated, remove.
- (void)startReachability {
NSString *name = @"io.envoyproxy.envoymobile.EnvoyNetworkMonitor";
SCNetworkReachabilityRef reachability =
Expand Down Expand Up @@ -135,8 +145,9 @@ static void _reachability_callback(SCNetworkReachabilityRef target,

NSLog(@"[Envoy] setting preferred network to %@", isUsingWWAN ? @"WWAN" : @"WLAN");
EnvoyNetworkMonitor *monitor = (__bridge EnvoyNetworkMonitor *)info;
monitor->_engine->onDefaultNetworkChanged(isUsingWWAN ? Envoy::NetworkType::WWAN
: Envoy::NetworkType::WLAN);
monitor->_engine->onDefaultNetworkChanged(isUsingWWAN
? static_cast<int>(Envoy::NetworkType::WWAN)
: static_cast<int>(Envoy::NetworkType::WLAN));
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class MockConnectivityManager : public Network::ConnectivityManager {
MOCK_METHOD(std::vector<Network::InterfacePair>, enumerateV6Interfaces, ());
MOCK_METHOD(std::vector<Network::InterfacePair>, enumerateInterfaces,
(unsigned short family, unsigned int select_flags, unsigned int reject_flags));
MOCK_METHOD(NetworkType, getPreferredNetwork, ());
MOCK_METHOD(int, getPreferredNetwork, ());
MOCK_METHOD(Network::SocketMode, getSocketMode, ());
MOCK_METHOD(envoy_netconf_t, getConfigurationKey, ());
MOCK_METHOD(Envoy::Network::ProxySettingsConstSharedPtr, getProxySettings, ());
Expand All @@ -44,7 +44,7 @@ class MockConnectivityManager : public Network::ConnectivityManager {
MOCK_METHOD(void, refreshDns, (envoy_netconf_t configuration_key, bool drain_connections));
MOCK_METHOD(void, resetConnectivityState, ());
MOCK_METHOD(Network::Socket::OptionsSharedPtr, getUpstreamSocketOptions,
(NetworkType network, Network::SocketMode socket_mode));
(int network, Network::SocketMode socket_mode));
MOCK_METHOD(envoy_netconf_t, addUpstreamSocketOptions,
(Network::Socket::OptionsSharedPtr options));

Expand Down
2 changes: 1 addition & 1 deletion mobile/test/common/integration/client_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,7 @@ TEST_P(ClientIntegrationTest, TestProxyResolutionApi) {
TEST_P(ClientIntegrationTest, OnNetworkChanged) {
builder_.addRuntimeGuard("dns_cache_set_ip_version_to_remove", true);
initialize();
internalEngine()->onDefaultNetworkChanged(NetworkType::WLAN);
internalEngine()->onDefaultNetworkChanged(1);
basicTest();
if (upstreamProtocol() == Http::CodecType::HTTP1) {
ASSERT_EQ(cc_.on_complete_received_byte_count_, 67);
Expand Down
Loading

0 comments on commit a73835b

Please sign in to comment.