1 // Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 
6 #ifndef VSOMEIP_V3_NETLINK_CONNECTOR_HPP_
7 #define VSOMEIP_V3_NETLINK_CONNECTOR_HPP_
8 
9 #ifndef _WIN32
10 
11 #include <sys/socket.h>
12 #include <linux/netlink.h>
13 #include <linux/rtnetlink.h>
14 
15 #include <map>
16 #include <mutex>
17 
18 #include <boost/asio/io_service.hpp>
19 #include <boost/asio/basic_raw_socket.hpp>
20 #include <boost/asio/ip/address.hpp>
21 
22 #include "../../endpoints/include/buffer.hpp"
23 
24 namespace vsomeip_v3 {
25 
26 template <typename Protocol>
27 class nl_endpoint {
28 public:
29     /// The protocol type associated with the endpoint.
30     typedef Protocol protocol_type;
31     typedef boost::asio::detail::socket_addr_type data_type;
32 
33     /// Default constructor.
nl_endpoint()34     nl_endpoint()
35     {
36         sockaddr.nl_family = PF_NETLINK;
37         sockaddr.nl_groups = 0;
38         sockaddr.nl_pid = static_cast<unsigned int>(getpid());
39     }
40 
41     /// Construct an endpoint using the specified path name.
nl_endpoint(int group,int pid=getpid ())42     nl_endpoint(int group, int pid=getpid())
43     {
44         sockaddr.nl_family = PF_NETLINK;
45         sockaddr.nl_groups = static_cast<unsigned int>(group);
46         sockaddr.nl_pid = static_cast<unsigned int>(pid);
47     }
48 
49     /// Copy constructor.
nl_endpoint(const nl_endpoint & other)50     nl_endpoint(const nl_endpoint& other)
51     {
52         sockaddr = other.sockaddr;
53     }
54 
55     /// Assign from another endpoint.
operator =(const nl_endpoint & other)56     nl_endpoint& operator=(const nl_endpoint& other)
57     {
58         sockaddr = other.sockaddr;
59         return *this;
60     }
61 
62     /// The protocol associated with the endpoint.
protocol() const63     protocol_type protocol() const
64     {
65         return protocol_type();
66     }
67 
68     /// Get the underlying endpoint in the native type.
data()69     data_type* data()
70     {
71         return reinterpret_cast<struct sockaddr*>(&sockaddr);
72     }
73 
74     /// Get the underlying endpoint in the native type.
data() const75     const data_type* data() const
76     {
77         return reinterpret_cast<const struct sockaddr*>(&sockaddr);
78     }
79 
80     /// Get the underlying size of the endpoint in the native type.
size() const81     std::size_t size() const
82     {
83         return sizeof(sockaddr);
84     }
85 
86     /// Set the underlying size of the endpoint in the native type.
resize(std::size_t size)87     void resize(std::size_t size)
88     {
89         (void)size;
90     /* nothing we can do here */
91     }
92 
93     /// Get the capacity of the endpoint in the native type.
capacity() const94     std::size_t capacity() const
95     {
96         return sizeof(sockaddr);
97     }
98 
99 private:
100     sockaddr_nl sockaddr;
101 };
102 
103 class nl_protocol {
104 public:
nl_protocol()105     nl_protocol() {
106         proto = 0;
107     }
nl_protocol(int proto)108     nl_protocol(int proto) {
109         this->proto = proto;
110     }
111     /// Obtain an identifier for the type of the protocol.
type() const112     int type() const
113     {
114         return SOCK_RAW;
115     }
116     /// Obtain an identifier for the protocol.
protocol() const117     int protocol() const
118     {
119         return proto;
120     }
121     /// Obtain an identifier for the protocol family.
family() const122     int family() const
123     {
124         return PF_NETLINK;
125     }
126 
127     typedef nl_endpoint<nl_protocol> endpoint;
128     typedef boost::asio::basic_raw_socket<nl_protocol> socket;
129 
130 private:
131     int proto;
132 };
133 
134 typedef std::function< void (bool, std::string, bool) > net_if_changed_handler_t;
135 
136 class netlink_connector : public std::enable_shared_from_this<netlink_connector> {
137 public:
netlink_connector(boost::asio::io_service & _io,boost::asio::ip::address _address,boost::asio::ip::address _multicast_address)138     netlink_connector(boost::asio::io_service& _io, boost::asio::ip::address _address,
139                       boost::asio::ip::address _multicast_address):
140         net_if_index_for_address_(0),
141         handler_(nullptr),
142         socket_(_io),
143         recv_buffer_(recv_buffer_size, 0),
144         address_(_address),
145         multicast_address_(_multicast_address) {
146     }
~netlink_connector()147     ~netlink_connector() {}
148 
149     void register_net_if_changes_handler(const net_if_changed_handler_t& _handler);
150     void unregister_net_if_changes_handler();
151 
152     void start();
153     void stop();
154 
155 private:
156     bool has_address(struct ifaddrmsg * ifa_struct,
157             size_t length,
158             const unsigned int address);
159     void send_ifa_request();
160     void send_ifi_request();
161     void send_rt_request();
162 
163     void receive_cbk(boost::system::error_code const &_error, std::size_t _bytes);
164     void send_cbk(boost::system::error_code const &_error, std::size_t _bytes);
165 
166     bool check_sd_multicast_route_match(struct rtmsg* _routemsg,
167                                         size_t _length,
168                                         std::string* _routename) const;
169 
170     std::map<int, unsigned int> net_if_flags_;
171     int net_if_index_for_address_;
172 
173     net_if_changed_handler_t handler_;
174 
175     std::mutex socket_mutex_;
176     boost::asio::basic_raw_socket<nl_protocol> socket_;
177 
178     const size_t recv_buffer_size = 16384;
179     message_buffer_t recv_buffer_;
180 
181     boost::asio::ip::address address_;
182     boost::asio::ip::address multicast_address_;
183 };
184 
185 } // namespace vsomeip_v3
186 
187 #endif // NOT _WIN32
188 
189 #endif // VSOMEIP_V3_NETLINK_CONNECTOR_HPP_
190