Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: talk/app/webrtc/java/jni/androidnetworkmonitor_jni.cc

Issue 1556743002: Bind a socket to a network if the network handle is set. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h ('k') | talk/app/webrtc/java/jni/classreferenceholder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698