From 20ebed51bbd7b719fae8cf2c4b901aafaf11422a Mon Sep 17 00:00:00 2001 From: Sepalani Date: Thu, 1 Oct 2020 12:10:34 +0400 Subject: [PATCH] IP/Top: Add Android network interface --- .../Android/app/src/main/AndroidManifest.xml | 1 + .../dolphinemu/utils/NetworkHelper.java | 126 ++++++++++++++++++ .../jni/AndroidCommon/AndroidCommon.cpp | 21 +++ .../Android/jni/AndroidCommon/AndroidCommon.h | 3 + Source/Android/jni/AndroidCommon/IDCache.cpp | 35 +++++ Source/Android/jni/AndroidCommon/IDCache.h | 5 + Source/Core/Core/IOS/Network/IP/Top.cpp | 15 ++- 7 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index 56d6eadfbf..dab8ce63a3 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -19,6 +19,7 @@ + diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java new file mode 100644 index 0000000000..08e9c9731f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java @@ -0,0 +1,126 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.app.Service; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.RouteInfo; +import android.os.Build; + +import androidx.annotation.Keep; +import androidx.annotation.RequiresApi; + +import org.dolphinemu.dolphinemu.DolphinApplication; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +public class NetworkHelper +{ + private static ConnectivityManager GetConnectivityManager() + { + Context context = DolphinApplication.getAppContext(); + ConnectivityManager manager = + (ConnectivityManager) context.getSystemService(Service.CONNECTIVITY_SERVICE); + if (manager == null) + Log.warning("Cannot get Network link as ConnectivityManager is null."); + return manager; + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private static LinkAddress GetIPv4Link() + { + ConnectivityManager manager = GetConnectivityManager(); + if (manager == null) + return null; + Network active_network = manager.getActiveNetwork(); + if (active_network == null) + { + Log.warning("Active network is null."); + return null; + } + LinkProperties properties = manager.getLinkProperties(active_network); + if (properties == null) + { + Log.warning("Link properties is null."); + return null; + } + for (LinkAddress link : properties.getLinkAddresses()) + { + InetAddress address = link.getAddress(); + if (address instanceof Inet4Address) + return link; + } + Log.warning("No IPv4 link found."); + return null; + } + + private static int InetAddressToInt(InetAddress address) + { + byte[] net_addr = address.getAddress(); + int result = 0; + // Convert address to little endian + for (int i = 0; i < net_addr.length; i++) + { + result |= (net_addr[i] & 0xFF) << (8 * i); + } + return result; + } + + @Keep + public static int GetNetworkIpAddress() + { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) + return 0; + LinkAddress link = GetIPv4Link(); + if (link == null) + return 0; + return InetAddressToInt(link.getAddress()); + } + + @Keep + public static int GetNetworkPrefixLength() + { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) + return 0; + LinkAddress link = GetIPv4Link(); + if (link == null) + return 0; + return link.getPrefixLength(); + } + + @Keep + public static int GetNetworkGateway() + { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) + return 0; + ConnectivityManager manager = GetConnectivityManager(); + if (manager == null) + return 0; + Network active_network = manager.getActiveNetwork(); + if (active_network == null) + return 0; + LinkProperties properties = manager.getLinkProperties(active_network); + if (properties == null) + return 0; + try + { + InetAddress addr_out = InetAddress.getByName("8.8.8.8"); + for (RouteInfo route : properties.getRoutes()) + { + if (!route.matches(addr_out)) + continue; + return InetAddressToInt(route.getGateway()); + } + } + catch (UnknownHostException ignore) + { + } + Log.warning("No valid gateway found."); + return 0; + } +} diff --git a/Source/Android/jni/AndroidCommon/AndroidCommon.cpp b/Source/Android/jni/AndroidCommon/AndroidCommon.cpp index 73405b6d8e..887ae4deab 100644 --- a/Source/Android/jni/AndroidCommon/AndroidCommon.cpp +++ b/Source/Android/jni/AndroidCommon/AndroidCommon.cpp @@ -65,3 +65,24 @@ bool DeleteAndroidContent(const std::string& uri) return env->CallStaticBooleanMethod(IDCache::GetContentHandlerClass(), IDCache::GetContentHandlerDelete(), ToJString(env, uri)); } + +int GetNetworkIpAddress() +{ + JNIEnv* env = IDCache::GetEnvForThread(); + return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(), + IDCache::GetNetworkHelperGetNetworkIpAddress()); +} + +int GetNetworkPrefixLength() +{ + JNIEnv* env = IDCache::GetEnvForThread(); + return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(), + IDCache::GetNetworkHelperGetNetworkPrefixLength()); +} + +int GetNetworkGateway() +{ + JNIEnv* env = IDCache::GetEnvForThread(); + return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(), + IDCache::GetNetworkHelperGetNetworkGateway()); +} diff --git a/Source/Android/jni/AndroidCommon/AndroidCommon.h b/Source/Android/jni/AndroidCommon/AndroidCommon.h index ca8245182d..2ab220eac7 100644 --- a/Source/Android/jni/AndroidCommon/AndroidCommon.h +++ b/Source/Android/jni/AndroidCommon/AndroidCommon.h @@ -14,3 +14,6 @@ std::vector JStringArrayToVector(JNIEnv* env, jobjectArray array); int OpenAndroidContent(const std::string& uri, const std::string& mode); bool DeleteAndroidContent(const std::string& uri); +int GetNetworkIpAddress(); +int GetNetworkPrefixLength(); +int GetNetworkGateway(); diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp index fcfd4ed177..674233d79f 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.cpp +++ b/Source/Android/jni/AndroidCommon/IDCache.cpp @@ -45,6 +45,11 @@ static jclass s_content_handler_class; static jmethodID s_content_handler_open_fd; static jmethodID s_content_handler_delete; +static jclass s_network_helper_class; +static jmethodID s_network_helper_get_network_ip_address; +static jmethodID s_network_helper_get_network_prefix_length; +static jmethodID s_network_helper_get_network_gateway; + namespace IDCache { JNIEnv* GetEnvForThread() @@ -205,6 +210,25 @@ jmethodID GetContentHandlerDelete() return s_content_handler_delete; } +jclass GetNetworkHelperClass() +{ + return s_network_helper_class; +} + +jmethodID GetNetworkHelperGetNetworkIpAddress() +{ + return s_network_helper_get_network_ip_address; +} + +jmethodID GetNetworkHelperGetNetworkPrefixLength() +{ + return s_network_helper_get_network_prefix_length; +} + +jmethodID GetNetworkHelperGetNetworkGateway() +{ + return s_network_helper_get_network_gateway; +} } // namespace IDCache #ifdef __cplusplus @@ -283,6 +307,16 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) s_content_handler_delete = env->GetStaticMethodID(s_content_handler_class, "delete", "(Ljava/lang/String;)Z"); + const jclass network_helper_class = + env->FindClass("org/dolphinemu/dolphinemu/utils/NetworkHelper"); + s_network_helper_class = reinterpret_cast(env->NewGlobalRef(network_helper_class)); + s_network_helper_get_network_ip_address = + env->GetStaticMethodID(s_network_helper_class, "GetNetworkIpAddress", "()I"); + s_network_helper_get_network_prefix_length = + env->GetStaticMethodID(s_network_helper_class, "GetNetworkPrefixLength", "()I"); + s_network_helper_get_network_gateway = + env->GetStaticMethodID(s_network_helper_class, "GetNetworkGateway", "()I"); + return JNI_VERSION; } @@ -301,6 +335,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) env->DeleteGlobalRef(s_ini_file_section_class); env->DeleteGlobalRef(s_compress_cb_class); env->DeleteGlobalRef(s_content_handler_class); + env->DeleteGlobalRef(s_network_helper_class); } #ifdef __cplusplus diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h index cd45b5d03f..c89e0c9fcc 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.h +++ b/Source/Android/jni/AndroidCommon/IDCache.h @@ -45,4 +45,9 @@ jclass GetContentHandlerClass(); jmethodID GetContentHandlerOpenFd(); jmethodID GetContentHandlerDelete(); +jclass GetNetworkHelperClass(); +jmethodID GetNetworkHelperGetNetworkIpAddress(); +jmethodID GetNetworkHelperGetNetworkPrefixLength(); +jmethodID GetNetworkHelperGetNetworkGateway(); + } // namespace IDCache diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp index 24262d7b9b..68fadeadf5 100644 --- a/Source/Core/Core/IOS/Network/IP/Top.cpp +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -50,6 +50,10 @@ #include #endif +#ifdef __ANDROID__ +#include "jni/AndroidCommon/AndroidCommon.h" +#endif + namespace IOS::HLE::Device { enum SOResultCode : s32 @@ -217,7 +221,14 @@ static std::optional GetSystemDefaultInterface() return DefaultInterface{entry.dwAddr, entry.dwMask, entry.dwBCastAddr}; } } -#elif !defined(__ANDROID__) +#elif defined(__ANDROID__) + const u32 addr = GetNetworkIpAddress(); + const u32 prefix_length = GetNetworkPrefixLength(); + const u32 netmask = (1 << prefix_length) - 1; + const u32 gateway = GetNetworkGateway(); + if (addr || netmask || gateway) + return DefaultInterface{addr, netmask, gateway}; +#else // Assume that the address that is used to access the Internet corresponds // to the default interface. auto get_default_address = []() -> std::optional { @@ -261,7 +272,7 @@ static std::optional GetSystemDefaultInterface() } } #endif - return {}; + return std::nullopt; } static DefaultInterface GetSystemDefaultInterfaceOrFallback()