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 | |
30 #include "webrtc/base/common.h" | 32 #include "webrtc/base/common.h" |
33 #include "webrtc/base/ipaddress.h" | |
31 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | 34 #include "talk/app/webrtc/java/jni/classreferenceholder.h" |
32 #include "talk/app/webrtc/java/jni/jni_helpers.h" | 35 #include "talk/app/webrtc/java/jni/jni_helpers.h" |
33 | 36 |
34 namespace webrtc_jni { | 37 namespace webrtc_jni { |
38 | |
35 jobject AndroidNetworkMonitor::application_context_ = nullptr; | 39 jobject AndroidNetworkMonitor::application_context_ = nullptr; |
36 | 40 |
41 static NetworkType GetNetworkTypeFromJava(JNIEnv* jni, jobject j_network_type) { | |
42 std::string enum_name = | |
43 GetJavaEnumName(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType", | |
44 j_network_type); | |
45 if (enum_name == "CONNECTION_UNKNOWN") { | |
46 return NetworkType::NETWORK_UNKNOWN; | |
47 } | |
48 if (enum_name == "CONNECTION_ETHERNET") { | |
49 return NetworkType::NETWORK_ETHERNET; | |
50 } | |
51 if (enum_name == "CONNECTION_WIFI") { | |
52 return NetworkType::NETWORK_WIFI; | |
53 } | |
54 if (enum_name == "CONNECTION_4G") { | |
55 return NetworkType::NETWORK_4G; | |
56 } | |
57 if (enum_name == "CONNECTION_3G") { | |
58 return NetworkType::NETWORK_3G; | |
59 } | |
60 if (enum_name == "CONNECTION_2G") { | |
61 return NetworkType::NETWORK_2G; | |
62 } | |
63 if (enum_name == "CONNECTION_BLUETOOTH") { | |
64 return NetworkType::NETWORK_BLUETOOTH; | |
65 } | |
66 if (enum_name == "CONNECTION_NONE") { | |
67 return NetworkType::NETWORK_NONE; | |
68 } | |
69 ASSERT(false); | |
70 return NetworkType::NETWORK_UNKNOWN; | |
71 } | |
72 | |
73 static rtc::IPAddress GetIPAddressFromJava(JNIEnv* jni, jobject j_ip_address) { | |
74 jclass j_ip_address_class = GetObjectClass(jni, j_ip_address); | |
75 jfieldID j_address_id = GetFieldID(jni, j_ip_address_class, "address", "[B"); | |
76 jbyteArray j_addresses = | |
77 static_cast<jbyteArray>(GetObjectField(jni, j_ip_address, j_address_id)); | |
78 size_t address_length = jni->GetArrayLength(j_addresses); | |
79 jbyte* addr_array = jni->GetByteArrayElements(j_addresses, NULL); | |
80 CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.GetIPAddressFromJava"; | |
81 if (address_length == 4) { | |
82 // IP4 | |
83 struct in_addr ip4_addr; | |
84 memcpy(&ip4_addr.s_addr, addr_array, 4); | |
85 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); | |
86 return rtc::IPAddress(ip4_addr); | |
87 } | |
88 // IP6 | |
89 RTC_CHECK(address_length == 16); | |
90 struct in6_addr ip6_addr; | |
91 memcpy(ip6_addr.s6_addr, addr_array, address_length); | |
92 jni->ReleaseByteArrayElements(j_addresses, addr_array, JNI_ABORT); | |
93 return rtc::IPAddress(ip6_addr); | |
94 } | |
95 | |
96 static void GetIPAddressesFromJava(JNIEnv* jni, | |
97 jobjectArray j_ip_addresses, | |
98 std::vector<rtc::IPAddress>* ip_addresses) { | |
99 ip_addresses->clear(); | |
100 size_t num_addresses = jni->GetArrayLength(j_ip_addresses); | |
101 for (size_t i = 0; i < num_addresses; ++i) { | |
102 jobject j_ip_address = jni->GetObjectArrayElement(j_ip_addresses, i); | |
103 rtc::IPAddress ip = GetIPAddressFromJava(jni, j_ip_address); | |
104 | |
105 ip_addresses->push_back(ip); | |
106 } | |
107 CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.GetIPAddressesFromJava"; | |
108 } | |
109 | |
110 static NetworkInformation GetNetworkInformationFromJava( | |
111 JNIEnv* jni, | |
112 jobject j_network_info) { | |
113 jclass j_network_info_class = GetObjectClass(jni, j_network_info); | |
114 jfieldID j_interface_name_id = | |
115 GetFieldID(jni, j_network_info_class, "name", "Ljava/lang/String;"); | |
116 jfieldID j_handle_id = GetFieldID(jni, j_network_info_class, "handle", "I"); | |
117 jfieldID j_type_id = | |
118 GetFieldID(jni, j_network_info_class, "type", | |
119 "Lorg/webrtc/NetworkMonitorAutoDetect$ConnectionType;"); | |
120 jfieldID j_ip_addresses_id = | |
121 GetFieldID(jni, j_network_info_class, "ipAddresses", | |
122 "[Lorg/webrtc/NetworkMonitorAutoDetect$IPAddress;"); | |
123 | |
124 NetworkInformation network_info; | |
125 network_info.interface_name = JavaToStdString( | |
126 jni, GetStringField(jni, j_network_info, j_interface_name_id)); | |
127 network_info.handle = static_cast<rtc::NetworkHandle>( | |
128 GetIntField(jni, j_network_info, j_handle_id)); | |
129 network_info.type = GetNetworkTypeFromJava( | |
130 jni, GetObjectField(jni, j_network_info, j_type_id)); | |
131 jobjectArray j_ip_addresses = static_cast<jobjectArray>( | |
132 GetObjectField(jni, j_network_info, j_ip_addresses_id)); | |
133 GetIPAddressesFromJava(jni, j_ip_addresses, &network_info.ip_addresses); | |
134 CHECK_EXCEPTION(jni) << "Error during NetworkMonitor.GetNetworkInfoFromJava"; | |
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"; |
172 thread_checker_.DetachFromThread(); | |
60 } | 173 } |
61 | 174 |
62 void AndroidNetworkMonitor::Start() { | 175 void AndroidNetworkMonitor::Start() { |
176 NetworkMonitorBase::Start(); | |
177 | |
63 RTC_CHECK(thread_checker_.CalledOnValidThread()); | 178 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
64 jmethodID m = | 179 jmethodID m = |
65 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); | 180 GetMethodID(jni(), *j_network_monitor_class_, "startMonitoring", "(J)V"); |
66 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | 181 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
67 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; | 182 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.startMonitoring"; |
68 } | 183 } |
69 | 184 |
70 void AndroidNetworkMonitor::Stop() { | 185 void AndroidNetworkMonitor::Stop() { |
71 RTC_CHECK(thread_checker_.CalledOnValidThread()); | 186 RTC_CHECK(thread_checker_.CalledOnValidThread()); |
72 jmethodID m = | 187 jmethodID m = |
73 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); | 188 GetMethodID(jni(), *j_network_monitor_class_, "stopMonitoring", "(J)V"); |
74 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); | 189 jni()->CallVoidMethod(*j_network_monitor_, m, jlongFromPointer(this)); |
75 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; | 190 CHECK_EXCEPTION(jni()) << "Error during NetworkMonitor.stopMonitoring"; |
76 } | 191 } |
77 | 192 |
193 int AndroidNetworkMonitor::BindSocketToNetwork(int socket_fd, | |
194 const rtc::IPAddress& address) { | |
195 RTC_CHECK(thread_checker_.CalledOnValidThread()); | |
196 if (network_info_map_.find(address) == network_info_map_.end()) { | |
197 return rtc::ERR_ADDRESS_NOT_FOUND; | |
pthatcher1
2016/01/14 20:07:24
If you store the result of the .find() you won't h
honghaiz3
2016/01/15 01:00:38
Done.
| |
198 } | |
199 // Android prior to Lollipop didn't have support for binding sockets to | |
200 // networks. However, in that case it should not have reached here because | |
201 // |network_info_map_| should only be populated on Android Lollipop and above. | |
202 NetworkInformation network = network_info_map_[address]; | |
203 | |
204 // NOTE: This does rely on Android implementation details, but | |
205 // these details are unlikely to change. | |
206 typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd); | |
207 static SetNetworkForSocket setNetworkForSocket; | |
208 // This is not threadsafe, but we are running this only on the worker thread. | |
209 if (setNetworkForSocket == nullptr) { | |
210 // Android's netd client library should always be loaded in our address | |
211 // space as it shims libc functions like connect(). | |
212 const std::string net_library_path = "libnetd_client.so"; | |
213 void* lib = dlopen(net_library_path.c_str(), RTLD_LAZY); | |
214 if (lib == nullptr) { | |
215 LOG(LS_ERROR) << "Library " << net_library_path << " not found!"; | |
216 return rtc::ERR_NOT_IMPLEMENTED; | |
217 } | |
218 setNetworkForSocket = reinterpret_cast<SetNetworkForSocket>( | |
219 dlsym(lib, "setNetworkForSocket")); | |
220 } | |
221 if (setNetworkForSocket == nullptr) { | |
222 LOG(LS_ERROR) << "Symbol setNetworkForSocket not found "; | |
223 return rtc::ERR_NOT_IMPLEMENTED; | |
224 } | |
225 int rv = setNetworkForSocket(network.handle, socket_fd); | |
226 // If |network| has since disconnected, |rv| will be ENONET. Surface this as | |
227 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back | |
228 // the less descriptive ERR_FAILED. | |
229 if (rv == ENONET) { | |
230 rv = rtc::ERR_NETWORK_CHANGED; | |
231 } | |
232 return rv; | |
233 } | |
234 | |
235 void AndroidNetworkMonitor::OnNetworkAvailable( | |
236 const NetworkInformation& network_info) { | |
237 LOG(LS_INFO) << "Network available: " << network_info.ToString(); | |
238 for (rtc::IPAddress address : network_info.ip_addresses) { | |
239 network_info_map_[address] = network_info; | |
240 } | |
241 } | |
242 | |
243 rtc::NetworkMonitorInterface* | |
244 AndroidNetworkMonitorFactory::GetOrCreateNetworkMonitor() { | |
245 rtc::CritScope cs(&crit_); | |
246 if (!network_monitor_) { | |
247 network_monitor_.reset(new AndroidNetworkMonitor()); | |
248 } | |
249 return network_monitor_.get(); | |
250 } | |
251 | |
78 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( | 252 JOW(void, NetworkMonitor_nativeNotifyConnectionTypeChanged)( |
79 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { | 253 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor) { |
80 rtc::NetworkMonitorInterface* network_monitor = | 254 rtc::NetworkMonitorInterface* network_monitor = |
81 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); | 255 reinterpret_cast<rtc::NetworkMonitorInterface*>(j_native_monitor); |
82 network_monitor->OnNetworksChanged(); | 256 network_monitor->OnNetworksChanged(); |
83 } | 257 } |
84 | 258 |
259 JOW(void, NetworkMonitor_nativeNotifyOfNetworkConnect)( | |
260 JNIEnv* jni, jobject j_monitor, jlong j_native_monitor, | |
261 jobject j_network_info) { | |
262 AndroidNetworkMonitor* network_monitor = | |
263 reinterpret_cast<AndroidNetworkMonitor*>(j_native_monitor); | |
264 NetworkInformation network_info = | |
265 GetNetworkInformationFromJava(jni, j_network_info); | |
266 network_monitor->OnNetworkAvailable(network_info); | |
267 } | |
268 | |
85 } // namespace webrtc_jni | 269 } // namespace webrtc_jni |
OLD | NEW |