11982bc8b68b8923f14097ad35dfdb81e9305d725Vitaly Buka// Copyright 2015 The Weave Authors. All rights reserved.
2ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine// Use of this source code is governed by a BSD-style license that can be
3ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine// found in the LICENSE file.
4ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
53523fdd2a071c7b918761cf82f1ac0ff73188093Johan Euphrosine#include "examples/provider/event_network.h"
6ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
7ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine#include <weave/enum_to_string.h>
8ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
9ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine#include <base/bind.h>
10ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine#include <event2/bufferevent.h>
1134668e731bb194b443bc0e6029d6d3583f08de28Vitaly Buka#include <event2/dns.h>
12ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
133523fdd2a071c7b918761cf82f1ac0ff73188093Johan Euphrosine#include "examples/provider/event_task_runner.h"
143523fdd2a071c7b918761cf82f1ac0ff73188093Johan Euphrosine#include "examples/provider/ssl_stream.h"
15ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
16ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinenamespace weave {
17ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinenamespace examples {
18ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
19ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinenamespace {
20ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosineconst char kNetworkProbeHostname[] = "talk.google.com";
21ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosineconst int kNetworkProbePort = 5223;
225c93de4dd8d152efcd62ff59f31700669e880185Johan Euphrosineconst int kNetworkProbeTimeoutS = 2;
23ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}  // namespace
24ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
25ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::Deleter::operator()(evdns_base* dns_base) {
26ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  evdns_base_free(dns_base, 0);
27ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
28ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
29ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::Deleter::operator()(bufferevent* bev) {
30ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  bufferevent_free(bev);
31ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
32ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
33ee020ee3798080e10ba1571a80ff2428636d2510Johan EuphrosineEventNetworkImpl::EventNetworkImpl(EventTaskRunner* task_runner)
34ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine    : task_runner_(task_runner) {
35ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  UpdateNetworkState();
36ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
37ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
38ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::AddConnectionChangedCallback(
39ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine    const ConnectionChangedCallback& callback) {
40ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  callbacks_.push_back(callback);
41ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
42ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
43ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::UpdateNetworkState() {
443d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  if (simulate_offline_) {
453d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka    LOG(INFO) << "Simulating offline state";
463d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka    connectivity_probe_.reset();
473d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka    return UpdateNetworkStateCallback(State::kOffline);
483d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  }
493d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka
503d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  connectivity_probe_.reset(
51ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      bufferevent_socket_new(task_runner_->GetEventBase(), -1,
523d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka                             BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS));
535c93de4dd8d152efcd62ff59f31700669e880185Johan Euphrosine  timeval timeout{kNetworkProbeTimeoutS, 0};
543d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  bufferevent_set_timeouts(connectivity_probe_.get(), &timeout, &timeout);
55ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  bufferevent_setcb(
563d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka      connectivity_probe_.get(), nullptr, nullptr,
57ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      [](struct bufferevent* buf, short events, void* ctx) {
58ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine        EventNetworkImpl* network = static_cast<EventNetworkImpl*>(ctx);
59ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine        if (events & BEV_EVENT_CONNECTED) {
60ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          network->UpdateNetworkStateCallback(State::kOnline);
61ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          return;
62ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine        }
63ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine        if (events & (BEV_EVENT_ERROR | BEV_EVENT_EOF | BEV_EVENT_TIMEOUT)) {
643d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka          int err = bufferevent_socket_get_dns_error(buf);
65ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          if (err) {
66ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine            LOG(ERROR) << "network connect dns error: "
67ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine                       << evutil_gai_strerror(err);
68ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          }
69ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          network->UpdateNetworkStateCallback(State::kOffline);
70ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine          return;
71ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine        }
72ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      },
73ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      this);
743d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  int err = bufferevent_socket_connect_hostname(
753d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka      connectivity_probe_.get(), dns_base_.get(), AF_INET,
763d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka      kNetworkProbeHostname, kNetworkProbePort);
77ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  if (err) {
78ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine    LOG(ERROR) << " network connect socket error: " << evutil_gai_strerror(err);
793d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka    return UpdateNetworkStateCallback(State::kOffline);
80ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  }
81ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
82ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
83ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::UpdateNetworkStateCallback(
84ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine    provider::Network::State state) {
851ca3c227950fcd2c8a2d5a03f0de9eb52afa2b98Johan Euphrosine  if (state != network_state_) {
861ca3c227950fcd2c8a2d5a03f0de9eb52afa2b98Johan Euphrosine    LOG(INFO) << "network state updated: " << weave::EnumToString(state);
871ca3c227950fcd2c8a2d5a03f0de9eb52afa2b98Johan Euphrosine    network_state_ = state;
881f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka
891f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka    // In general it's better to send false notification than miss one.
901f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka    // However current implementation can only send them very often on every
911f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka    // UpdateNetworkStateCallback or just here, guarder with this if condition.
921f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka    for (const auto& cb : callbacks_)
931f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka      cb.Run();
941ca3c227950fcd2c8a2d5a03f0de9eb52afa2b98Johan Euphrosine  }
951f4308f367456c4920e48c5bb3e7cbff54d49ce0Vitaly Buka
963d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  // Reset current posted task.
973d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka  weak_ptr_factory_.InvalidateWeakPtrs();
983d8feaf206e4fc4e0e410800bc7c6aba9d983b14Vitaly Buka
99ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  // TODO(proppy): use netlink interface event instead of polling
100ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  task_runner_->PostDelayedTask(
101ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      FROM_HERE, base::Bind(&EventNetworkImpl::UpdateNetworkState,
102ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine                            weak_ptr_factory_.GetWeakPtr()),
103ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine      base::TimeDelta::FromSeconds(10));
104ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
105ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
106ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosineweave::provider::Network::State EventNetworkImpl::GetConnectionState() const {
107ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine  return network_state_;
108ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
109ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
110ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosinevoid EventNetworkImpl::OpenSslSocket(const std::string& host,
111ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine                                     uint16_t port,
112ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine                                     const OpenSslSocketCallback& callback) {
11310e69bc6877a855fc917ac1d265498fb262452cdVitaly Buka  SSLStream::Connect(task_runner_, host, port, callback);
114ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}
115ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine
116ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}  // namespace examples
117ee020ee3798080e10ba1571a80ff2428636d2510Johan Euphrosine}  // namespace weave
118