examples/ubuntu: add netlink network provider This report the network state using netlink kernel interface thru libnl-3.0 and allow us to remove the dependencies on network manager command line tools. Bug: 24466635 Change-Id: Icebc38a68522ad24a6f7cdad6e22cf39ce098ffa Reviewed-on: https://weave-review.googlesource.com/1246 Reviewed-by: Vitaly Buka <vitalybuka@google.com> Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/libweave/examples/ubuntu/netlink_network.cc b/libweave/examples/ubuntu/netlink_network.cc new file mode 100644 index 0000000..a76655a --- /dev/null +++ b/libweave/examples/ubuntu/netlink_network.cc
@@ -0,0 +1,115 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "examples/ubuntu/netlink_network.h" + +#include <weave/provider/task_runner.h> +#include <base/bind.h> +#include <netlink/route/link.h> + +#include "examples/ubuntu/ssl_stream.h" + +namespace weave { +namespace examples { + +void NetlinkNetworkImpl::Deleter::operator()(nl_sock* s) { + nl_close(s); + nl_socket_free(s); +} + +void NetlinkNetworkImpl::Deleter::operator()(nl_cache* c) { + nl_cache_put(c); +} + +void NetlinkNetworkImpl::Deleter::operator()(rtnl_link* l) { + rtnl_link_put(l); +} + +NetlinkNetworkImpl::NetlinkNetworkImpl(weave::provider::TaskRunner* task_runner) + : task_runner_(task_runner) { + nl_sock_.reset(nl_socket_alloc()); + CHECK(nl_sock_); + CHECK_EQ(nl_connect(nl_sock_.get(), NETLINK_ROUTE), 0); + nl_cache* nl_cache; + CHECK_EQ(rtnl_link_alloc_cache(nl_sock_.get(), AF_UNSPEC, &nl_cache), 0); + nl_cache_.reset(nl_cache); + UpdateNetworkState(); +} + +void NetlinkNetworkImpl::AddConnectionChangedCallback( + const ConnectionChangedCallback& callback) { + callbacks_.push_back(callback); +} + +void NetlinkNetworkImpl::UpdateNetworkState() { + // TODO(proppy): pick up interface with the default route instead of index 0. + // TODO(proppy): test actual internet connection. + // TODO(proppy): subscribe to interface changes instead of polling. + network_state_ = GetInterfaceState(0); + task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&NetlinkNetworkImpl::UpdateNetworkState, + weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(10)); + for (const auto& cb : callbacks_) + cb.Run(); +} + +weave::provider::Network::State NetlinkNetworkImpl::GetInterfaceState( + int if_index) { + auto refill_result = nl_cache_refill(nl_sock_.get(), nl_cache_.get()); + if (refill_result < 0) { + LOG(ERROR) << "failed to refresh netlink cache: " << refill_result; + return Network::State::kFailure; + } + std::unique_ptr<rtnl_link, Deleter> nl_link{ + rtnl_link_get(nl_cache_.get(), if_index)}; + if (!nl_link) { + LOG(ERROR) << "failed to get interface 0"; + return Network::State::kFailure; + } + + int state = rtnl_link_get_operstate(nl_link.get()); + switch (state) { + case IF_OPER_DOWN: + case IF_OPER_LOWERLAYERDOWN: + return Network::State::kOffline; + case IF_OPER_DORMANT: + return Network::State::kConnecting; + case IF_OPER_UP: + return Network::State::kConnected; + case IF_OPER_TESTING: + case IF_OPER_NOTPRESENT: + case IF_OPER_UNKNOWN: + default: + LOG(ERROR) << "unknown interface state: " << state; + return Network::State::kFailure; + } +} + +weave::provider::Network::State NetlinkNetworkImpl::GetConnectionState() const { + return network_state_; +} + +void NetlinkNetworkImpl::OpenSslSocket( + const std::string& host, + uint16_t port, + const OpenSslSocketSuccessCallback& success_callback, + const ErrorCallback& error_callback) { + // Connect to SSL port instead of upgrading to TLS. + std::unique_ptr<SSLStream> tls_stream{new SSLStream{task_runner_}}; + + if (tls_stream->Init(host, port)) { + task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(success_callback, base::Passed(&tls_stream)), {}); + } else { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, "tls", "tls_init_failed", + "Failed to initialize TLS stream."); + task_runner_->PostDelayedTask(FROM_HERE, + base::Bind(error_callback, error.get()), {}); + } +} + +} // namespace examples +} // namespace weave
diff --git a/libweave/examples/ubuntu/netlink_network.h b/libweave/examples/ubuntu/netlink_network.h new file mode 100644 index 0000000..3f5f51a --- /dev/null +++ b/libweave/examples/ubuntu/netlink_network.h
@@ -0,0 +1,55 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIBWEAVE_EXAMPLES_UBUNTU_NETLINK_MANAGER_H_ +#define LIBWEAVE_EXAMPLES_UBUNTU_NETLINK_MANAGER_H_ + +#include <weave/provider/network.h> + +#include <base/memory/weak_ptr.h> + +struct nl_sock; +struct nl_cache; +struct rtnl_link; + +namespace weave { + +namespace provider { +class TaskRunner; +} + +namespace examples { + +class NetlinkNetworkImpl : public weave::provider::Network { + public: + explicit NetlinkNetworkImpl(weave::provider::TaskRunner* task_runner_); + void AddConnectionChangedCallback( + const ConnectionChangedCallback& callback) override; + State GetConnectionState() const override; + void OpenSslSocket(const std::string& host, + uint16_t port, + const OpenSslSocketSuccessCallback& success_callback, + const ErrorCallback& error_callback) override; + + private: + class Deleter { + public: + void operator()(nl_sock* s); + void operator()(nl_cache* c); + void operator()(rtnl_link* l); + }; + void UpdateNetworkState(); + State GetInterfaceState(int if_index); + provider::TaskRunner* task_runner_{nullptr}; + std::vector<ConnectionChangedCallback> callbacks_; + provider::Network::State network_state_{provider::Network::State::kOffline}; + std::unique_ptr<nl_sock, Deleter> nl_sock_; + std::unique_ptr<nl_cache, Deleter> nl_cache_; + base::WeakPtrFactory<NetlinkNetworkImpl> weak_ptr_factory_{this}; +}; + +} // namespace examples +} // namespace weave + +#endif // LIBWEAVE_EXAMPLES_UBUNTU_NETLINK_MANAGER_H_
diff --git a/libweave/examples/ubuntu/prerequisites.sh b/libweave/examples/ubuntu/prerequisites.sh index f64f06b..6af38b9 100755 --- a/libweave/examples/ubuntu/prerequisites.sh +++ b/libweave/examples/ubuntu/prerequisites.sh
@@ -15,6 +15,8 @@ libavahi-client-dev \ libcurl4-openssl-dev \ libexpat1-dev \ + libnl-3-dev \ + libnl-route-3-dev \ libtool \ ninja-build \ || exit 1
diff --git a/libweave/examples/ubuntu/weave.gyp b/libweave/examples/ubuntu/weave.gyp index a4df01d..81b492b 100644 --- a/libweave/examples/ubuntu/weave.gyp +++ b/libweave/examples/ubuntu/weave.gyp
@@ -3,7 +3,7 @@ { 'target_name': 'weave', 'type': 'executable', - 'cflags': ['-pthread'], + 'cflags': ['-pthread', '-I/usr/include/libnl3'], 'sources': [ 'avahi_client.cc', 'bluez_client.cc', @@ -12,6 +12,7 @@ 'event_task_runner.cc', 'file_config_store.cc', 'main.cc', + 'netlink_network.cc', 'network_manager.cc', 'ssl_stream.cc', ], @@ -28,6 +29,8 @@ '-lavahi-common', '-lavahi-client', '-levent_openssl', + '-lnl-3', + '-lnl-route-3', ] } ]