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
operator ()(evdns_base * dns_base)25 void EventNetworkImpl::Deleter::operator()(evdns_base* dns_base) {
26 evdns_base_free(dns_base, 0);
27 }
28
operator ()(bufferevent * bev)29 void EventNetworkImpl::Deleter::operator()(bufferevent* bev) {
30 bufferevent_free(bev);
31 }
32
EventNetworkImpl(EventTaskRunner * task_runner)33 EventNetworkImpl::EventNetworkImpl(EventTaskRunner* task_runner)
34 : task_runner_(task_runner) {
35 UpdateNetworkState();
36 }
37
AddConnectionChangedCallback(const ConnectionChangedCallback & callback)38 void EventNetworkImpl::AddConnectionChangedCallback(
39 const ConnectionChangedCallback& callback) {
40 callbacks_.push_back(callback);
41 }
42
UpdateNetworkState()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
UpdateNetworkStateCallback(provider::Network::State state)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
GetConnectionState() const106 weave::provider::Network::State EventNetworkImpl::GetConnectionState() const {
107 return network_state_;
108 }
109
OpenSslSocket(const std::string & host,uint16_t port,const OpenSslSocketCallback & callback)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