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