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 
32 using base::Bind;
33 using base::Callback;
34 using std::vector;
35 using std::string;
36 
37 namespace shill {
38 
39 // static
40 const char DNSServerTester::kDNSTestHostname[] = "www.gstatic.com";
41 // static
42 const int DNSServerTester::kDNSTestRetryIntervalMilliseconds = 60000;
43 // static
44 const int DNSServerTester::kDNSTimeoutMilliseconds = 5000;
45 
DNSServerTester(ConnectionRefPtr connection,EventDispatcher * dispatcher,const vector<string> & dns_servers,const bool retry_until_success,const Callback<void (const Status)> & callback)46 DNSServerTester::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 
~DNSServerTester()66 DNSServerTester::~DNSServerTester() {
67   Stop();
68 }
69 
Start()70 void DNSServerTester::Start() {
71   // Stop existing attempt.
72   Stop();
73   // Schedule the test to start immediately.
74   StartAttempt(0);
75 }
76 
StartAttempt(int delay_ms)77 void 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 
StartAttemptTask()83 void 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 
Stop()92 void DNSServerTester::Stop() {
93   start_attempt_.Cancel();
94   StopAttempt();
95 }
96 
StopAttempt()97 void DNSServerTester::StopAttempt() {
98   if (dns_test_client_.get()) {
99     dns_test_client_->Stop();
100   }
101 }
102 
CompleteAttempt(Status status)103 void 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 
DNSClientCallback(const Error & error,const IPAddress & ip)113 void 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