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
3// found in the LICENSE file.
4
5#ifndef NET_BASE_ADDRESS_TRACKER_LINUX_H_
6#define NET_BASE_ADDRESS_TRACKER_LINUX_H_
7
8#include <sys/socket.h>  // Needed to include netlink.
9// Mask superfluous definition of |struct net|. This is fixed in Linux 2.6.38.
10#define net net_kernel
11#include <linux/rtnetlink.h>
12#undef net
13
14#include <map>
15
16#include "base/basictypes.h"
17#include "base/callback.h"
18#include "base/compiler_specific.h"
19#include "base/containers/hash_tables.h"
20#include "base/message_loop/message_loop.h"
21#include "base/synchronization/condition_variable.h"
22#include "base/synchronization/lock.h"
23#include "base/threading/thread_checker.h"
24#include "net/base/net_util.h"
25#include "net/base/network_change_notifier.h"
26
27namespace net {
28namespace internal {
29
30// Keeps track of network interface addresses using rtnetlink. Used by
31// NetworkChangeNotifier to provide signals to registered IPAddressObservers.
32class NET_EXPORT_PRIVATE AddressTrackerLinux :
33    public base::MessageLoopForIO::Watcher {
34 public:
35  typedef std::map<IPAddressNumber, struct ifaddrmsg> AddressMap;
36
37  // Non-tracking version constructor: it takes a snapshot of the
38  // current system configuration. Once Init() returns, the
39  // configuration is available through GetOnlineLinks() and
40  // GetAddressMap().
41  AddressTrackerLinux();
42
43  // Tracking version constructor: it will run |address_callback| when
44  // the AddressMap changes, |link_callback| when the list of online
45  // links changes, and |tunnel_callback| when the list of online
46  // tunnels changes.
47  AddressTrackerLinux(const base::Closure& address_callback,
48                      const base::Closure& link_callback,
49                      const base::Closure& tunnel_callback);
50  virtual ~AddressTrackerLinux();
51
52  // In tracking mode, it starts watching the system configuration for
53  // changes. The current thread must have a MessageLoopForIO. In
54  // non-tracking mode, once Init() returns, a snapshot of the system
55  // configuration is available through GetOnlineLinks() and
56  // GetAddressMap().
57  void Init();
58
59  AddressMap GetAddressMap() const;
60
61  // Returns set of interface indicies for online interfaces.
62  base::hash_set<int> GetOnlineLinks() const;
63
64  // Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
65  // Safe to call from any thread, but will block until Init() has completed.
66  NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();
67
68 private:
69  friend class AddressTrackerLinuxTest;
70
71  // In tracking mode, holds |lock| while alive. In non-tracking mode,
72  // enforces single-threaded access.
73  class AddressTrackerAutoLock {
74   public:
75    AddressTrackerAutoLock(const AddressTrackerLinux& tracker,
76                           base::Lock& lock);
77    ~AddressTrackerAutoLock();
78
79   private:
80    const AddressTrackerLinux& tracker_;
81    base::Lock& lock_;
82    DISALLOW_COPY_AND_ASSIGN(AddressTrackerAutoLock);
83  };
84
85  // A function that returns the name of an interface given the interface index
86  // in |interface_index|.
87  typedef const char* (*GetInterfaceNameFunction)(int interface_index);
88
89  // Sets |*address_changed| to indicate whether |address_map_| changed and
90  // sets |*link_changed| to indicate if |online_links_| changed and sets
91  // |*tunnel_changed| to indicate if |online_links_| changed with regards to a
92  // tunnel interface while reading messages from |netlink_fd_|.
93  void ReadMessages(bool* address_changed,
94                    bool* link_changed,
95                    bool* tunnel_changed);
96
97  // Sets |*address_changed| to true if |address_map_| changed, sets
98  // |*link_changed| to true if |online_links_| changed, sets |*tunnel_changed|
99  // to true if |online_links_| changed with regards to a tunnel interface while
100  // reading the message from |buffer|.
101  void HandleMessage(char* buffer,
102                     size_t length,
103                     bool* address_changed,
104                     bool* link_changed,
105                     bool* tunnel_changed);
106
107  // Call when some part of initialization failed; forces online and unblocks.
108  void AbortAndForceOnline();
109
110  // MessageLoopForIO::Watcher:
111  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
112  virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE;
113
114  // Close |netlink_fd_|
115  void CloseSocket();
116
117  // Does |msg| refer to a tunnel interface?
118  bool IsTunnelInterface(const struct ifinfomsg* msg) const;
119
120  // Gets the name of an interface given the interface index |interface_index|.
121  // May return empty string if it fails but should not return NULL. This is
122  // overridden by tests.
123  GetInterfaceNameFunction get_interface_name_;
124
125  base::Closure address_callback_;
126  base::Closure link_callback_;
127  base::Closure tunnel_callback_;
128
129  int netlink_fd_;
130  base::MessageLoopForIO::FileDescriptorWatcher watcher_;
131
132  mutable base::Lock address_map_lock_;
133  AddressMap address_map_;
134
135  // Set of interface indices for links that are currently online.
136  mutable base::Lock online_links_lock_;
137  base::hash_set<int> online_links_;
138
139  base::Lock is_offline_lock_;
140  bool is_offline_;
141  bool is_offline_initialized_;
142  base::ConditionVariable is_offline_initialized_cv_;
143  bool tracking_;
144
145  // Used to verify single-threaded access in non-tracking mode.
146  base::ThreadChecker thread_checker_;
147};
148
149}  // namespace internal
150}  // namespace net
151
152#endif  // NET_BASE_ADDRESS_TRACKER_LINUX_H_
153