OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2015 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
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 | |
14 * derived from this software without specific prior written permission. | |
15 * | |
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 | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
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, | |
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 | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h" | |
29 | |
30 #include <dlfcn.h> | |
31 | |
32 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | |
33 #include "talk/app/webrtc/java/jni/jni_helpers.h" | |
34 #include "webrtc/base/bind.h" | |
35 #include "webrtc/base/common.h" | |
36 #include "webrtc/base/ipaddress.h" | |
37 | |
38 namespace webrtc_jni { | |
39 | |
40 jobject AndroidNetworkMonitor::application_context_ = nullptr; | |
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::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) { | |
75 switch (network_type) { | |
76 case NETWORK_UNKNOWN: | |
77 RTC_DCHECK(false) << "Unknown network type"; | |
78 return rtc::ADAPTER_TYPE_UNKNOWN; | |
79 case NETWORK_ETHERNET: | |
80 return rtc::ADAPTER_TYPE_ETHERNET; | |
81 case NETWORK_WIFI: | |
82 return rtc::ADAPTER_TYPE_WIFI; | |
83 case NETWORK_4G: | |
84 case NETWORK_3G: | |
85 case NETWORK_2G: | |
86 return rtc::ADAPTER_TYPE_CELLULAR; | |
87 case NETWORK_BLUETOOTH: | |
88 // There is no corresponding mapping for bluetooth networks. | |
89 // Map it to VPN for now. | |
90 return rtc::ADAPTER_TYPE_VPN; | |
91 default: | |
92 RTC_DCHECK(false) << "Invalid network type " << network_type; | |
93 return rtc::ADAPTER_TYPE_UNKNOWN; | |
94 } | |
95 } | |
96 | |
97 static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) { | |
98 jclass j_ip_address_class = GetObjectClass(jni, j_ip_address); | |
99 jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B"); | |
100 jbyteArray j_addresses = | |
101 static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id)); | |
102 size_t address_length = jni->GetArrayLength(j_addresses); | |
103 jbyte* addr_array = jni->GetByteArrayElements(j_addresses, nullptr); | |
104 CHECK_EXCEPTION(jni) << "Error during GetIPAddressFromJava"; | |
105 if (address_length == 4) { | |
106 // IP4 | |
107 struct in_addr ip4_addr; | |
108 memcpy(&ip4_addr.s_addr, addr_array, 4); | |
109 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); | |
110 return rtc::IPAddress(ip4_addr); | |
111 } | |
112 // IP6 | |
113 RTC_CHECK(address_length == 16); | |
114 struct in6_addr ip6_addr; | |
115 memcpy(ip6_addr.s6_addr, addr_array, address_length); | |
116 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); | |
117 return rtc::IPAddress(ip6_addr); | |
118 } | |
119 | |
120 static void GetIPAddressesFromJava(JNIEnv* jni, | |
121 jobjectArray j_ip_addresses, | |
122 std::vector<rtc::IPAddress>* ip_addresses) { | |
123 ip_addresses->clear(); | |
124 size_t num_addresses = jni->GetArrayLength(j_ip_addresses); | |
125 CHECK_EXCEPTION(jni) << "Error during GetArrayLength"; | |
126 for (size_t i = 0; i < num_addresses; ++i) { | |
127 jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i); | |
128 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement"; | |
129 rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address); | |
130 ip_addresses->push_back(ip); | |
131 } | |
132 } | |
133 | |
134 static NetworkInformation GetNetworkInformationFromJava( | |
135 JNIEnv* jni, | |
136 jobject j_network_info) { | |
137 jclass j_network_info_class = GetObjectClass(jni, j_network_info); | |
138 jfieldID j_interface_name_id = | |
139 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;"); | |
140 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "I"); | |
141 jfieldID j_type_id = | |
142 GetFieldID(jni, j_network_info_class, "type", | |
143 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;"); | |
144 jfieldID j_ip_addresses_id = | |
145 GetFieldID(jni, j_network_info_class, "ipAddresses", | |
146 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;"); | |
147 | |
148 NetworkInformation network_info; | |
149 network_info.interface_name = JavaToStdString( | |
150 jni, GetStringField(jni, j_network_info, j_interface_name_id)); | |
151 network_info.handle = | |
152 static_cast<NetworkHandle>(GetIntField(jni, j_network_info, j_handle_id)); | |
153 network_info.type = GetNetworkTypeFromJava( | |
154 jni, GetObjectField(jni, j_network_info, j_type_id)); | |
155 jobjectArray j_ip_addresses = static_cast<jobjectArray>( | |
156 GetObjectField(jni, j_network_info, j_ip_addresses_id)); | |
157 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses); | |
158 return network_info; | |
159 } | |
160 | |
161 std::string NetworkInformation::ToString() const { | |
162 std::stringstream ss; | |
163 ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type " | |
164 << type << "; address"; | |
165 for (const rtc::IPAddress address : ip_addresses) { | |
166 ss << " " << address.ToString(); | |
167 } | |
168 ss << "]"; | |
169 return ss.str(); | |
170 } | |
171 | |
172 // static | |
173 void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) { | |
174 if (application_context_) { | |
175 jni->DeleteGlobalRef(application_context_); | |
176 } | |
177 application_context_ = NewGlobalRef(jni, context); | |
178 } | |
179 | |
180 AndroidNetworkMonitor::AndroidNetworkMonitor() | |
181 : j_network_monitor_class_(jni(), | |
182 FindClass(jni(), "org/webrtc/NetworkMonitor")), | |
183 j_network_monitor_( | |
184 jni(), | |
185 jni()->CallStaticObjectMethod( | |
186 *j_network_monitor_class_, | |
187 GetStaticMethodID( | |
188 jni(), | |
189 *j_network_monitor_class_, | |
190 "init", | |
191 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"), | |
192 application_context_)) { | |
193 ASSERT(application_context_ != nullptr); | |
194 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init"; | |
195 } | |
196 | |
197 void AndroidNetworkMonitor::Start() { | |
198 RTC_CHECK(thread_checker_.CalledOnValidThread()); | |
199 if (started_) { | |
200 return; | |
201 } | |
202 started_ = true; | |
203 | |
204 // This is kind of magic behavior, but doing this allows the SocketServer to | |
205 // use this as a NetworkBinder to bind sockets on a particular network when | |
206 // it creates sockets. | |
207 worker_thread()->socketserver()->set_network_binder(this); | |
208 | |
209 jmethodID m = | |
210 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); | |
211 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | |
212 CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; | |
213 } | |
214 | |
215 void AndroidNetworkMonitor::Stop() { | |
216 RTC_CHECK(thread_checker_.CalledOnValidThread()); | |
217 if (!started_) { | |
218 return; | |
219 } | |
220 started_ = false; | |
221 | |
222 // Once the network monitor stops, it will clear all network information and | |
223 // it won't find the network handle to bind anyway. | |
224 if (worker_thread()->socketserver()->network_binder() == this) { | |
225 worker_thread()->socketserver()->set_network_binder(nullptr); | |
226 } | |
227 | |
228 jmethodID m = | |
229 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); | |
230 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | |
231 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; | |
232 | |
233 network_handle_by_address_.clear(); | |
234 network_info_by_handle_.clear(); | |
235 } | |
236 | |
237 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, | |
238 const rtc::IPAddress& address) { | |
239 RTC_CHECK(thread_checker_.CalledOnValidThread()); | |
240 // Android prior to Lollipop didn't have support for binding sockets to | |
241 // networks. However, in that case it should not have reached here because | |
242 // |network_handle_by_address_| should only be populated in Android Lollipop | |
243 // and above. | |
244 // TODO(honghaiz): Add a check for Android version here so that it won't try | |
245 // to look for handle if the Android version is before Lollipop. | |
246 auto iter = network_handle_by_address_.find(address); | |
247 if (iter == network_handle_by_address_.end()) { | |
248 return rtc::NETWORK_BIND_ADDRESS_NOT_FOUND; | |
249 } | |
250 NetworkHandle network_handle = iter->second; | |
251 | |
252 // NOTE: This does rely on Android implementation details, but | |
253 // these details are unlikely to change. | |
254 typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); | |
255 static SetNetworkForSocket setNetworkForSocket; | |
256 // This is not threadsafe, but we are running this only on the worker thread. | |
257 if (setNetworkForSocket == nullptr) { | |
258 // Android's netd client library should always be loaded in our address | |
259 // space as it shims libc functions like connect(). | |
260 const std::string net_library_path = "libnetd_client.so"; | |
261 void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY); | |
262 if (lib == nullptr) { | |
263 LOG(LS_ERROR) << "Library " << net_library_path << " not found!"; | |
264 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; | |
265 } | |
266 setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>( | |
267 dlsym(lib, "setNetworkForSocket")); | |
268 } | |
269 if (setNetworkForSocket == nullptr) { | |
270 LOG(LS_ERROR) << "Symbol setNetworkForSocket not found "; | |
271 return rtc::NETWORK_BIND_NOT_IMPLEMENTED; | |
272 } | |
273 int rv = setNetworkForSocket(network_handle, socket_fd); | |
274 // If |network| has since disconnected, |rv| will be ENONET. Surface this as | |
275 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back | |
276 // the less descriptive ERR_FAILED. | |
277 if (rv == 0) { | |
278 return rtc::NETWORK_BIND_SUCCESS; | |
279 } | |
280 if (rv == ENONET) { | |
281 return rtc::NETWORK_BIND_NETWORK_CHANGED; | |
282 } | |
283 return rtc::NETWORK_BIND_FAILURE; | |
284 } | |
285 | |
286 void AndroidNetworkMonitor::OnNetworkConnected( | |
287 const NetworkInformation& network_info) { | |
288 LOG(LS_INFO) << "Network connected: " << network_info.ToString(); | |
289 worker_thread()->Invoke<void>(rtc::Bind( | |
290 &AndroidNetworkMonitor::OnNetworkConnected_w, this, network_info)); | |
291 } | |
292 | |
293 void AndroidNetworkMonitor::OnNetworkConnected_w( | |
294 const NetworkInformation& network_info) { | |
295 adapter_type_by_name_[network_info.interface_name] = | |
296 AdapterTypeFromNetworkType(network_info.type); | |
297 network_info_by_handle_[network_info.handle] = network_info; | |
298 for (const rtc::IPAddress& address : network_info.ip_addresses) { | |
299 network_handle_by_address_[address] = network_info.handle; | |
300 } | |
301 } | |
302 | |
303 void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) { | |
304 LOG(LS_INFO) << "Network disconnected for handle " << handle; | |
305 worker_thread()->Invoke<void>( | |
306 rtc::Bind(&AndroidNetworkMonitor::OnNetworkDisconnected_w, this, handle)); | |
307 } | |
308 | |
309 void AndroidNetworkMonitor::OnNetworkDisconnected_w(NetworkHandle handle) { | |
310 auto iter = network_info_by_handle_.find(handle); | |
311 if (iter != network_info_by_handle_.end()) { | |
312 for (const rtc::IPAddress& address : iter->second.ip_addresses) { | |
313 network_handle_by_address_.erase(address); | |
314 } | |
315 network_info_by_handle_.erase(iter); | |
316 } | |
317 } | |
318 | |
319 void AndroidNetworkMonitor::SetNetworkInfos( | |
320 const std::vector<NetworkInformation>& network_infos) { | |
321 RTC_CHECK(thread_checker_.CalledOnValidThread()); | |
322 network_handle_by_address_.clear(); | |
323 network_info_by_handle_.clear(); | |
324 for (NetworkInformation network : network_infos) { | |
325 OnNetworkConnected_w(network); | |
326 } | |
327 } | |
328 | |
329 rtc::AdapterType AndroidNetworkMonitor::GetAdapterType( | |
330 const std::string& if_name) { | |
331 auto iter = adapter_type_by_name_.find(if_name); | |
332 if (iter == adapter_type_by_name_.end()) { | |
333 return rtc::ADAPTER_TYPE_UNKNOWN; | |
334 } | |
335 return iter->second; | |
336 } | |
337 | |
338 rtc::NetworkMonitorInterface* | |
339 AndroidNetworkMonitorFactory::CreateNetworkMonitor() { | |
340 return new AndroidNetworkMonitor(); | |
341 } | |
342 | |
343 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( | |
344 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { | |
345 rtc::NetworkMonitorInterface* network_monitor = | |
346 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); | |
347 network_monitor->OnNetworksChanged(); | |
348 } | |
349 | |
350 JOW(void, NetworkMonitor_nativeNotifyOfActiveNetworkList)( | |
351 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, | |
352 jobjectArray j_network_infos) { | |
353 AndroidNetworkMonitor* network_monitor = | |
354 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); | |
355 std::vector<NetworkInformation> network_infos; | |
356 size_t num_networks = jni->GetArrayLength(j_network_infos); | |
357 for (size_t i = 0; i < num_networks; ++i) { | |
358 jobject j_network_info = jni->GetObjectArrayElement(j_network_infos, i); | |
359 CHECK_EXCEPTION(jni) << "Error during GetObjectArrayElement"; | |
360 network_infos.push_back(GetNetworkInformationFromJava(jni, j_network_info)); | |
361 } | |
362 network_monitor->SetNetworkInfos(network_infos); | |
363 } | |
364 | |
365 JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)( | |
366 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, | |
367 jobject j_network_info) { | |
368 AndroidNetworkMonitor* network_monitor = | |
369 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); | |
370 NetworkInformation network_info = | |
371 GetNetworkInformationFromJava(jni, j_network_info); | |
372 network_monitor->OnNetworkConnected(network_info); | |
373 } | |
374 | |
375 JOW(void, NetworkMonitor_nativeNotifyOfNetworkDisconnect)( | |
376 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, | |
377 jint network_handle) { | |
378 AndroidNetworkMonitor* network_monitor = | |
379 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); | |
380 network_monitor->OnNetworkDisconnected( | |
381 static_cast<NetworkHandle>(network_handle)); | |
382 } | |
383 | |
384 } // namespace webrtc_jni | |
OLD | NEW |