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