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 "webrtc/base/bind.h" | |
33 #include "webrtc/base/common.h" | |
34 #include "webrtc/base/ipaddress.h" | |
35 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | |
36 #include "talk/app/webrtc/java/jni/jni_helpers.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::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 | |
149 // static | |
150 void AndroidNetworkMonitor::SetAndroidContext(JNIEnv* jni, jobject context) { | |
151 if (application_context_) { | |
152 jni->DeleteGlobalRef(application_context_); | |
153 } | |
154 application_context_ = NewGlobalRef(jni, context); | |
155 } | |
156 | |
157 AndroidNetworkMonitor::AndroidNetworkMonitor() | |
158 : j_network_monitor_class_(jni(), | |
159 FindClass(jni(), "org/webrtc/NetworkMonitor")), | |
160 j_network_monitor_( | |
161 jni(), | |
162 jni()->CallStaticObjectMethod( | |
163 *j_network_monitor_class_, | |
164 GetStaticMethodID( | |
165 jni(), | |
166 *j_network_monitor_class_, | |
167 "init", | |
168 "(Landroid/content/Context;)Lorg/webrtc/NetworkMonitor;"), | |
169 application_context_)) { | |
170 ASSERT(application_context_ != nullptr); | |
171 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.init"; | |
172 } | |
173 | |
174 void AndroidNetworkMonitor::Start() { | |
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 | |
186 jmethodID m = | |
187 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); | |
188 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | |
189 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; | |
190 } | |
191 | |
192 void AndroidNetworkMonitor::Stop() { | |
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 | |
205 jmethodID m = | |
206 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); | |
207 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | |
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(); | |
277 } | |
278 | |
279 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( | |
280 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { | |
281 rtc::NetworkMonitorInterface* network_monitor = | |
282 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); | |
283 network_monitor->OnNetworksChanged(); | |
284 } | |
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 | |
296 } // namespace webrtc_jni | |
OLD | NEW |