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',
]
}
]