blob: 0b18a0a29cf06817f197f63899c1e90ba62dfd3c [file] [log] [blame]
Vitaly Buka1982bc82015-10-16 18:08:55 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Johan Euphrosineee020ee2015-10-12 12:49:16 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Johan Euphrosine3523fdd2015-10-14 20:46:05 -07005#include "examples/provider/event_network.h"
Johan Euphrosineee020ee2015-10-12 12:49:16 -07006
7#include <weave/enum_to_string.h>
8
9#include <base/bind.h>
Johan Euphrosineee020ee2015-10-12 12:49:16 -070010#include <event2/bufferevent.h>
Vitaly Buka34668e72015-12-15 14:46:47 -080011#include <event2/dns.h>
Johan Euphrosineee020ee2015-10-12 12:49:16 -070012
Johan Euphrosine3523fdd2015-10-14 20:46:05 -070013#include "examples/provider/event_task_runner.h"
14#include "examples/provider/ssl_stream.h"
Johan Euphrosineee020ee2015-10-12 12:49:16 -070015
16namespace weave {
17namespace examples {
18
19namespace {
20const char kNetworkProbeHostname[] = "talk.google.com";
21const int kNetworkProbePort = 5223;
Johan Euphrosine5c93de42015-10-15 00:17:14 -070022const int kNetworkProbeTimeoutS = 2;
Johan Euphrosineee020ee2015-10-12 12:49:16 -070023} // namespace
24
25void EventNetworkImpl::Deleter::operator()(evdns_base* dns_base) {
26 evdns_base_free(dns_base, 0);
27}
28
29void EventNetworkImpl::Deleter::operator()(bufferevent* bev) {
30 bufferevent_free(bev);
31}
32
33EventNetworkImpl::EventNetworkImpl(EventTaskRunner* task_runner)
34 : task_runner_(task_runner) {
35 UpdateNetworkState();
36}
37
38void EventNetworkImpl::AddConnectionChangedCallback(
39 const ConnectionChangedCallback& callback) {
40 callbacks_.push_back(callback);
41}
42
43void EventNetworkImpl::UpdateNetworkState() {
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070044 if (simulate_offline_) {
45 LOG(INFO) << "Simulating offline state";
46 connectivity_probe_.reset();
47 return UpdateNetworkStateCallback(State::kOffline);
48 }
49
50 connectivity_probe_.reset(
Johan Euphrosineee020ee2015-10-12 12:49:16 -070051 bufferevent_socket_new(task_runner_->GetEventBase(), -1,
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070052 BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS));
Johan Euphrosine5c93de42015-10-15 00:17:14 -070053 timeval timeout{kNetworkProbeTimeoutS, 0};
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070054 bufferevent_set_timeouts(connectivity_probe_.get(), &timeout, &timeout);
Johan Euphrosineee020ee2015-10-12 12:49:16 -070055 bufferevent_setcb(
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070056 connectivity_probe_.get(), nullptr, nullptr,
Johan Euphrosineee020ee2015-10-12 12:49:16 -070057 [](struct bufferevent* buf, short events, void* ctx) {
58 EventNetworkImpl* network = static_cast<EventNetworkImpl*>(ctx);
Johan Euphrosineee020ee2015-10-12 12:49:16 -070059 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)) {
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070064 int err = bufferevent_socket_get_dns_error(buf);
Johan Euphrosineee020ee2015-10-12 12:49:16 -070065 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);
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070074 int err = bufferevent_socket_connect_hostname(
75 connectivity_probe_.get(), dns_base_.get(), AF_INET,
76 kNetworkProbeHostname, kNetworkProbePort);
Johan Euphrosineee020ee2015-10-12 12:49:16 -070077 if (err) {
78 LOG(ERROR) << " network connect socket error: " << evutil_gai_strerror(err);
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070079 return UpdateNetworkStateCallback(State::kOffline);
Johan Euphrosineee020ee2015-10-12 12:49:16 -070080 }
Johan Euphrosineee020ee2015-10-12 12:49:16 -070081}
82
83void EventNetworkImpl::UpdateNetworkStateCallback(
84 provider::Network::State state) {
Johan Euphrosine1ca3c222015-10-15 20:43:42 -070085 if (state != network_state_) {
86 LOG(INFO) << "network state updated: " << weave::EnumToString(state);
87 network_state_ = state;
Vitaly Buka1f4308f2015-10-16 10:20:46 -070088
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();
Johan Euphrosine1ca3c222015-10-15 20:43:42 -070094 }
Vitaly Buka1f4308f2015-10-16 10:20:46 -070095
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070096 // Reset current posted task.
97 weak_ptr_factory_.InvalidateWeakPtrs();
98
Johan Euphrosineee020ee2015-10-12 12:49:16 -070099 // 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
106weave::provider::Network::State EventNetworkImpl::GetConnectionState() const {
107 return network_state_;
108}
109
110void EventNetworkImpl::OpenSslSocket(const std::string& host,
111 uint16_t port,
112 const OpenSslSocketCallback& callback) {
Vitaly Buka10e69bc2015-10-16 01:21:07 -0700113 SSLStream::Connect(task_runner_, host, port, callback);
Johan Euphrosineee020ee2015-10-12 12:49:16 -0700114}
115
116} // namespace examples
117} // namespace weave