Home | History | Annotate | Download | only in provider
      1 // Copyright 2015 The Weave Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "examples/provider/event_network.h"
      6 
      7 #include <weave/enum_to_string.h>
      8 
      9 #include <base/bind.h>
     10 #include <event2/bufferevent.h>
     11 #include <event2/dns.h>
     12 
     13 #include "examples/provider/event_task_runner.h"
     14 #include "examples/provider/ssl_stream.h"
     15 
     16 namespace weave {
     17 namespace examples {
     18 
     19 namespace {
     20 const char kNetworkProbeHostname[] = "talk.google.com";
     21 const int kNetworkProbePort = 5223;
     22 const int kNetworkProbeTimeoutS = 2;
     23 }  // namespace
     24 
     25 void EventNetworkImpl::Deleter::operator()(evdns_base* dns_base) {
     26   evdns_base_free(dns_base, 0);
     27 }
     28 
     29 void EventNetworkImpl::Deleter::operator()(bufferevent* bev) {
     30   bufferevent_free(bev);
     31 }
     32 
     33 EventNetworkImpl::EventNetworkImpl(EventTaskRunner* task_runner)
     34     : task_runner_(task_runner) {
     35   UpdateNetworkState();
     36 }
     37 
     38 void EventNetworkImpl::AddConnectionChangedCallback(
     39     const ConnectionChangedCallback& callback) {
     40   callbacks_.push_back(callback);
     41 }
     42 
     43 void EventNetworkImpl::UpdateNetworkState() {
     44   if (simulate_offline_) {
     45     LOG(INFO) << "Simulating offline state";
     46     connectivity_probe_.reset();
     47     return UpdateNetworkStateCallback(State::kOffline);
     48   }
     49 
     50   connectivity_probe_.reset(
     51       bufferevent_socket_new(task_runner_->GetEventBase(), -1,
     52                              BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS));
     53   timeval timeout{kNetworkProbeTimeoutS, 0};
     54   bufferevent_set_timeouts(connectivity_probe_.get(), &timeout, &timeout);
     55   bufferevent_setcb(
     56       connectivity_probe_.get(), nullptr, nullptr,
     57       [](struct bufferevent* buf, short events, void* ctx) {
     58         EventNetworkImpl* network = static_cast<EventNetworkImpl*>(ctx);
     59         if (events & BEV_EVENT_CONNECTED) {
     60           network->UpdateNetworkStateCallback(State::kOnline);
     61           return;
     62         }
     63         if (events & (BEV_EVENT_ERROR | BEV_EVENT_EOF | BEV_EVENT_TIMEOUT)) {
     64           int err = bufferevent_socket_get_dns_error(buf);
     65           if (err) {
     66             LOG(ERROR) << "network connect dns error: "
     67                        << evutil_gai_strerror(err);
     68           }
     69           network->UpdateNetworkStateCallback(State::kOffline);
     70           return;
     71         }
     72       },
     73       this);
     74   int err = bufferevent_socket_connect_hostname(
     75       connectivity_probe_.get(), dns_base_.get(), AF_INET,
     76       kNetworkProbeHostname, kNetworkProbePort);
     77   if (err) {
     78     LOG(ERROR) << " network connect socket error: " << evutil_gai_strerror(err);
     79     return UpdateNetworkStateCallback(State::kOffline);
     80   }
     81 }
     82 
     83 void EventNetworkImpl::UpdateNetworkStateCallback(
     84     provider::Network::State state) {
     85   if (state != network_state_) {
     86     LOG(INFO) << "network state updated: " << weave::EnumToString(state);
     87     network_state_ = state;
     88 
     89     // In general it's better to send false notification than miss one.
     90     // However current implementation can only send them very often on every
     91     // UpdateNetworkStateCallback or just here, guarder with this if condition.
     92     for (const auto& cb : callbacks_)
     93       cb.Run();
     94   }
     95 
     96   // Reset current posted task.
     97   weak_ptr_factory_.InvalidateWeakPtrs();
     98 
     99   // TODO(proppy): use netlink interface event instead of polling
    100   task_runner_->PostDelayedTask(
    101       FROM_HERE, base::Bind(&EventNetworkImpl::UpdateNetworkState,
    102                             weak_ptr_factory_.GetWeakPtr()),
    103       base::TimeDelta::FromSeconds(10));
    104 }
    105 
    106 weave::provider::Network::State EventNetworkImpl::GetConnectionState() const {
    107   return network_state_;
    108 }
    109 
    110 void EventNetworkImpl::OpenSslSocket(const std::string& host,
    111                                      uint16_t port,
    112                                      const OpenSslSocketCallback& callback) {
    113   SSLStream::Connect(task_runner_, host, port, callback);
    114 }
    115 
    116 }  // namespace examples
    117 }  // namespace weave
    118