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