|  | // 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/provider/event_network.h" | 
|  |  | 
|  | #include <weave/enum_to_string.h> | 
|  |  | 
|  | #include <base/bind.h> | 
|  | #include <event2/bufferevent.h> | 
|  | #include <event2/dns.h> | 
|  |  | 
|  | #include "examples/provider/event_task_runner.h" | 
|  | #include "examples/provider/ssl_stream.h" | 
|  |  | 
|  | namespace weave { | 
|  | namespace examples { | 
|  |  | 
|  | namespace { | 
|  | const char kNetworkProbeHostname[] = "talk.google.com"; | 
|  | const int kNetworkProbePort = 5223; | 
|  | const int kNetworkProbeTimeoutS = 2; | 
|  | }  // 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() { | 
|  | if (simulate_offline_) { | 
|  | LOG(INFO) << "Simulating offline state"; | 
|  | connectivity_probe_.reset(); | 
|  | return UpdateNetworkStateCallback(State::kOffline); | 
|  | } | 
|  |  | 
|  | connectivity_probe_.reset( | 
|  | bufferevent_socket_new(task_runner_->GetEventBase(), -1, | 
|  | BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS)); | 
|  | timeval timeout{kNetworkProbeTimeoutS, 0}; | 
|  | bufferevent_set_timeouts(connectivity_probe_.get(), &timeout, &timeout); | 
|  | bufferevent_setcb( | 
|  | connectivity_probe_.get(), nullptr, nullptr, | 
|  | [](struct bufferevent* buf, short events, void* ctx) { | 
|  | EventNetworkImpl* network = static_cast<EventNetworkImpl*>(ctx); | 
|  | 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(buf); | 
|  | if (err) { | 
|  | LOG(ERROR) << "network connect dns error: " | 
|  | << evutil_gai_strerror(err); | 
|  | } | 
|  | network->UpdateNetworkStateCallback(State::kOffline); | 
|  | return; | 
|  | } | 
|  | }, | 
|  | this); | 
|  | int err = bufferevent_socket_connect_hostname( | 
|  | connectivity_probe_.get(), dns_base_.get(), AF_INET, | 
|  | kNetworkProbeHostname, kNetworkProbePort); | 
|  | if (err) { | 
|  | LOG(ERROR) << " network connect socket error: " << evutil_gai_strerror(err); | 
|  | return UpdateNetworkStateCallback(State::kOffline); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EventNetworkImpl::UpdateNetworkStateCallback( | 
|  | provider::Network::State state) { | 
|  | if (state != network_state_) { | 
|  | LOG(INFO) << "network state updated: " << weave::EnumToString(state); | 
|  | network_state_ = state; | 
|  |  | 
|  | // In general it's better to send false notification than miss one. | 
|  | // However current implementation can only send them very often on every | 
|  | // UpdateNetworkStateCallback or just here, guarder with this if condition. | 
|  | for (const auto& cb : callbacks_) | 
|  | cb.Run(); | 
|  | } | 
|  |  | 
|  | // Reset current posted task. | 
|  | weak_ptr_factory_.InvalidateWeakPtrs(); | 
|  |  | 
|  | // 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) { | 
|  | SSLStream::Connect(task_runner_, host, port, callback); | 
|  | } | 
|  |  | 
|  | }  // namespace examples | 
|  | }  // namespace weave |