OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/address_tracker_linux.h" | 5 #include "net/base/address_tracker_linux.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <linux/if.h> | 8 #include <linux/if.h> |
9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
10 | 10 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 const base::Closure& tunnel_callback) | 102 const base::Closure& tunnel_callback) |
103 : get_interface_name_(GetInterfaceName), | 103 : get_interface_name_(GetInterfaceName), |
104 address_callback_(address_callback), | 104 address_callback_(address_callback), |
105 link_callback_(link_callback), | 105 link_callback_(link_callback), |
106 tunnel_callback_(tunnel_callback), | 106 tunnel_callback_(tunnel_callback), |
107 netlink_fd_(-1), | 107 netlink_fd_(-1), |
108 is_offline_(true), | 108 is_offline_(true), |
109 is_offline_initialized_(false), | 109 is_offline_initialized_(false), |
110 is_offline_initialized_cv_(&is_offline_lock_) { | 110 is_offline_initialized_cv_(&is_offline_lock_) { |
111 DCHECK(!address_callback.is_null()); | 111 DCHECK(!address_callback.is_null()); |
112 DCHECK(!link_callback.is_null()); | 112 DCHECK(!link_callback.is_null()); |
pauljensen
2014/09/18 13:56:15
I think these two lines will give you troubles whe
guoweis2
2014/09/18 19:41:11
There is a do nothing version used by unit tests.
| |
113 } | 113 } |
114 | 114 |
115 AddressTrackerLinux::~AddressTrackerLinux() { | 115 AddressTrackerLinux::~AddressTrackerLinux() { |
116 CloseSocket(); | 116 CloseSocket(); |
117 } | 117 } |
118 | 118 |
119 void AddressTrackerLinux::Init() { | 119 void AddressTrackerLinux::Init(bool track) { |
120 netlink_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | 120 netlink_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
121 if (netlink_fd_ < 0) { | 121 if (netlink_fd_ < 0) { |
122 PLOG(ERROR) << "Could not create NETLINK socket"; | 122 PLOG(ERROR) << "Could not create NETLINK socket"; |
123 AbortAndForceOnline(); | 123 AbortAndForceOnline(); |
124 return; | 124 return; |
125 } | 125 } |
126 | 126 |
127 // Request notifications. | 127 int rv; |
128 struct sockaddr_nl addr = {}; | 128 |
129 addr.nl_family = AF_NETLINK; | 129 if (track) { |
130 addr.nl_pid = getpid(); | 130 // Request notifications. |
131 // TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993 | 131 struct sockaddr_nl addr = {}; |
132 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | | 132 addr.nl_family = AF_NETLINK; |
133 RTMGRP_LINK; | 133 addr.nl_pid = getpid(); |
134 int rv = bind(netlink_fd_, | 134 // TODO(szym): Track RTMGRP_LINK as well for ifi_type, |
135 reinterpret_cast<struct sockaddr*>(&addr), | 135 // http://crbug.com/113993 |
136 sizeof(addr)); | 136 addr.nl_groups = |
137 if (rv < 0) { | 137 RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | RTMGRP_LINK; |
138 PLOG(ERROR) << "Could not bind NETLINK socket"; | 138 rv = bind( |
139 AbortAndForceOnline(); | 139 netlink_fd_, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)); |
140 return; | 140 if (rv < 0) { |
141 PLOG(ERROR) << "Could not bind NETLINK socket"; | |
142 AbortAndForceOnline(); | |
143 return; | |
144 } | |
141 } | 145 } |
142 | 146 |
143 // Request dump of addresses. | 147 // Request dump of addresses. |
144 struct sockaddr_nl peer = {}; | 148 struct sockaddr_nl peer = {}; |
145 peer.nl_family = AF_NETLINK; | 149 peer.nl_family = AF_NETLINK; |
146 | 150 |
147 struct { | 151 struct { |
148 struct nlmsghdr header; | 152 struct nlmsghdr header; |
149 struct rtgenmsg msg; | 153 struct rtgenmsg msg; |
150 } request = {}; | 154 } request = {}; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 } | 188 } |
185 | 189 |
186 // Consume pending message to populate links_online_, but don't notify. | 190 // Consume pending message to populate links_online_, but don't notify. |
187 ReadMessages(&address_changed, &link_changed, &tunnel_changed); | 191 ReadMessages(&address_changed, &link_changed, &tunnel_changed); |
188 { | 192 { |
189 base::AutoLock lock(is_offline_lock_); | 193 base::AutoLock lock(is_offline_lock_); |
190 is_offline_initialized_ = true; | 194 is_offline_initialized_ = true; |
191 is_offline_initialized_cv_.Signal(); | 195 is_offline_initialized_cv_.Signal(); |
192 } | 196 } |
193 | 197 |
194 rv = base::MessageLoopForIO::current()->WatchFileDescriptor( | 198 if (track) { |
195 netlink_fd_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this); | 199 rv = base::MessageLoopForIO::current()->WatchFileDescriptor( |
196 if (rv < 0) { | 200 netlink_fd_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this); |
197 PLOG(ERROR) << "Could not watch NETLINK socket"; | 201 if (rv < 0) { |
198 AbortAndForceOnline(); | 202 PLOG(ERROR) << "Could not watch NETLINK socket"; |
199 return; | 203 AbortAndForceOnline(); |
204 return; | |
205 } | |
200 } | 206 } |
201 } | 207 } |
202 | 208 |
203 void AddressTrackerLinux::AbortAndForceOnline() { | 209 void AddressTrackerLinux::AbortAndForceOnline() { |
204 CloseSocket(); | 210 CloseSocket(); |
205 base::AutoLock lock(is_offline_lock_); | 211 base::AutoLock lock(is_offline_lock_); |
206 is_offline_ = false; | 212 is_offline_ = false; |
207 is_offline_initialized_ = true; | 213 is_offline_initialized_ = true; |
208 is_offline_initialized_cv_.Signal(); | 214 is_offline_initialized_cv_.Signal(); |
209 } | 215 } |
210 | 216 |
211 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { | 217 AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const { |
212 base::AutoLock lock(address_map_lock_); | 218 base::AutoLock lock(address_map_lock_); |
213 return address_map_; | 219 return address_map_; |
214 } | 220 } |
215 | 221 |
222 base::hash_set<int> AddressTrackerLinux::GetOnlineLinks() const { | |
223 base::AutoLock lock(online_links_lock_); | |
224 return online_links_; | |
225 } | |
226 | |
216 NetworkChangeNotifier::ConnectionType | 227 NetworkChangeNotifier::ConnectionType |
217 AddressTrackerLinux::GetCurrentConnectionType() { | 228 AddressTrackerLinux::GetCurrentConnectionType() { |
218 // http://crbug.com/125097 | 229 // http://crbug.com/125097 |
219 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 230 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
220 base::AutoLock lock(is_offline_lock_); | 231 base::AutoLock lock(is_offline_lock_); |
221 // Make sure the initial offline state is set before returning. | 232 // Make sure the initial offline state is set before returning. |
222 while (!is_offline_initialized_) { | 233 while (!is_offline_initialized_) { |
223 is_offline_initialized_cv_.Wait(); | 234 is_offline_initialized_cv_.Wait(); |
224 } | 235 } |
225 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. | 236 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
(...skipping 21 matching lines...) Expand all Loading... | |
247 LOG(ERROR) << "Unexpected shutdown of NETLINK socket."; | 258 LOG(ERROR) << "Unexpected shutdown of NETLINK socket."; |
248 return; | 259 return; |
249 } | 260 } |
250 if (rv < 0) { | 261 if (rv < 0) { |
251 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) | 262 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) |
252 break; | 263 break; |
253 PLOG(ERROR) << "Failed to recv from netlink socket"; | 264 PLOG(ERROR) << "Failed to recv from netlink socket"; |
254 return; | 265 return; |
255 } | 266 } |
256 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); | 267 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed); |
257 }; | 268 } |
258 if (*link_changed) { | 269 if (*link_changed) { |
270 bool is_offline; | |
271 { | |
272 base::AutoLock lock(online_links_lock_); | |
273 is_offline = online_links_.empty(); | |
274 } | |
259 base::AutoLock lock(is_offline_lock_); | 275 base::AutoLock lock(is_offline_lock_); |
260 is_offline_ = online_links_.empty(); | 276 is_offline_ = is_offline; |
261 } | 277 } |
262 } | 278 } |
263 | 279 |
264 void AddressTrackerLinux::HandleMessage(char* buffer, | 280 void AddressTrackerLinux::HandleMessage(char* buffer, |
265 size_t length, | 281 size_t length, |
266 bool* address_changed, | 282 bool* address_changed, |
267 bool* link_changed, | 283 bool* link_changed, |
268 bool* tunnel_changed) { | 284 bool* tunnel_changed) { |
269 DCHECK(buffer); | 285 DCHECK(buffer); |
270 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); | 286 for (struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buffer); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 base::AutoLock lock(address_map_lock_); | 328 base::AutoLock lock(address_map_lock_); |
313 if (address_map_.erase(address)) | 329 if (address_map_.erase(address)) |
314 *address_changed = true; | 330 *address_changed = true; |
315 } | 331 } |
316 } break; | 332 } break; |
317 case RTM_NEWLINK: { | 333 case RTM_NEWLINK: { |
318 const struct ifinfomsg* msg = | 334 const struct ifinfomsg* msg = |
319 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); | 335 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); |
320 if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) && | 336 if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) && |
321 (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) { | 337 (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) { |
338 base::AutoLock lock(online_links_lock_); | |
322 if (online_links_.insert(msg->ifi_index).second) { | 339 if (online_links_.insert(msg->ifi_index).second) { |
323 *link_changed = true; | 340 *link_changed = true; |
324 if (IsTunnelInterface(msg)) | 341 if (IsTunnelInterface(msg)) |
325 *tunnel_changed = true; | 342 *tunnel_changed = true; |
326 } | 343 } |
327 } else { | 344 } else { |
345 base::AutoLock lock(online_links_lock_); | |
328 if (online_links_.erase(msg->ifi_index)) { | 346 if (online_links_.erase(msg->ifi_index)) { |
329 *link_changed = true; | 347 *link_changed = true; |
330 if (IsTunnelInterface(msg)) | 348 if (IsTunnelInterface(msg)) |
331 *tunnel_changed = true; | 349 *tunnel_changed = true; |
332 } | 350 } |
333 } | 351 } |
334 } break; | 352 } break; |
335 case RTM_DELLINK: { | 353 case RTM_DELLINK: { |
336 const struct ifinfomsg* msg = | 354 const struct ifinfomsg* msg = |
337 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); | 355 reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); |
356 base::AutoLock lock(online_links_lock_); | |
338 if (online_links_.erase(msg->ifi_index)) { | 357 if (online_links_.erase(msg->ifi_index)) { |
339 *link_changed = true; | 358 *link_changed = true; |
340 if (IsTunnelInterface(msg)) | 359 if (IsTunnelInterface(msg)) |
341 *tunnel_changed = true; | 360 *tunnel_changed = true; |
342 } | 361 } |
343 } break; | 362 } break; |
344 default: | 363 default: |
345 break; | 364 break; |
346 } | 365 } |
347 } | 366 } |
(...skipping 21 matching lines...) Expand all Loading... | |
369 netlink_fd_ = -1; | 388 netlink_fd_ = -1; |
370 } | 389 } |
371 | 390 |
372 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { | 391 bool AddressTrackerLinux::IsTunnelInterface(const struct ifinfomsg* msg) const { |
373 // Linux kernel drivers/net/tun.c uses "tun" name prefix. | 392 // Linux kernel drivers/net/tun.c uses "tun" name prefix. |
374 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; | 393 return strncmp(get_interface_name_(msg->ifi_index), "tun", 3) == 0; |
375 } | 394 } |
376 | 395 |
377 } // namespace internal | 396 } // namespace internal |
378 } // namespace net | 397 } // namespace net |
OLD | NEW |