1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/dns_server_tester.h"
18
19#include <string>
20
21#include <base/bind.h>
22#include <base/strings/string_number_conversions.h>
23#include <base/strings/string_util.h>
24#include <base/strings/stringprintf.h>
25
26#include "shill/connection.h"
27#include "shill/dns_client.h"
28#include "shill/dns_client_factory.h"
29#include "shill/error.h"
30#include "shill/event_dispatcher.h"
31
32using base::Bind;
33using base::Callback;
34using std::vector;
35using std::string;
36
37namespace shill {
38
39// static
40const char DNSServerTester::kDNSTestHostname[] = "www.gstatic.com";
41// static
42const int DNSServerTester::kDNSTestRetryIntervalMilliseconds = 60000;
43// static
44const int DNSServerTester::kDNSTimeoutMilliseconds = 5000;
45
46DNSServerTester::DNSServerTester(ConnectionRefPtr connection,
47                                 EventDispatcher* dispatcher,
48                                 const vector<string>& dns_servers,
49                                 const bool retry_until_success,
50                                 const Callback<void(const Status)>& callback)
51    : connection_(connection),
52      dispatcher_(dispatcher),
53      retry_until_success_(retry_until_success),
54      weak_ptr_factory_(this),
55      dns_result_callback_(callback),
56      dns_client_callback_(Bind(&DNSServerTester::DNSClientCallback,
57                                weak_ptr_factory_.GetWeakPtr())),
58      dns_test_client_(DNSClientFactory::GetInstance()->CreateDNSClient(
59          IPAddress::kFamilyIPv4,
60          connection_->interface_name(),
61          dns_servers,
62          kDNSTimeoutMilliseconds,
63          dispatcher_,
64          dns_client_callback_)) {}
65
66DNSServerTester::~DNSServerTester() {
67  Stop();
68}
69
70void DNSServerTester::Start() {
71  // Stop existing attempt.
72  Stop();
73  // Schedule the test to start immediately.
74  StartAttempt(0);
75}
76
77void DNSServerTester::StartAttempt(int delay_ms) {
78  start_attempt_.Reset(Bind(&DNSServerTester::StartAttemptTask,
79                            weak_ptr_factory_.GetWeakPtr()));
80  dispatcher_->PostDelayedTask(start_attempt_.callback(), delay_ms);
81}
82
83void DNSServerTester::StartAttemptTask() {
84  Error error;
85  if (!dns_test_client_->Start(kDNSTestHostname, &error)) {
86    LOG(ERROR) << __func__ << ": Failed to start DNS client "
87                                << error.message();
88    CompleteAttempt(kStatusFailure);
89  }
90}
91
92void DNSServerTester::Stop() {
93  start_attempt_.Cancel();
94  StopAttempt();
95}
96
97void DNSServerTester::StopAttempt() {
98  if (dns_test_client_.get()) {
99    dns_test_client_->Stop();
100  }
101}
102
103void DNSServerTester::CompleteAttempt(Status status) {
104  if (status == kStatusFailure && retry_until_success_) {
105    // Schedule the test to restart after retry timeout interval.
106    StartAttempt(kDNSTestRetryIntervalMilliseconds);
107    return;
108  }
109
110  dns_result_callback_.Run(status);
111}
112
113void DNSServerTester::DNSClientCallback(const Error& error,
114                                        const IPAddress& ip) {
115  Status status = kStatusSuccess;
116  if (!error.IsSuccess()) {
117    status = kStatusFailure;
118  }
119
120  CompleteAttempt(status);
121}
122
123}  // namespace shill
124