summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
Diffstat (limited to 'net/base')
-rw-r--r--net/base/address_tracker_linux.cc214
-rw-r--r--net/base/address_tracker_linux.h49
-rw-r--r--net/base/address_tracker_linux_unittest.cc209
-rw-r--r--net/base/network_change_notifier_linux.cc257
-rw-r--r--net/base/network_change_notifier_linux.h9
-rw-r--r--net/base/network_change_notifier_linux_unittest.cc243
6 files changed, 359 insertions, 622 deletions
diff --git a/net/base/address_tracker_linux.cc b/net/base/address_tracker_linux.cc
index 52bc928..67eaa69 100644
--- a/net/base/address_tracker_linux.cc
+++ b/net/base/address_tracker_linux.cc
@@ -5,9 +5,11 @@
#include "net/base/address_tracker_linux.h"
#include <errno.h>
+#include <linux/if.h>
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread_restrictions.h"
#include "net/base/network_change_notifier_linux.h"
namespace net {
@@ -63,28 +65,29 @@ bool GetAddress(const struct nlmsghdr* header, IPAddressNumber* out) {
return true;
}
-void CloseSocket(int fd) {
- if (HANDLE_EINTR(close(fd)) < 0)
- PLOG(ERROR) << "Could not close NETLINK socket.";
-}
-
} // namespace
-AddressTrackerLinux::AddressTrackerLinux(const base::Closure& callback)
- : callback_(callback),
- netlink_fd_(-1) {
- DCHECK(!callback.is_null());
+AddressTrackerLinux::AddressTrackerLinux(const base::Closure& address_callback,
+ const base::Closure& link_callback)
+ : address_callback_(address_callback),
+ link_callback_(link_callback),
+ netlink_fd_(-1),
+ is_offline_(true),
+ is_offline_initialized_(false),
+ is_offline_initialized_cv_(&is_offline_lock_) {
+ DCHECK(!address_callback.is_null());
+ DCHECK(!link_callback.is_null());
}
AddressTrackerLinux::~AddressTrackerLinux() {
- if (netlink_fd_ >= 0)
- CloseSocket(netlink_fd_);
+ CloseSocket();
}
void AddressTrackerLinux::Init() {
- int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock < 0) {
+ netlink_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (netlink_fd_ < 0) {
PLOG(ERROR) << "Could not create NETLINK socket";
+ AbortAndForceOnline();
return;
}
@@ -93,26 +96,14 @@ void AddressTrackerLinux::Init() {
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
// TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993
- addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY;
- int rv = bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
+ addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY |
+ RTMGRP_LINK;
+ int rv = bind(netlink_fd_,
+ reinterpret_cast<struct sockaddr*>(&addr),
+ sizeof(addr));
if (rv < 0) {
PLOG(ERROR) << "Could not bind NETLINK socket";
- CloseSocket(sock);
- return;
- }
-
- // Watch for asynchronous messages.
- if (SetNonBlocking(sock)) {
- PLOG(ERROR) << "Could not make NETLINK socket non-blocking";
- CloseSocket(sock);
- return;
- }
-
- rv = MessageLoopForIO::current()->WatchFileDescriptor(
- sock, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
- if (rv < 0) {
- PLOG(ERROR) << "Could not watch NETLINK socket";
- CloseSocket(sock);
+ AbortAndForceOnline();
return;
}
@@ -125,105 +116,200 @@ void AddressTrackerLinux::Init() {
struct rtgenmsg msg;
} request = {};
- request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
+ request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request));
request.header.nlmsg_type = RTM_GETADDR;
request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
request.header.nlmsg_pid = getpid();
request.msg.rtgen_family = AF_UNSPEC;
- rv = HANDLE_EINTR(sendto(sock, &request, request.header.nlmsg_len, 0,
+ rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len,
+ 0, reinterpret_cast<struct sockaddr*>(&peer),
+ sizeof(peer)));
+ if (rv < 0) {
+ PLOG(ERROR) << "Could not send NETLINK request";
+ AbortAndForceOnline();
+ return;
+ }
+
+ // Consume pending message to populate the AddressMap, but don't notify.
+ // Sending another request without first reading responses results in EBUSY.
+ bool address_changed;
+ bool link_changed;
+ ReadMessages(&address_changed, &link_changed);
+
+ // Request dump of link state
+ request.header.nlmsg_type = RTM_GETLINK;
+
+ rv = HANDLE_EINTR(sendto(netlink_fd_, &request, request.header.nlmsg_len, 0,
reinterpret_cast<struct sockaddr*>(&peer),
sizeof(peer)));
if (rv < 0) {
PLOG(ERROR) << "Could not send NETLINK request";
- CloseSocket(sock);
+ AbortAndForceOnline();
return;
}
- netlink_fd_ = sock;
+ // Consume pending message to populate links_online_, but don't notify.
+ ReadMessages(&address_changed, &link_changed);
+ {
+ base::AutoLock lock(is_offline_lock_);
+ is_offline_initialized_ = true;
+ is_offline_initialized_cv_.Signal();
+ }
+
+ rv = MessageLoopForIO::current()->WatchFileDescriptor(
+ netlink_fd_, true, MessageLoopForIO::WATCH_READ, &watcher_, this);
+ if (rv < 0) {
+ PLOG(ERROR) << "Could not watch NETLINK socket";
+ AbortAndForceOnline();
+ return;
+ }
+}
- // Consume any pending messages to populate the AddressMap, but don't notify.
- ReadMessages();
+void AddressTrackerLinux::AbortAndForceOnline() {
+ CloseSocket();
+ base::AutoLock lock(is_offline_lock_);
+ is_offline_ = false;
+ is_offline_initialized_ = true;
+ is_offline_initialized_cv_.Signal();
}
AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const {
- base::AutoLock lock(lock_);
- return map_;
+ base::AutoLock lock(address_map_lock_);
+ return address_map_;
+}
+
+NetworkChangeNotifier::ConnectionType
+AddressTrackerLinux::GetCurrentConnectionType() {
+ // http://crbug.com/125097
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ base::AutoLock lock(is_offline_lock_);
+ // Make sure the initial offline state is set before returning.
+ while (!is_offline_initialized_) {
+ is_offline_initialized_cv_.Wait();
+ }
+ // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN.
+ // http://crbug.com/160537
+ return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE :
+ NetworkChangeNotifier::CONNECTION_UNKNOWN;
}
-bool AddressTrackerLinux::ReadMessages() {
+void AddressTrackerLinux::ReadMessages(bool* address_changed,
+ bool* link_changed) {
+ *address_changed = false;
+ *link_changed = false;
char buffer[4096];
- bool changed = false;
+ bool first_loop = true;
for (;;) {
- int rv = HANDLE_EINTR(recv(netlink_fd_, buffer, sizeof(buffer), 0));
+ int rv = HANDLE_EINTR(recv(netlink_fd_,
+ buffer,
+ sizeof(buffer),
+ // Block the first time through loop.
+ first_loop ? 0 : MSG_DONTWAIT));
+ first_loop = false;
if (rv == 0) {
LOG(ERROR) << "Unexpected shutdown of NETLINK socket.";
- return false;
+ return;
}
if (rv < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
break;
PLOG(ERROR) << "Failed to recv from netlink socket";
- return false;
+ return;
}
- changed |= HandleMessage(buffer, rv);
+ HandleMessage(buffer, rv, address_changed, link_changed);
};
- return changed;
+ if (*link_changed) {
+ base::AutoLock lock(is_offline_lock_);
+ is_offline_ = online_links_.empty();
+ }
}
-bool AddressTrackerLinux::HandleMessage(const char* buffer, size_t length) {
+void AddressTrackerLinux::HandleMessage(const char* buffer,
+ size_t length,
+ bool* address_changed,
+ bool* link_changed) {
DCHECK(buffer);
- bool changed = false;
for (const struct nlmsghdr* header =
reinterpret_cast<const struct nlmsghdr*>(buffer);
NLMSG_OK(header, length);
header = NLMSG_NEXT(header, length)) {
switch (header->nlmsg_type) {
case NLMSG_DONE:
- return changed;
- case NLMSG_ERROR:
- LOG(ERROR) << "Unexpected netlink error.";
- return changed;
+ return;
+ case NLMSG_ERROR: {
+ const struct nlmsgerr* msg =
+ reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(header));
+ LOG(ERROR) << "Unexpected netlink error " << msg->error << ".";
+ } return;
case RTM_NEWADDR: {
IPAddressNumber address;
if (GetAddress(header, &address)) {
- base::AutoLock lock(lock_);
+ base::AutoLock lock(address_map_lock_);
const struct ifaddrmsg* msg =
reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header));
// Only indicate change if the address is new or ifaddrmsg info has
// changed.
- AddressMap::iterator it = map_.find(address);
- if (it == map_.end()) {
- map_.insert(it, std::make_pair(address, *msg));
- changed = true;
+ AddressMap::iterator it = address_map_.find(address);
+ if (it == address_map_.end()) {
+ address_map_.insert(it, std::make_pair(address, *msg));
+ *address_changed = true;
} else if (memcmp(&it->second, msg, sizeof(*msg))) {
it->second = *msg;
- changed = true;
+ *address_changed = true;
}
}
} break;
case RTM_DELADDR: {
IPAddressNumber address;
if (GetAddress(header, &address)) {
- base::AutoLock lock(lock_);
- if (map_.erase(address))
- changed = true;
+ base::AutoLock lock(address_map_lock_);
+ if (address_map_.erase(address))
+ *address_changed = true;
+ }
+ } break;
+ case RTM_NEWLINK: {
+ const struct ifinfomsg* msg =
+ reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header));
+ if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) &&
+ (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) {
+ if (online_links_.insert(msg->ifi_index).second)
+ *link_changed = true;
+ } else {
+ if (online_links_.erase(msg->ifi_index))
+ *link_changed = true;
}
} break;
+ case RTM_DELLINK: {
+ const struct ifinfomsg* msg =
+ reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header));
+ if (online_links_.erase(msg->ifi_index))
+ *link_changed = true;
+ } break;
default:
break;
}
}
- return changed;
}
void AddressTrackerLinux::OnFileCanReadWithoutBlocking(int fd) {
DCHECK_EQ(netlink_fd_, fd);
- if (ReadMessages())
- callback_.Run();
+ bool address_changed;
+ bool link_changed;
+ ReadMessages(&address_changed, &link_changed);
+ if (address_changed)
+ address_callback_.Run();
+ if (link_changed)
+ link_callback_.Run();
}
void AddressTrackerLinux::OnFileCanWriteWithoutBlocking(int /* fd */) {}
+void AddressTrackerLinux::CloseSocket() {
+ if (netlink_fd_ >= 0 && HANDLE_EINTR(close(netlink_fd_)) < 0)
+ PLOG(ERROR) << "Could not close NETLINK socket.";
+ netlink_fd_ = -1;
+}
+
} // namespace internal
} // namespace net
diff --git a/net/base/address_tracker_linux.h b/net/base/address_tracker_linux.h
index a70a14c..87ce139 100644
--- a/net/base/address_tracker_linux.h
+++ b/net/base/address_tracker_linux.h
@@ -16,9 +16,12 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
#include "base/message_loop.h"
+#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "net/base/net_util.h"
+#include "net/base/network_change_notifier.h"
namespace net {
namespace internal {
@@ -30,8 +33,10 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux
public:
typedef std::map<IPAddressNumber, struct ifaddrmsg> AddressMap;
- // Will run |callback| when the AddressMap changes.
- explicit AddressTrackerLinux(const base::Closure& callback);
+ // Will run |address_callback| when the AddressMap changes and will run
+ // |link_callback| when the list of online links changes.
+ AddressTrackerLinux(const base::Closure& address_callback,
+ const base::Closure& link_callback);
virtual ~AddressTrackerLinux();
// Starts watching system configuration for changes. The current thread must
@@ -40,26 +45,52 @@ class NET_EXPORT_PRIVATE AddressTrackerLinux
AddressMap GetAddressMap() const;
+ // Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
+ // Safe to call from any thread, but will block until Init() has completed.
+ NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();
+
private:
friend class AddressTrackerLinuxTest;
- // Returns true if |map_| changed while reading messages from |netlink_fd_|.
- bool ReadMessages();
+ // Sets |*address_changed| to indicate whether |address_map_| changed and
+ // sets |*link_changed| to indicate if |online_links_| changed while reading
+ // messages from |netlink_fd_|.
+ void ReadMessages(bool* address_changed, bool* link_changed);
+
+ // Sets |*address_changed| to true if |address_map_| changed, sets
+ // |*link_changed| to true if |online_links_| changed while reading the
+ // message from |buffer|.
+ void HandleMessage(const char* buffer,
+ size_t length,
+ bool* address_changed,
+ bool* link_changed);
- // Returns true if |map_| changed while reading the message from |buffer|.
- bool HandleMessage(const char* buffer, size_t length);
+ // Call when some part of initialization failed; forces online and unblocks.
+ void AbortAndForceOnline();
// MessageLoopForIO::Watcher:
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE;
- base::Closure callback_;
+ // Close |netlink_fd_|
+ void CloseSocket();
+
+ base::Closure address_callback_;
+ base::Closure link_callback_;
int netlink_fd_;
MessageLoopForIO::FileDescriptorWatcher watcher_;
- mutable base::Lock lock_;
- AddressMap map_;
+ mutable base::Lock address_map_lock_;
+ AddressMap address_map_;
+
+ // Set of interface indices for links that are currently online.
+ base::hash_set<int> online_links_;
+
+ base::Lock is_offline_lock_;
+ bool is_offline_;
+ bool is_offline_initialized_;
+ base::ConditionVariable is_offline_initialized_cv_;
};
} // namespace internal
diff --git a/net/base/address_tracker_linux_unittest.cc b/net/base/address_tracker_linux_unittest.cc
index c366f5a..a9feed4 100644
--- a/net/base/address_tracker_linux_unittest.cc
+++ b/net/base/address_tracker_linux_unittest.cc
@@ -4,6 +4,8 @@
#include "net/base/address_tracker_linux.h"
+#include <linux/if.h>
+
#include <vector>
#include "base/bind.h"
@@ -12,27 +14,45 @@
namespace net {
namespace internal {
+typedef std::vector<char> Buffer;
+
void Noop() {}
class AddressTrackerLinuxTest : public testing::Test {
protected:
- AddressTrackerLinuxTest() : tracker_(base::Bind(&Noop)) {}
+ AddressTrackerLinuxTest() : tracker_(base::Bind(&Noop), base::Bind(&Noop)) {}
+
+ bool HandleAddressMessage(const Buffer& buf) {
+ bool address_changed = false;
+ bool link_changed = false;
+ tracker_.HandleMessage(&buf[0], buf.size(),
+ &address_changed, &link_changed);
+ EXPECT_FALSE(link_changed);
+ return address_changed;
+ }
- bool HandleMessage(char* buf, size_t length) {
- return tracker_.HandleMessage(buf, length);
+ bool HandleLinkMessage(const Buffer& buf) {
+ bool address_changed = false;
+ bool link_changed = false;
+ tracker_.HandleMessage(&buf[0], buf.size(),
+ &address_changed, &link_changed);
+ EXPECT_FALSE(address_changed);
+ return link_changed;
}
AddressTrackerLinux::AddressMap GetAddressMap() {
return tracker_.GetAddressMap();
}
+ const base::hash_set<int>* GetOnlineLinks() const {
+ return &tracker_.online_links_;
+ }
+
AddressTrackerLinux tracker_;
};
namespace {
-typedef std::vector<char> Buffer;
-
class NetlinkMessage {
public:
explicit NetlinkMessage(uint16 type) : buffer_(NLMSG_HDRLEN) {
@@ -83,12 +103,12 @@ class NetlinkMessage {
Buffer buffer_;
};
-void MakeMessage(uint16 type,
- uint8 flags,
- uint8 family,
- const IPAddressNumber& address,
- const IPAddressNumber& local,
- Buffer* output) {
+void MakeAddrMessage(uint16 type,
+ uint8 flags,
+ uint8 family,
+ const IPAddressNumber& address,
+ const IPAddressNumber& local,
+ Buffer* output) {
NetlinkMessage nlmsg(type);
struct ifaddrmsg msg = {};
msg.ifa_family = family;
@@ -101,6 +121,16 @@ void MakeMessage(uint16 type,
nlmsg.AppendTo(output);
}
+void MakeLinkMessage(uint16 type, uint32 flags, uint32 index, Buffer* output) {
+ NetlinkMessage nlmsg(type);
+ struct ifinfomsg msg = {};
+ msg.ifi_index = index;
+ msg.ifi_flags = flags;
+ nlmsg.AddPayload(&msg, sizeof(msg));
+ output->clear();
+ nlmsg.AppendTo(output);
+}
+
const unsigned char kAddress0[] = { 127, 0, 0, 1 };
const unsigned char kAddress1[] = { 10, 0, 0, 1 };
const unsigned char kAddress2[] = { 192, 168, 0, 1 };
@@ -117,28 +147,30 @@ TEST_F(AddressTrackerLinuxTest, NewAddress) {
const IPAddressNumber kAddr3(kAddress3, kAddress3 + arraysize(kAddress3));
Buffer buffer;
- MakeMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
- EXPECT_TRUE(map.find(kAddr0) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
buffer.clear();
- MakeMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr1, kAddr2, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr1, kAddr2,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(2u, map.size());
- EXPECT_TRUE(map.find(kAddr0) != map.end());
- EXPECT_TRUE(map.find(kAddr2) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr0));
+ EXPECT_EQ(1u, map.count(kAddr2));
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr2].ifa_flags);
buffer.clear();
- MakeMessage(RTM_NEWADDR, 0, AF_INET6, kEmpty, kAddr3, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_INET6, kEmpty, kAddr3, &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(3u, map.size());
- EXPECT_TRUE(map.find(kAddr3) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr3));
}
TEST_F(AddressTrackerLinuxTest, NewAddressChange) {
@@ -146,26 +178,30 @@ TEST_F(AddressTrackerLinuxTest, NewAddressChange) {
const IPAddressNumber kAddr0(kAddress0, kAddress0 + arraysize(kAddress0));
Buffer buffer;
- MakeMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
- EXPECT_TRUE(map.find(kAddr0) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
buffer.clear();
- MakeMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr0, kEmpty, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr0, kEmpty,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
- EXPECT_TRUE(map.find(kAddr0) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr0].ifa_flags);
// Both messages in one buffer.
buffer.clear();
- MakeMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty, &buffer);
- MakeMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr0, kEmpty, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kEmpty,
+ &buffer);
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kAddr0, kEmpty,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr0].ifa_flags);
@@ -175,14 +211,15 @@ TEST_F(AddressTrackerLinuxTest, NewAddressDuplicate) {
const IPAddressNumber kAddr0(kAddress0, kAddress0 + arraysize(kAddress0));
Buffer buffer;
- MakeMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kAddr0, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kAddr0, kAddr0,
+ &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
- EXPECT_TRUE(map.find(kAddr0) != map.end());
+ EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
- EXPECT_FALSE(HandleMessage(&buffer[0], buffer.size()));
+ EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
@@ -195,30 +232,30 @@ TEST_F(AddressTrackerLinuxTest, DeleteAddress) {
const IPAddressNumber kAddr2(kAddress2, kAddress2 + arraysize(kAddress2));
Buffer buffer;
- MakeMessage(RTM_NEWADDR, 0, AF_INET, kAddr0, kEmpty, &buffer);
- MakeMessage(RTM_NEWADDR, 0, AF_INET, kAddr1, kAddr2, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kAddr0, kEmpty, &buffer);
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kAddr1, kAddr2, &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(2u, map.size());
buffer.clear();
- MakeMessage(RTM_DELADDR, 0, AF_INET, kEmpty, kAddr0, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kEmpty, kAddr0, &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
- EXPECT_TRUE(map.find(kAddr0) == map.end());
- EXPECT_TRUE(map.find(kAddr2) != map.end());
+ EXPECT_EQ(0u, map.count(kAddr0));
+ EXPECT_EQ(1u, map.count(kAddr2));
buffer.clear();
- MakeMessage(RTM_DELADDR, 0, AF_INET, kAddr2, kAddr1, &buffer);
+ MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kAddr2, kAddr1, &buffer);
// kAddr1 does not exist in the map.
- EXPECT_FALSE(HandleMessage(&buffer[0], buffer.size()));
+ EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
buffer.clear();
- MakeMessage(RTM_DELADDR, 0, AF_INET, kAddr2, kEmpty, &buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kAddr2, kEmpty, &buffer);
+ EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(0u, map.size());
}
@@ -230,13 +267,13 @@ TEST_F(AddressTrackerLinuxTest, IgnoredMessage) {
Buffer buffer;
// Ignored family.
- MakeMessage(RTM_NEWADDR, 0, AF_UNSPEC, kAddr3, kAddr0, &buffer);
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_UNSPEC, kAddr3, kAddr0, &buffer);
// No address.
- MakeMessage(RTM_NEWADDR, 0, AF_INET, kEmpty, kEmpty, &buffer);
+ MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kEmpty, kEmpty, &buffer);
// Ignored type.
- MakeMessage(RTM_DELROUTE, 0, AF_INET6, kAddr3, kEmpty, &buffer);
- EXPECT_FALSE(HandleMessage(&buffer[0], buffer.size()));
- EXPECT_EQ(0u, GetAddressMap().size());
+ MakeAddrMessage(RTM_DELROUTE, 0, AF_INET6, kAddr3, kEmpty, &buffer);
+ EXPECT_FALSE(HandleAddressMessage(buffer));
+ EXPECT_TRUE(GetAddressMap().empty());
// Valid message after ignored messages.
NetlinkMessage nlmsg(RTM_NEWADDR);
@@ -249,10 +286,80 @@ TEST_F(AddressTrackerLinuxTest, IgnoredMessage) {
nlmsg.AddAttribute(IFA_ADDRESS, &kAddr0[0], kAddr0.size());
nlmsg.AppendTo(&buffer);
- EXPECT_TRUE(HandleMessage(&buffer[0], buffer.size()));
+ EXPECT_TRUE(HandleAddressMessage(buffer));
EXPECT_EQ(1u, GetAddressMap().size());
}
+TEST_F(AddressTrackerLinuxTest, AddInterface) {
+ Buffer buffer;
+
+ // Ignores loopback.
+ MakeLinkMessage(RTM_NEWLINK,
+ IFF_LOOPBACK | IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
+ 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Ignores not IFF_LOWER_UP.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Ignores deletion.
+ MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Verify success.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_EQ(1u, GetOnlineLinks()->count(0));
+ EXPECT_EQ(1u, GetOnlineLinks()->size());
+
+ // Ignores redundant enables.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_EQ(1u, GetOnlineLinks()->count(0));
+ EXPECT_EQ(1u, GetOnlineLinks()->size());
+
+ // Verify adding another online device (e.g. VPN) is considered a change.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 1, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_EQ(1u, GetOnlineLinks()->count(0));
+ EXPECT_EQ(1u, GetOnlineLinks()->count(1));
+ EXPECT_EQ(2u, GetOnlineLinks()->size());
+}
+
+TEST_F(AddressTrackerLinuxTest, RemoveInterface) {
+ Buffer buffer;
+
+ // Should disappear when not IFF_LOWER_UP.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_FALSE(GetOnlineLinks()->empty());
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Ignores redundant disables.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Ignores deleting down interfaces.
+ MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_FALSE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+
+ // Should disappear when deleted.
+ MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_FALSE(GetOnlineLinks()->empty());
+ MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 0, &buffer);
+ EXPECT_TRUE(HandleLinkMessage(buffer));
+ EXPECT_TRUE(GetOnlineLinks()->empty());
+}
+
} // namespace
} // namespace internal
diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc
index a3753a9..fc2b372 100644
--- a/net/base/network_change_notifier_linux.cc
+++ b/net/base/network_change_notifier_linux.cc
@@ -1,252 +1,26 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//
-// This implementation of NetworkChangeNotifier's offline state detection
-// depends on D-Bus and NetworkManager, and is known to work on at least
-// GNOME version 2.30. If D-Bus or NetworkManager are unavailable, this
-// implementation will always behave as if it is online.
#include "net/base/network_change_notifier_linux.h"
-#include <resolv.h>
-
#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
#include "base/compiler_specific.h"
-#include "base/memory/weak_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "dbus/object_proxy.h"
#include "net/base/address_tracker_linux.h"
-#include "net/base/net_errors.h"
#include "net/dns/dns_config_service.h"
namespace net {
-namespace {
-
-const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager";
-const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager";
-const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager";
-
-// http://projects.gnome.org/NetworkManager/developers/spec-08.html#type-NM_STATE
-enum {
- NM_LEGACY_STATE_UNKNOWN = 0,
- NM_LEGACY_STATE_ASLEEP = 1,
- NM_LEGACY_STATE_CONNECTING = 2,
- NM_LEGACY_STATE_CONNECTED = 3,
- NM_LEGACY_STATE_DISCONNECTED = 4
-};
-
-// http://projects.gnome.org/NetworkManager/developers/migrating-to-09/spec.html#type-NM_STATE
-enum {
- NM_STATE_UNKNOWN = 0,
- NM_STATE_ASLEEP = 10,
- NM_STATE_DISCONNECTED = 20,
- NM_STATE_DISCONNECTING = 30,
- NM_STATE_CONNECTING = 40,
- NM_STATE_CONNECTED_LOCAL = 50,
- NM_STATE_CONNECTED_SITE = 60,
- NM_STATE_CONNECTED_GLOBAL = 70
-};
-
-} // namespace
-
-// A wrapper around NetworkManager's D-Bus API.
-class NetworkManagerApi {
- public:
- NetworkManagerApi(const base::Closure& notification_callback, dbus::Bus* bus)
- : is_offline_(false),
- offline_state_initialized_(true /*manual_reset*/, false),
- notification_callback_(notification_callback),
- helper_thread_id_(base::kInvalidThreadId),
- ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)),
- system_bus_(bus) { }
-
- ~NetworkManagerApi() { }
-
- // Should be called on a helper thread which must be of type IO.
- void Init();
-
- // Must be called by the helper thread's CleanUp() method.
- void CleanUp();
-
- // Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
- // Safe to call from any thread, but will block until Init() has completed.
- NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();
-
- private:
- // Callbacks for D-Bus API.
- void OnInitialResponse(dbus::Response* response) {
- HandleResponse(response);
- offline_state_initialized_.Signal();
- }
-
- void OnSignaled(dbus::Signal* signal);
-
- void OnConnected(const std::string&, const std::string&, bool success) {
- if (!success) {
- DLOG(WARNING) << "Failed to set up offline state detection";
- offline_state_initialized_.Signal();
- }
- }
-
- // Helper for OnInitialResponse.
- void HandleResponse(dbus::Response* response);
-
- // Converts a NetworkManager state uint to a bool.
- static bool StateIsOffline(uint32 state);
-
- bool is_offline_;
- base::Lock is_offline_lock_;
- base::WaitableEvent offline_state_initialized_;
-
- base::Closure notification_callback_;
-
- base::PlatformThreadId helper_thread_id_;
-
- base::WeakPtrFactory<NetworkManagerApi> ptr_factory_;
-
- scoped_refptr<dbus::Bus> system_bus_;
-
- DISALLOW_COPY_AND_ASSIGN(NetworkManagerApi);
-};
-
-void NetworkManagerApi::Init() {
- // D-Bus requires an IO MessageLoop.
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_IO);
- helper_thread_id_ = base::PlatformThread::CurrentId();
-
- if (!system_bus_) {
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SYSTEM;
- options.connection_type = dbus::Bus::PRIVATE;
- system_bus_ = new dbus::Bus(options);
- }
-
- // Ignore ServiceUnknown errors to avoid log spam: http://crbug.com/109696.
- dbus::ObjectProxy* proxy = system_bus_->GetObjectProxyWithOptions(
- kNetworkManagerServiceName, dbus::ObjectPath(kNetworkManagerPath),
- dbus::ObjectProxy::IGNORE_SERVICE_UNKNOWN_ERRORS);
-
- // Get the initial state asynchronously.
- dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get");
- dbus::MessageWriter builder(&method_call);
- builder.AppendString(kNetworkManagerInterface);
- builder.AppendString("State");
- proxy->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&NetworkManagerApi::OnInitialResponse,
- ptr_factory_.GetWeakPtr()));
-
- // And sign up for notifications.
- proxy->ConnectToSignal(
- kNetworkManagerInterface,
- "StateChanged",
- base::Bind(&NetworkManagerApi::OnSignaled, ptr_factory_.GetWeakPtr()),
- base::Bind(&NetworkManagerApi::OnConnected, ptr_factory_.GetWeakPtr()));
-}
-
-void NetworkManagerApi::CleanUp() {
- DCHECK_EQ(helper_thread_id_, base::PlatformThread::CurrentId());
- ptr_factory_.InvalidateWeakPtrs();
-}
-
-void NetworkManagerApi::HandleResponse(dbus::Response* response) {
- DCHECK_EQ(helper_thread_id_, base::PlatformThread::CurrentId());
- if (!response) {
- DVLOG(1) << "No response received for initial state request";
- return;
- }
- dbus::MessageReader reader(response);
- uint32 state = 0;
- if (!reader.PopVariantOfUint32(&state)) {
- DLOG(WARNING) << "Unexpected response for NetworkManager State request: "
- << response->ToString();
- return;
- }
- {
- base::AutoLock lock(is_offline_lock_);
- is_offline_ = StateIsOffline(state);
- }
-}
-
-void NetworkManagerApi::OnSignaled(dbus::Signal* signal) {
- DCHECK_EQ(helper_thread_id_, base::PlatformThread::CurrentId());
- dbus::MessageReader reader(signal);
- uint32 state = 0;
- if (!reader.PopUint32(&state)) {
- DLOG(WARNING) << "Unexpected signal for NetworkManager StateChanged: "
- << signal->ToString();
- return;
- }
- bool new_is_offline = StateIsOffline(state);
- {
- base::AutoLock lock(is_offline_lock_);
- if (is_offline_ != new_is_offline)
- is_offline_ = new_is_offline;
- else
- return;
- }
- notification_callback_.Run();
-}
-
-bool NetworkManagerApi::StateIsOffline(uint32 state) {
- switch (state) {
- case NM_LEGACY_STATE_CONNECTED:
- case NM_STATE_CONNECTED_SITE:
- case NM_STATE_CONNECTED_GLOBAL:
- // Definitely connected
- return false;
- case NM_LEGACY_STATE_DISCONNECTED:
- case NM_STATE_DISCONNECTED:
- // Definitely disconnected
- return true;
- case NM_STATE_CONNECTED_LOCAL:
- // Local networking only; I'm treating this as offline (keybuk)
- return true;
- case NM_LEGACY_STATE_CONNECTING:
- case NM_STATE_DISCONNECTING:
- case NM_STATE_CONNECTING:
- // In-flight change to connection status currently underway
- return true;
- case NM_LEGACY_STATE_ASLEEP:
- case NM_STATE_ASLEEP:
- // Networking disabled or no devices on system
- return true;
- default:
- // Unknown status
- return false;
- }
-}
-
-NetworkChangeNotifier::ConnectionType
-NetworkManagerApi::GetCurrentConnectionType() {
- // http://crbug.com/125097
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- offline_state_initialized_.Wait();
- base::AutoLock lock(is_offline_lock_);
- // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN.
- return is_offline_ ? NetworkChangeNotifier::CONNECTION_NONE :
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
-}
-
class NetworkChangeNotifierLinux::Thread : public base::Thread {
public:
- explicit Thread(dbus::Bus* bus);
+ Thread();
virtual ~Thread();
// Plumbing for NetworkChangeNotifier::GetCurrentConnectionType.
// Safe to call from any thread.
NetworkChangeNotifier::ConnectionType GetCurrentConnectionType() {
- return network_manager_api_.GetCurrentConnectionType();
+ return address_tracker_.GetCurrentConnectionType();
}
const internal::AddressTrackerLinux* address_tracker() const {
@@ -259,24 +33,20 @@ class NetworkChangeNotifierLinux::Thread : public base::Thread {
virtual void CleanUp() OVERRIDE;
private:
- // Used to detect online/offline state changes.
- NetworkManagerApi network_manager_api_;
-
scoped_ptr<DnsConfigService> dns_config_service_;
+ // Used to detect online/offline state and IP address changes.
internal::AddressTrackerLinux address_tracker_;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
-NetworkChangeNotifierLinux::Thread::Thread(dbus::Bus* bus)
+NetworkChangeNotifierLinux::Thread::Thread()
: base::Thread("NetworkChangeNotifier"),
- network_manager_api_(
- base::Bind(&NetworkChangeNotifier::
- NotifyObserversOfConnectionTypeChange),
- bus),
address_tracker_(
base::Bind(&NetworkChangeNotifier::
- NotifyObserversOfIPAddressChange)) {
+ NotifyObserversOfIPAddressChange),
+ base::Bind(&NetworkChangeNotifier::
+ NotifyObserversOfConnectionTypeChange)) {
}
NetworkChangeNotifierLinux::Thread::~Thread() {
@@ -284,7 +54,6 @@ NetworkChangeNotifierLinux::Thread::~Thread() {
}
void NetworkChangeNotifierLinux::Thread::Init() {
- network_manager_api_.Init();
address_tracker_.Init();
dns_config_service_ = DnsConfigService::CreateSystemService();
dns_config_service_->WatchConfig(
@@ -292,21 +61,15 @@ void NetworkChangeNotifierLinux::Thread::Init() {
}
void NetworkChangeNotifierLinux::Thread::CleanUp() {
- network_manager_api_.CleanUp();
dns_config_service_.reset();
}
NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::Create() {
- return new NetworkChangeNotifierLinux(NULL);
-}
-
-NetworkChangeNotifierLinux* NetworkChangeNotifierLinux::CreateForTest(
- dbus::Bus* bus) {
- return new NetworkChangeNotifierLinux(bus);
+ return new NetworkChangeNotifierLinux();
}
-NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(dbus::Bus* bus)
- : notifier_thread_(new Thread(bus)) {
+NetworkChangeNotifierLinux::NetworkChangeNotifierLinux()
+ : notifier_thread_(new Thread()) {
// We create this notifier thread because the notification implementation
// needs a MessageLoopForIO, and there's no guarantee that
// MessageLoop::current() meets that criterion.
diff --git a/net/base/network_change_notifier_linux.h b/net/base/network_change_notifier_linux.h
index 1b3f376..6e10854 100644
--- a/net/base/network_change_notifier_linux.h
+++ b/net/base/network_change_notifier_linux.h
@@ -11,10 +11,6 @@
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
-namespace dbus {
-class Bus;
-}
-
namespace net {
class NET_EXPORT_PRIVATE NetworkChangeNotifierLinux
@@ -22,13 +18,10 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierLinux
public:
static NetworkChangeNotifierLinux* Create();
- // Unittests inject a mock bus.
- static NetworkChangeNotifierLinux* CreateForTest(dbus::Bus* bus);
-
private:
class Thread;
- explicit NetworkChangeNotifierLinux(dbus::Bus* bus);
+ NetworkChangeNotifierLinux();
virtual ~NetworkChangeNotifierLinux();
// NetworkChangeNotifier:
diff --git a/net/base/network_change_notifier_linux_unittest.cc b/net/base/network_change_notifier_linux_unittest.cc
deleted file mode 100644
index 8fc9631..0000000
--- a/net/base/network_change_notifier_linux_unittest.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/base/network_change_notifier_linux.h"
-
-#include "base/bind.h"
-#include "base/message_loop_proxy.h"
-#include "base/synchronization/waitable_event.h"
-#include "dbus/mock_bus.h"
-#include "dbus/mock_object_proxy.h"
-#include "dbus/message.h"
-#include "dbus/object_path.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-using testing::_;
-using testing::DoAll;
-using testing::InvokeWithoutArgs;
-using testing::Return;
-using testing::SaveArg;
-
-class NetworkChangeNotifierLinuxTest : public testing::Test {
- protected:
- // A subset of the NetworkManager-defined constants used in
- // the tests below. See network_change_notifier_linux.cc
- // for the full list.
- enum {
- NM_STATE_DISCONNECTED = 20,
- NM_STATE_DISCONNECTING = 30,
- NM_STATE_CONNECTED_SITE = 70,
- NM_STATE_CONNECTED_GLOBAL = 70
- };
-
- NetworkChangeNotifierLinuxTest()
- : initialized_(false, false) {}
-
- virtual void SetUp() {
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SYSTEM;
- mock_bus_ = new dbus::MockBus(options);
-
- mock_object_proxy_ = new dbus::MockObjectProxy(
- mock_bus_.get(),
- "service_name",
- dbus::ObjectPath("service_path"));
- EXPECT_CALL(*mock_bus_, GetObjectProxyWithOptions(_, _, _))
- .WillOnce(Return(mock_object_proxy_.get()));
-
- EXPECT_CALL(*mock_object_proxy_, CallMethod(_, _, _))
- .WillOnce(SaveArg<2>(&response_callback_));
- EXPECT_CALL(*mock_object_proxy_, ConnectToSignal(_, _, _, _))
- .WillOnce(
- DoAll(
- SaveArg<2>(&signal_callback_),
- InvokeWithoutArgs(
- this,
- &NetworkChangeNotifierLinuxTest::Initialize)));
-
- notifier_.reset(NetworkChangeNotifierLinux::CreateForTest(mock_bus_.get()));
-
- initialized_.Wait();
- }
-
- void Initialize() {
- notifier_thread_proxy_ = base::MessageLoopProxy::current();
- initialized_.Signal();
- }
-
- void RunOnNotifierThread(const base::Closure& callback) {
- base::WaitableEvent event(false, false);
- notifier_thread_proxy_->PostTask(FROM_HERE, base::Bind(
- &RunOnNotifierThreadHelper, callback, &event));
- event.Wait();
- // Run any tasks queued on the main thread, e.g. by
- // ObserverListThreadSafe.
- MessageLoop::current()->RunUntilIdle();
- }
-
- void SendResponse(uint32 state) {
- scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
- dbus::MessageWriter writer(response.get());
- writer.AppendVariantOfUint32(state);
- RunOnNotifierThread(base::Bind(response_callback_, response.get()));
- }
-
- void SendSignal(uint32 state) {
- dbus::Signal signal("org.freedesktop.NetworkManager", "StateChanged");
- dbus::MessageWriter writer(&signal);
- writer.AppendUint32(state);
- RunOnNotifierThread(base::Bind(signal_callback_, &signal));
- }
-
- dbus::ObjectProxy::ResponseCallback response_callback_;
- dbus::ObjectProxy::SignalCallback signal_callback_;
-
- // Allows creating a new NetworkChangeNotifier. Must be created before
- // |notifier_| and destroyed after it to avoid DCHECK failures.
- NetworkChangeNotifier::DisableForTest disable_for_test_;
- scoped_ptr<NetworkChangeNotifier> notifier_;
-
- private:
- static void RunOnNotifierThreadHelper(const base::Closure& callback,
- base::WaitableEvent* event) {
- callback.Run();
- event->Signal();
- }
-
- base::WaitableEvent initialized_;
-
- // Valid only after initialized_ is signaled.
- scoped_refptr<base::MessageLoopProxy> notifier_thread_proxy_;
-
- scoped_refptr<dbus::MockBus> mock_bus_;
- scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
-};
-
-namespace {
-
-class OfflineObserver : public NetworkChangeNotifier::ConnectionTypeObserver {
- public:
- OfflineObserver()
- : notification_count(0),
- last_online_value(true) {
- NetworkChangeNotifier::AddConnectionTypeObserver(this);
- }
-
- ~OfflineObserver() {
- NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
- }
-
- virtual void OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType type) OVERRIDE {
- notification_count++;
- last_online_value = type != NetworkChangeNotifier::CONNECTION_NONE;
- }
-
- int notification_count;
- bool last_online_value;
-};
-
-TEST_F(NetworkChangeNotifierLinuxTest, Offline) {
- SendResponse(NM_STATE_DISCONNECTED);
- EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, Online) {
- SendResponse(NM_STATE_CONNECTED_GLOBAL);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());}
-
-TEST_F(NetworkChangeNotifierLinuxTest, OfflineThenOnline) {
- OfflineObserver observer;
-
- SendResponse(NM_STATE_DISCONNECTED);
- EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-
- SendSignal(NM_STATE_CONNECTED_GLOBAL);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(1, observer.notification_count);
- EXPECT_TRUE(observer.last_online_value);
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, MultipleStateChanges) {
- OfflineObserver observer;
-
- SendResponse(NM_STATE_CONNECTED_GLOBAL);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-
- SendSignal(NM_STATE_DISCONNECTED);
- EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(1, observer.notification_count);
- EXPECT_FALSE(observer.last_online_value);
-
- SendSignal(NM_STATE_CONNECTED_GLOBAL);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(2, observer.notification_count);
- EXPECT_TRUE(observer.last_online_value);
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, IgnoreContinuedOnlineState) {
- OfflineObserver observer;
-
- SendResponse(NM_STATE_CONNECTED_SITE);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-
- SendSignal(NM_STATE_CONNECTED_GLOBAL);
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, IgnoreContinuedOfflineState) {
- OfflineObserver observer;
-
- SendResponse(NM_STATE_DISCONNECTING);
- EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-
- SendSignal(NM_STATE_DISCONNECTED);
- EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
- EXPECT_EQ(0, observer.notification_count);
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, NullResponse) {
- RunOnNotifierThread(base::Bind(
- response_callback_, static_cast<dbus::Response*>(NULL)));
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, EmptyResponse) {
- scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
- RunOnNotifierThread(base::Bind(response_callback_, response.get()));
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
-}
-
-TEST_F(NetworkChangeNotifierLinuxTest, InvalidResponse) {
- scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
- dbus::MessageWriter writer(response.get());
- writer.AppendUint16(20); // Uint16 instead of the expected Uint32
- RunOnNotifierThread(base::Bind(response_callback_, response.get()));
- EXPECT_NE(NetworkChangeNotifier::CONNECTION_NONE,
- NetworkChangeNotifier::GetConnectionType());
-}
-
-} // namespace
-} // namespace net