example/ubuntu: add libevent network provider
- probe network by connecting to talk.google.com xmpp
- non blocking dns and connection
- replaces netlink based network
Bug: 24466635
Change-Id: I8a00731e18b8f155a8bf71f6c5593ca60d8612be
Reviewed-on: https://weave-review.googlesource.com/1303
Reviewed-by: Johan Euphrosine <proppy@google.com>
diff --git a/libweave/examples/ubuntu/event_network.cc b/libweave/examples/ubuntu/event_network.cc
new file mode 100644
index 0000000..b411f80
--- /dev/null
+++ b/libweave/examples/ubuntu/event_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/event_network.h"
+
+#include <weave/enum_to_string.h>
+
+#include <base/bind.h>
+#include <event2/dns.h>
+#include <event2/bufferevent.h>
+
+#include "examples/ubuntu/event_task_runner.h"
+#include "examples/ubuntu/ssl_stream.h"
+
+namespace weave {
+namespace examples {
+
+namespace {
+const char kNetworkProbeHostname[] = "talk.google.com";
+const int kNetworkProbePort = 5223;
+} // namespace
+
+void EventNetworkImpl::Deleter::operator()(evdns_base* dns_base) {
+ evdns_base_free(dns_base, 0);
+}
+
+void EventNetworkImpl::Deleter::operator()(bufferevent* bev) {
+ bufferevent_free(bev);
+}
+
+EventNetworkImpl::EventNetworkImpl(EventTaskRunner* task_runner)
+ : task_runner_(task_runner) {
+ UpdateNetworkState();
+}
+
+void EventNetworkImpl::AddConnectionChangedCallback(
+ const ConnectionChangedCallback& callback) {
+ callbacks_.push_back(callback);
+}
+
+void EventNetworkImpl::UpdateNetworkState() {
+ std::unique_ptr<bufferevent, Deleter> bev{
+ bufferevent_socket_new(task_runner_->GetEventBase(), -1,
+ BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS)};
+ bufferevent_setcb(
+ bev.get(), nullptr, nullptr,
+ [](struct bufferevent* buf, short events, void* ctx) {
+ EventNetworkImpl* network = static_cast<EventNetworkImpl*>(ctx);
+ std::unique_ptr<bufferevent, Deleter> bev{buf};
+ if (events & BEV_EVENT_CONNECTED) {
+ network->UpdateNetworkStateCallback(State::kOnline);
+ return;
+ }
+ if (events & (BEV_EVENT_ERROR | BEV_EVENT_EOF | BEV_EVENT_TIMEOUT)) {
+ int err = bufferevent_socket_get_dns_error(bev.get());
+ if (err) {
+ LOG(ERROR) << "network connect dns error: "
+ << evutil_gai_strerror(err);
+ }
+ network->UpdateNetworkStateCallback(State::kOffline);
+ return;
+ }
+ },
+ this);
+ int err = bufferevent_socket_connect_hostname(bev.get(), dns_base_.get(),
+ AF_INET, kNetworkProbeHostname,
+ kNetworkProbePort);
+ if (err) {
+ LOG(ERROR) << " network connect socket error: " << evutil_gai_strerror(err);
+ UpdateNetworkStateCallback(State::kOffline);
+ return;
+ }
+ // release the bufferevent, so that the eventcallback can free it.
+ bev.release();
+}
+
+void EventNetworkImpl::UpdateNetworkStateCallback(
+ provider::Network::State state) {
+ network_state_ = state;
+ LOG(INFO) << "network state updated: " << weave::EnumToString(state);
+ for (const auto& cb : callbacks_)
+ cb.Run();
+ // TODO(proppy): use netlink interface event instead of polling
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&EventNetworkImpl::UpdateNetworkState,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(10));
+}
+
+weave::provider::Network::State EventNetworkImpl::GetConnectionState() const {
+ return network_state_;
+}
+
+void EventNetworkImpl::OpenSslSocket(const std::string& host,
+ uint16_t port,
+ const OpenSslSocketCallback& 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(callback, base::Passed(&tls_stream), nullptr),
+ {});
+ } else {
+ ErrorPtr error;
+ Error::AddTo(&error, FROM_HERE, "tls", "tls_init_failed",
+ "Failed to initialize TLS stream.");
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
+ }
+}
+
+} // namespace examples
+} // namespace weave
diff --git a/libweave/examples/ubuntu/event_network.h b/libweave/examples/ubuntu/event_network.h
new file mode 100644
index 0000000..79c458c
--- /dev/null
+++ b/libweave/examples/ubuntu/event_network.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Weave 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_EVENT_NETWORK_H_
+#define LIBWEAVE_EXAMPLES_UBUNTU_EVENT_NETWORK_H_
+
+#include <weave/provider/network.h>
+
+#include <base/memory/weak_ptr.h>
+
+struct evdns_base;
+struct bufferevent;
+
+namespace weave {
+namespace examples {
+
+class EventTaskRunner;
+
+class EventNetworkImpl : public weave::provider::Network {
+ class Deleter {
+ public:
+ void operator()(evdns_base* dns_base);
+ void operator()(bufferevent* bev);
+ };
+
+ public:
+ explicit EventNetworkImpl(EventTaskRunner* task_runner_);
+ void AddConnectionChangedCallback(
+ const ConnectionChangedCallback& callback) override;
+ State GetConnectionState() const override;
+ void OpenSslSocket(const std::string& host,
+ uint16_t port,
+ const OpenSslSocketCallback& callback) override;
+
+ private:
+ void UpdateNetworkState();
+ void UpdateNetworkStateCallback(provider::Network::State state);
+ EventTaskRunner* task_runner_{nullptr};
+ std::unique_ptr<evdns_base, Deleter> dns_base_;
+ std::vector<ConnectionChangedCallback> callbacks_;
+ provider::Network::State network_state_{provider::Network::State::kOffline};
+ base::WeakPtrFactory<EventNetworkImpl> weak_ptr_factory_{this};
+};
+
+} // namespace examples
+} // namespace weave
+
+#endif // LIBWEAVE_EXAMPLES_UBUNTU_EVENT_NETWORK_H_
diff --git a/libweave/examples/ubuntu/netlink_network.cc b/libweave/examples/ubuntu/netlink_network.cc
deleted file mode 100644
index ea1786e..0000000
--- a/libweave/examples/ubuntu/netlink_network.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2015 The Weave 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::kError;
- }
- 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::kError;
- }
-
- 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::kOnline;
- case IF_OPER_TESTING:
- case IF_OPER_NOTPRESENT:
- case IF_OPER_UNKNOWN:
- default:
- LOG(ERROR) << "unknown interface state: " << state;
- return Network::State::kError;
- }
-}
-
-weave::provider::Network::State NetlinkNetworkImpl::GetConnectionState() const {
- return network_state_;
-}
-
-void NetlinkNetworkImpl::OpenSslSocket(const std::string& host,
- uint16_t port,
- const OpenSslSocketCallback& 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(callback, base::Passed(&tls_stream), nullptr),
- {});
- } else {
- ErrorPtr error;
- Error::AddTo(&error, FROM_HERE, "tls", "tls_init_failed",
- "Failed to initialize TLS stream.");
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(callback, nullptr, base::Passed(&error)), {});
- }
-}
-
-} // namespace examples
-} // namespace weave
diff --git a/libweave/examples/ubuntu/netlink_network.h b/libweave/examples/ubuntu/netlink_network.h
deleted file mode 100644
index 781e9b4..0000000
--- a/libweave/examples/ubuntu/netlink_network.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2015 The Weave 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 OpenSslSocketCallback& 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/weave.gyp b/libweave/examples/ubuntu/weave.gyp
index 01ede1a..a561c9d 100644
--- a/libweave/examples/ubuntu/weave.gyp
+++ b/libweave/examples/ubuntu/weave.gyp
@@ -12,8 +12,6 @@
'expat',
'libcurl',
'libcrypto',
- 'libnl-3.0',
- 'libnl-route-3.0',
'openssl',
]
},
@@ -38,7 +36,7 @@
'event_task_runner.cc',
'file_config_store.cc',
'main.cc',
- 'netlink_network.cc',
+ 'event_network.cc',
'network_manager.cc',
'ssl_stream.cc',
],