OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
11 * this list of conditions and the following disclaimer in the documentation | 11 * this list of conditions and the following disclaimer in the documentation |
12 * and/or other materials provided with the distribution. | 12 * and/or other materials provided with the distribution. |
13 * 3. The name of the author may not be used to endorse or promote products | 13 * 3. The name of the author may not be used to endorse or promote products |
14 * derived from this software without specific prior written permission. | 14 * derived from this software without specific prior written permission. |
15 * | 15 * |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 #include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h" | 28 #include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h" |
29 | 29 |
| 30 #include <dlfcn.h> |
| 31 |
| 32 #include "webrtc/base/bind.h" |
30 #include "webrtc/base/common.h" | 33 #include "webrtc/base/common.h" |
| 34 #include "webrtc/base/ipaddress.h" |
31 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | 35 #include "talk/app/webrtc/java/jni/classreferenceholder.h" |
32 #include "talk/app/webrtc/java/jni/jni_helpers.h" | 36 #include "talk/app/webrtc/java/jni/jni_helpers.h" |
33 | 37 |
34 namespace webrtc_jni { | 38 namespace webrtc_jni { |
| 39 |
35 jobject AndroidNetworkMonitor::application_context_ = nullptr; | 40 jobject AndroidNetworkMonitor::application_context_ = nullptr; |
36 | 41 |
| 42 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) { |
| 43 std::string enum_name = |
| 44 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType", |
| 45 j_network_type); |
| 46 if (enum_name == "CONNECTION_UNKNOWN") { |
| 47 return NetworkType::NETWORK_UNKNOWN; |
| 48 } |
| 49 if (enum_name == "CONNECTION_ETHERNET") { |
| 50 return NetworkType::NETWORK_ETHERNET; |
| 51 } |
| 52 if (enum_name == "CONNECTION_WIFI") { |
| 53 return NetworkType::NETWORK_WIFI; |
| 54 } |
| 55 if (enum_name == "CONNECTION_4G") { |
| 56 return NetworkType::NETWORK_4G; |
| 57 } |
| 58 if (enum_name == "CONNECTION_3G") { |
| 59 return NetworkType::NETWORK_3G; |
| 60 } |
| 61 if (enum_name == "CONNECTION_2G") { |
| 62 return NetworkType::NETWORK_2G; |
| 63 } |
| 64 if (enum_name == "CONNECTION_BLUETOOTH") { |
| 65 return NetworkType::NETWORK_BLUETOOTH; |
| 66 } |
| 67 if (enum_name == "CONNECTION_NONE") { |
| 68 return NetworkType::NETWORK_NONE; |
| 69 } |
| 70 ASSERT(false); |
| 71 return NetworkType::NETWORK_UNKNOWN; |
| 72 } |
| 73 |
| 74 static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) { |
| 75 jclass j_ip_address_class = GetObjectClass(jni, j_ip_address); |
| 76 jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B"); |
| 77 jbyteArray j_addresses = |
| 78 static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id)); |
| 79 size_t address_length = jni->GetArrayLength(j_addresses); |
| 80 jbyte* addr_array = jni->GetByteArrayElements(j_addresses, nullptr); |
| 81 CHECK_EXCEPTION(jni) << "Error during GetIPAddressFromJava"; |
| 82 if (address_length == 4) { |
| 83 // IP4 |
| 84 struct in_addr ip4_addr; |
| 85 memcpy(&ip4_addr.s_addr, addr_array, 4); |
| 86 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); |
| 87 return rtc::IPAddress(ip4_addr); |
| 88 } |
| 89 // IP6 |
| 90 RTC_CHECK(address_length == 16); |
| 91 struct in6_addr ip6_addr; |
| 92 memcpy(ip6_addr.s6_addr, addr_array, address_length); |
| 93 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); |
| 94 return rtc::IPAddress(ip6_addr); |
| 95 } |
| 96 |
| 97 static void GetIPAddressesFromJava(JNIEnv* jni, |
| 98 jobjectArray j_ip_addresses, |
| 99 std::vector<rtc::IPAddress>* ip_addresses) { |
| 100 ip_addresses->clear(); |
| 101 size_t num_addresses = jni->GetArrayLength(j_ip_addresses); |
| 102 CHECK_EXCEPTION(jni) << "Error during GetArrayLength"; |
| 103 for (size_t i = 0; i < num_addresses; ++i) { |
| 104 jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i); |
| 105 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement"; |
| 106 rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address); |
| 107 ip_addresses->push_back(ip); |
| 108 } |
| 109 } |
| 110 |
| 111 static NetworkInformation GetNetworkInformationFromJava( |
| 112 JNIEnv* jni, |
| 113 jobject j_network_info) { |
| 114 jclass j_network_info_class = GetObjectClass(jni, j_network_info); |
| 115 jfieldID j_interface_name_id = |
| 116 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;"); |
| 117 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "I"); |
| 118 jfieldID j_type_id = |
| 119 GetFieldID(jni, j_network_info_class, "type", |
| 120 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;"); |
| 121 jfieldID j_ip_addresses_id = |
| 122 GetFieldID(jni, j_network_info_class, "ipAddresses", |
| 123 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;"); |
| 124 |
| 125 NetworkInformation network_info; |
| 126 network_info.interface_name = JavaToStdString( |
| 127 jni, GetStringField(jni, j_network_info, j_interface_name_id)); |
| 128 network_info.handle = |
| 129 static_cast<NetworkHandle>(GetIntField(jni, j_network_info, j_handle_id)); |
| 130 network_info.type = GetNetworkTypeFromJava( |
| 131 jni, GetObjectField(jni, j_network_info, j_type_id)); |
| 132 jobjectArray j_ip_addresses = static_cast<jobjectArray>( |
| 133 GetObjectField(jni, j_network_info, j_ip_addresses_id)); |
| 134 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses); |
| 135 return network_info; |
| 136 } |
| 137 |
| 138 std::string NetworkInformation::ToString() const { |
| 139 std::stringstream ss; |
| 140 ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type " |
| 141 << type << "; address"; |
| 142 for (const rtc::IPAddress address : ip_addresses) { |
| 143 ss << " " << address.ToString(); |
| 144 } |
| 145 ss << "]"; |
| 146 return ss.str(); |
| 147 } |
| 148 |
37 // static | 149 // static |
38 void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) { | 150 void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) { |
39 if (application_context_) { | 151 if (application_context_) { |
40 jni->DeleteGlobalRef(application_context_); | 152 jni->DeleteGlobalRef(application_context_); |
41 } | 153 } |
42 application_context_ = NewGlobalRef(jni, context); | 154 application_context_ = NewGlobalRef(jni, context); |
43 } | 155 } |
44 | 156 |
45 AndroidNetworkMonitor::AndroidNetworkMonitor() | 157 AndroidNetworkMonitor::AndroidNetworkMonitor() |
46 : j_network_monitor_class_(jni(), | 158 : j_network_monitor_class_(jni(), |
47 FindClass(jni(), "org/webrtc/NetworkMonitor")), | 159 FindClass(jni(), "org/webrtc/NetworkMonitor")), |
48 j_network_monitor_( | 160 j_network_monitor_( |
49 jni(), | 161 jni(), |
50 jni()->CallStaticObjectMethod( | 162 jni()->CallStaticObjectMethod( |
51 *j_network_monitor_class_, | 163 *j_network_monitor_class_, |
52 GetStaticMethodID( | 164 GetStaticMethodID( |
53 jni(), | 165 jni(), |
54 *j_network_monitor_class_, | 166 *j_network_monitor_class_, |
55 "init", | 167 "init", |
56 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"), | 168 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"), |
57 application_context_)) { | 169 application_context_)) { |
58 ASSERT(application_context_ != nullptr); | 170 ASSERT(application_context_ != nullptr); |
59 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init"; | 171 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init"; |
60 } | 172 } |
61 | 173 |
62 void AndroidNetworkMonitor::Start() { | 174 void AndroidNetworkMonitor::Start() { |
63 RTC_CHECK(thread_checker_.CalledOnValidThread()); | 175 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| 176 if (started_) { |
| 177 return; |
| 178 } |
| 179 started_ = true; |
| 180 |
| 181 // This is kind of magic behavior, but doing this allows the SocketServer to |
| 182 // use this as a NetworkBinder to bind sockets on a particular network when |
| 183 // it creates sockets. |
| 184 worker_thread()->socketserver()->set_network_binder(this); |
| 185 |
64 jmethodID m = | 186 jmethodID m = |
65 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); | 187 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); |
66 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | 188 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
67 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; | 189 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; |
68 } | 190 } |
69 | 191 |
70 void AndroidNetworkMonitor::Stop() { | 192 void AndroidNetworkMonitor::Stop() { |
71 RTC_CHECK(thread_checker_.CalledOnValidThread()); | 193 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| 194 if (!started_) { |
| 195 return; |
| 196 } |
| 197 started_ = false; |
| 198 |
| 199 // Once the network monitor stops, it will clear all network information and |
| 200 // it won't find the network handle to bind anyway. |
| 201 if (worker_thread()->socketserver()->network_binder() == this) { |
| 202 worker_thread()->socketserver()->set_network_binder(nullptr); |
| 203 } |
| 204 |
72 jmethodID m = | 205 jmethodID m = |
73 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); | 206 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); |
74 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | 207 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
75 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; | 208 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; |
| 209 |
| 210 network_info_by_address_.clear(); |
| 211 } |
| 212 |
| 213 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, |
| 214 const rtc::IPAddress& address) { |
| 215 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
| 216 auto it = network_info_by_address_.find(address); |
| 217 if (it == network_info_by_address_.end()) { |
| 218 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; |
| 219 } |
| 220 // Android prior to Lollipop didn't have support for binding sockets to |
| 221 // networks. However, in that case it should not have reached here because |
| 222 // |network_info_by_address_| should only be populated in Android Lollipop |
| 223 // and above. |
| 224 NetworkInformation network = it->second; |
| 225 |
| 226 // NOTE: This does rely on Android implementation details, but |
| 227 // these details are unlikely to change. |
| 228 typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); |
| 229 static SetNetworkForSocket setNetworkForSocket; |
| 230 // This is not threadsafe, but we are running this only on the worker thread. |
| 231 if (setNetworkForSocket == nullptr) { |
| 232 // Android's netd client library should always be loaded in our address |
| 233 // space as it shims libc functions like connect(). |
| 234 const std::string net_library_path = "libnetd_client.so"; |
| 235 void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY); |
| 236 if (lib == nullptr) { |
| 237 LOG(LS_ERROR) << "Library " << net_library_path << " not found!"; |
| 238 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; |
| 239 } |
| 240 setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>( |
| 241 dlsym(lib, "setNetworkForSocket")); |
| 242 } |
| 243 if (setNetworkForSocket == nullptr) { |
| 244 LOG(LS_ERROR) << "Symbol setNetworkForSocket not found "; |
| 245 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; |
| 246 } |
| 247 int rv = setNetworkForSocket(network.handle, socket_fd); |
| 248 // If |network| has since disconnected, |rv| will be ENONET. Surface this as |
| 249 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back |
| 250 // the less descriptive ERR_FAILED. |
| 251 if (rv == 0) { |
| 252 return rtc::NETWORK_BIND_SUCCESS; |
| 253 } |
| 254 if (rv == ENONET) { |
| 255 return rtc::NETWORK_BIND_NETWORK_CHANGED; |
| 256 } |
| 257 return rtc::NETWORK_BIND_FAILURE; |
| 258 } |
| 259 |
| 260 void AndroidNetworkMonitor::OnNetworkAvailable( |
| 261 const NetworkInformation& network_info) { |
| 262 worker_thread()->Invoke<void>(rtc::Bind( |
| 263 &AndroidNetworkMonitor::OnNetworkAvailable_w, this, network_info)); |
| 264 } |
| 265 |
| 266 void AndroidNetworkMonitor::OnNetworkAvailable_w( |
| 267 const NetworkInformation& network_info) { |
| 268 LOG(LS_INFO) << "Network available: " << network_info.ToString(); |
| 269 for (rtc::IPAddress address : network_info.ip_addresses) { |
| 270 network_info_by_address_[address] = network_info; |
| 271 } |
| 272 } |
| 273 |
| 274 rtc::NetworkMonitorInterface* |
| 275 AndroidNetworkMonitorFactory::CreateNetworkMonitor() { |
| 276 return new AndroidNetworkMonitor(); |
76 } | 277 } |
77 | 278 |
78 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( | 279 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( |
79 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { | 280 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { |
80 rtc::NetworkMonitorInterface* network_monitor = | 281 rtc::NetworkMonitorInterface* network_monitor = |
81 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); | 282 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); |
82 network_monitor->OnNetworksChanged(); | 283 network_monitor->OnNetworksChanged(); |
83 } | 284 } |
84 | 285 |
| 286 JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)( |
| 287 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, |
| 288 jobject j_network_info) { |
| 289 AndroidNetworkMonitor* network_monitor = |
| 290 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); |
| 291 NetworkInformation network_info = |
| 292 GetNetworkInformationFromJava(jni, j_network_info); |
| 293 network_monitor->OnNetworkAvailable(network_info); |
| 294 } |
| 295 |
85 } // namespace webrtc_jni | 296 } // namespace webrtc_jni |
OLD | NEW |