summaryrefslogtreecommitdiff
path: root/src/components/transport_manager/include/transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h
blob: bb60b09a9d8b2546ee574bb097d4c93a05ad9f52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_
#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_

#include <map>
#include <string>
#include <vector>

#include <netinet/in.h>
#include "transport_manager/tcp/network_interface_listener.h"
#include "utils/macro.h"
#include "utils/threads/thread_delegate.h"

struct ifaddrmsg;

namespace transport_manager {
namespace transport_adapter {

class TcpClientListener;

/**
 * @brief Struct to keep network interface's status flags and IP addresses
 */
class InterfaceStatus {
 public:
  InterfaceStatus()
      : flags_(0)
      , has_ipv4_(false)
      , has_ipv6_(false)
      , ipv4_address_()
      , ipv6_address_() {}
  ~InterfaceStatus() {}

  bool IsAvailable() const;
  bool IsLoopback() const;
  // only for debugging output
  unsigned int GetFlags() const {
    return flags_;
  }

  bool HasIPAddress() const;
  std::string GetIPv4Address() const;
  std::string GetIPv6Address() const;

  void SetFlags(unsigned int flags) {
    flags_ = flags;
  }

  // specify NULL to remove existing address
  void SetIPv4Address(struct in_addr* addr);
  void SetIPv6Address(struct in6_addr* addr);

 private:
  unsigned int flags_;
  bool has_ipv4_;
  bool has_ipv6_;
  struct in_addr ipv4_address_;
  struct in6_addr ipv6_address_;
};

typedef std::map<std::string, InterfaceStatus> InterfaceStatusTable;

/**
 * @brief Listener to detect various events on network interfaces
 */
class PlatformSpecificNetworkInterfaceListener
    : public NetworkInterfaceListener {
 public:
  /**
   * @brief Constructor
   *
   * @param tcp_client_listener  an instance of TcpClientListener which receives
   *                             status updates
   * @param designated_interface  if we want to listen only on a specific
   *                              network interface, specify its name
   */
  PlatformSpecificNetworkInterfaceListener(
      TcpClientListener* tcp_client_listener,
      const std::string designated_interface = "");

  /**
   * @brief Destructor
   */
  virtual ~PlatformSpecificNetworkInterfaceListener();

  /**
   * @brief Initialize this listener
   */
  bool Init() OVERRIDE;

  /**
   * @brief Deinitialize this listener
   */
  void Deinit() OVERRIDE;

  /**
   * @brief Start this listener
   */
  bool Start() OVERRIDE;

  /**
   * @brief Stop this listener
   */
  bool Stop() OVERRIDE;

#ifdef BUILD_TESTS
  void SetTesting(bool enabled) {
    testing_ = enabled;
  }

  int GetSocket() const {
    return socket_;
  }

  threads::Thread* GetThread() const {
    return thread_;
  }

  void OverwriteStatusTable(const InterfaceStatusTable dummy_table) {
    status_table_ = dummy_table;
  }

  void testCallNotifyIPAddresses() {
    NotifyIPAddresses();
  }

  const std::string& GetSelectedInterfaceName() const {
    return selected_interface_;
  }
#endif  // BUILD_TESTS

 private:
  // Struct to hold an event on a network interface.
  // The event can be either an update on flags or an update on IP address.
  struct EventParam {
    unsigned int if_index;
    unsigned int flags;
    struct sockaddr_storage address;

    EventParam(int interface_index, unsigned int interface_flags = 0)
        : if_index(interface_index), flags(interface_flags), address() {}
  };

  // parent class which we will notify the events to
  TcpClientListener* tcp_client_listener_;
  // if configured, NetworkInterfaceListener will always look into the IP
  // addresses of this interface
  const std::string designated_interface_;

  // a map to store status of each interface
  InterfaceStatusTable status_table_;
  // this is the name of the interface we are currently focusing on
  std::string selected_interface_;
  // previous IP addresses that we have notified
  std::string notified_ipv4_addr_;
  std::string notified_ipv6_addr_;

  int socket_;
  int pipe_fds_[2];
  threads::Thread* thread_;

#ifdef BUILD_TESTS
  bool testing_;
#endif

  void Loop();
  bool StopLoop();

  // reset status_table_ by fetching current status of each interface
  bool InitializeStatus();
  // update status_table_ by applying the events
  bool UpdateStatus(uint16_t type, std::vector<EventParam>& params);
  // update notified_ipv4_addr_ and notified_ipv6_addr_ then notify the parent
  // class of the change if necessary
  void NotifyIPAddresses();
  // Select an appropriate network interface that we will get IP addresses. Also
  // update selected_interface_.
  const std::string SelectInterface();
  // convert ifaddrmsg to a list of EventParam structs
  std::vector<EventParam> ParseIFAddrMessage(struct ifaddrmsg* message,
                                             unsigned int size);
  // for debugging
  void DumpTable() const;

  class ListenerThreadDelegate : public threads::ThreadDelegate {
   public:
    explicit ListenerThreadDelegate(
        PlatformSpecificNetworkInterfaceListener* parent);
    virtual void threadMain();
    void exitThreadMain();

   private:
    PlatformSpecificNetworkInterfaceListener* parent_;
  };

  DISALLOW_COPY_AND_ASSIGN(PlatformSpecificNetworkInterfaceListener);
};

}  // namespace transport_adapter
}  // namespace transport_manager

#endif  // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_