summaryrefslogtreecommitdiff
path: root/implementation/endpoints/src/netlink_connector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'implementation/endpoints/src/netlink_connector.cpp')
-rw-r--r--implementation/endpoints/src/netlink_connector.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/implementation/endpoints/src/netlink_connector.cpp b/implementation/endpoints/src/netlink_connector.cpp
new file mode 100644
index 0000000..aab5363
--- /dev/null
+++ b/implementation/endpoints/src/netlink_connector.cpp
@@ -0,0 +1,262 @@
+// Copyright (C) 2014-2016 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef WIN32
+
+#include <thread>
+
+#include <boost/asio/write.hpp>
+#include <boost/asio/read.hpp>
+
+#include "../include/netlink_connector.hpp"
+#include "../../logging/include/logger.hpp"
+
+namespace vsomeip {
+
+void netlink_connector::register_net_if_changes_handler(net_if_changed_handler_t _handler) {
+ handler_ = _handler;
+}
+
+void netlink_connector::unregister_net_if_changes_handler() {
+ handler_ = nullptr;
+}
+
+void netlink_connector::stop() {
+ boost::system::error_code its_error;
+ socket_.close(its_error);
+ if (its_error) {
+ VSOMEIP_WARNING << "Error closing NETLINK socket!";
+ }
+}
+
+void netlink_connector::start() {
+ boost::system::error_code ec;
+ if (socket_.is_open()) {
+ socket_.close(ec);
+ if (ec) {
+ VSOMEIP_WARNING << "Error closing NETLINK socket: " << ec.message();
+ }
+ }
+ socket_.open(nl_protocol(NETLINK_ROUTE), ec);
+ if (ec) {
+ VSOMEIP_WARNING << "Error opening NETLINK socket: " << ec.message();
+ if (handler_) {
+ handler_("n/a", true);
+ }
+ return;
+ }
+ if (socket_.is_open()) {
+ socket_.bind(nl_endpoint<nl_protocol>(RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR), ec);
+
+ if (ec) {
+ VSOMEIP_WARNING << "Error binding NETLINK socket: " << ec.message();
+ if (handler_) {
+ handler_("n/a", true);
+ }
+ return;
+ }
+
+ send_ifa_request();
+
+ socket_.async_receive(
+ boost::asio::buffer(&recv_buffer_[0], recv_buffer_size),
+ std::bind(
+ &netlink_connector::receive_cbk,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+ } else {
+ VSOMEIP_WARNING << "Error opening NETLINK socket!";
+ if (handler_) {
+ handler_("n/a", true);
+ }
+ }
+}
+
+void netlink_connector::receive_cbk(boost::system::error_code const &_error,
+ std::size_t _bytes) {
+ if (!_error) {
+ size_t len = _bytes;
+
+ unsigned int address;
+ if (address_.is_v4()) {
+ inet_pton(AF_INET, address_.to_string().c_str(), &address);
+ } else {
+ inet_pton(AF_INET6, address_.to_string().c_str(), &address);
+ }
+
+ struct nlmsghdr *nlh = (struct nlmsghdr *)&recv_buffer_[0];
+
+ while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
+ char ifname[1024];
+ struct ifinfomsg *ifi = (ifinfomsg *)NLMSG_DATA(nlh);
+ struct ifaddrmsg *ifa = (ifaddrmsg *)NLMSG_DATA(nlh);
+ switch (nlh->nlmsg_type) {
+ case RTM_NEWADDR:
+ // New Address information
+ if (has_address((struct ifaddrmsg *)NLMSG_DATA(nlh),
+ IFA_PAYLOAD(nlh), address)) {
+ net_if_index_for_address_ = ifa->ifa_index;
+ auto its_if = net_if_flags_.find(ifa->ifa_index);
+ if (its_if != net_if_flags_.end()) {
+ if ((its_if->second & IFF_UP) &&
+ (its_if->second & IFF_RUNNING)) {
+ if (handler_) {
+ if_indextoname(ifa->ifa_index,ifname);
+ handler_(ifname, true);
+ }
+ } else {
+ if (handler_) {
+ if_indextoname(ifa->ifa_index,ifname);
+ handler_(ifname, false);
+ }
+ }
+ } else {
+ // Request interface information
+ // as we don't know about up/running state!
+ send_ifi_request();
+ }
+ }
+ break;
+ case RTM_NEWLINK:
+ // New Interface information
+ net_if_flags_[ifi->ifi_index] = ifi->ifi_flags;
+ if (net_if_index_for_address_ == ifi->ifi_index) {
+ if ((ifi->ifi_flags & IFF_UP) &&
+ (ifi->ifi_flags & IFF_RUNNING)) {
+ if (handler_) {
+ if_indextoname(ifi->ifi_index,ifname);
+ handler_(ifname, true);
+ }
+ } else {
+ if (handler_) {
+ if_indextoname(ifi->ifi_index,ifname);
+ handler_(ifname, false);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ nlh = NLMSG_NEXT(nlh, len);
+ }
+ socket_.async_receive(
+ boost::asio::buffer(&recv_buffer_[0], recv_buffer_size),
+ std::bind(
+ &netlink_connector::receive_cbk,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+ } else {
+ if (_error != boost::asio::error::operation_aborted) {
+ VSOMEIP_WARNING << "Error receive_cbk NETLINK socket!" << _error.message();
+ boost::system::error_code its_error;
+ if (socket_.is_open()) {
+ socket_.close(its_error);
+ if (its_error) {
+ VSOMEIP_WARNING << "Error closing NETLINK socket!" << its_error.message();
+ }
+ }
+ if (handler_) {
+ handler_("n/a", true);
+ }
+ }
+ }
+}
+
+void netlink_connector::send_cbk(boost::system::error_code const &_error, std::size_t _bytes) {
+ (void)_bytes;
+ if (_error) {
+ VSOMEIP_WARNING << "Netlink send error : " << _error.message();
+ if (handler_) {
+ handler_("n/a", true);
+ }
+ }
+}
+
+void netlink_connector::send_ifa_request() {
+ typedef struct {
+ struct nlmsghdr nlhdr;
+ struct ifaddrmsg addrmsg;
+ } netlink_address_msg;
+ netlink_address_msg get_address_msg;
+ memset(&get_address_msg, 0, sizeof(get_address_msg));
+ get_address_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ get_address_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ get_address_msg.nlhdr.nlmsg_type = RTM_GETADDR;
+ if (address_.is_v4()) {
+ get_address_msg.addrmsg.ifa_family = AF_INET;
+ } else {
+ get_address_msg.addrmsg.ifa_family = AF_INET6;
+ }
+
+ socket_.async_send(
+ boost::asio::buffer(&get_address_msg, get_address_msg.nlhdr.nlmsg_len),
+ std::bind(
+ &netlink_connector::send_cbk,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+}
+
+void netlink_connector::send_ifi_request() {
+ typedef struct {
+ struct nlmsghdr nlhdr;
+ struct ifinfomsg infomsg;
+ } netlink_link_msg;
+ netlink_link_msg get_link_msg;
+ memset(&get_link_msg, 0, sizeof(get_link_msg));
+ get_link_msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ get_link_msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ get_link_msg.nlhdr.nlmsg_type = RTM_GETLINK;
+ get_link_msg.infomsg.ifi_family = AF_UNSPEC;
+
+ socket_.async_send(
+ boost::asio::buffer(&get_link_msg, get_link_msg.nlhdr.nlmsg_len),
+ std::bind(
+ &netlink_connector::send_cbk,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2
+ )
+ );
+}
+
+bool netlink_connector::has_address(const struct ifaddrmsg * ifa_struct,
+ size_t length,
+ const unsigned int address) {
+
+ struct rtattr *retrta;
+ retrta = (struct rtattr *)IFA_RTA(ifa_struct);
+ while RTA_OK(retrta, length) {
+ if (retrta->rta_type == IFA_ADDRESS) {
+ char pradd[128];
+ unsigned int * tmp_address = (unsigned int *)RTA_DATA(retrta);
+ if (address_.is_v4()) {
+ inet_ntop(AF_INET, tmp_address, pradd, sizeof(pradd));
+ } else {
+ inet_ntop(AF_INET6, tmp_address, pradd, sizeof(pradd));
+ }
+ if (address == *tmp_address) {
+ return true;
+ }
+ }
+ retrta = RTA_NEXT(retrta, length);
+ }
+
+ return false;
+}
+
+} // namespace vsomeip
+
+#endif
+