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