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