Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: net/dns/dns_transaction.cc

Issue 8762001: Isolates generic DnsClient from AsyncHostResolver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: retrying to fix status of dns_session.h Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/dns/dns_transaction.h ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/dns/dns_transaction.h" 5 #include "net/dns/dns_transaction.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/rand_util.h" 8 #include "base/rand_util.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "net/base/dns_util.h"
11 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h" 11 #include "net/base/net_errors.h"
12 #include "net/dns/dns_protocol.h"
13 #include "net/dns/dns_query.h" 13 #include "net/dns/dns_query.h"
14 #include "net/dns/dns_response.h" 14 #include "net/dns/dns_response.h"
15 #include "net/dns/dns_session.h"
15 #include "net/socket/client_socket_factory.h" 16 #include "net/socket/client_socket_factory.h"
16 #include "net/udp/datagram_client_socket.h" 17 #include "net/udp/datagram_client_socket.h"
17 18
18 namespace net { 19 namespace net {
19 20
20 namespace { 21 namespace {
21 22
22 // Retry timeouts.
23 const int kTimeoutsMs[] = {3000, 5000, 11000};
24 const int kMaxAttempts = arraysize(kTimeoutsMs);
25
26 // Returns the string representation of an IPAddressNumber.
27 std::string IPAddressToString(const IPAddressNumber& ip_address) {
28 IPEndPoint ip_endpoint(ip_address, 0);
29 struct sockaddr_storage addr;
30 size_t addr_len = sizeof(addr);
31 struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr);
32 if (!ip_endpoint.ToSockAddr(sockaddr, &addr_len))
33 return "";
34 return NetAddressToString(sockaddr, addr_len);
35 }
36
37 }
38
39 DnsTransaction::Delegate::Delegate() {
40 }
41
42 DnsTransaction::Delegate::~Delegate() {
43 while (!registered_transactions_.empty()) {
44 DnsTransaction* transaction = *registered_transactions_.begin();
45 transaction->SetDelegate(NULL);
46 }
47 DCHECK(registered_transactions_.empty());
48 }
49
50 void DnsTransaction::Delegate::OnTransactionComplete(
51 int result,
52 const DnsTransaction* transaction,
53 const IPAddressList& ip_addresses) {
54 }
55
56 void DnsTransaction::Delegate::Attach(DnsTransaction* transaction) {
57 DCHECK(registered_transactions_.find(transaction) ==
58 registered_transactions_.end());
59 registered_transactions_.insert(transaction);
60 }
61
62 void DnsTransaction::Delegate::Detach(DnsTransaction* transaction) {
63 DCHECK(registered_transactions_.find(transaction) !=
64 registered_transactions_.end());
65 registered_transactions_.erase(transaction);
66 }
67
68 namespace {
69
70 class DnsTransactionStartParameters : public NetLog::EventParameters { 23 class DnsTransactionStartParameters : public NetLog::EventParameters {
71 public: 24 public:
72 DnsTransactionStartParameters(const IPEndPoint& dns_server, 25 DnsTransactionStartParameters(const IPEndPoint& dns_server,
73 const DnsTransaction::Key& key, 26 const base::StringPiece& qname,
27 uint16 qtype,
74 const NetLog::Source& source) 28 const NetLog::Source& source)
75 : dns_server_(dns_server), key_(key), source_(source) {} 29 : dns_server_(dns_server),
30 qname_(qname.data(), qname.length()),
31 qtype_(qtype),
32 source_(source) {}
76 33
77 virtual Value* ToValue() const { 34 virtual Value* ToValue() const {
78 std::string hostname;
79 DnsResponseBuffer(
80 reinterpret_cast<const uint8*>(key_.first.c_str()), key_.first.size()).
81 DNSName(&hostname);
82
83 DictionaryValue* dict = new DictionaryValue(); 35 DictionaryValue* dict = new DictionaryValue();
84 dict->SetString("dns_server", dns_server_.ToString()); 36 dict->SetString("dns_server", dns_server_.ToString());
85 dict->SetString("hostname", hostname); 37 dict->SetString("hostname", qname_);
86 dict->SetInteger("query_type", key_.second); 38 dict->SetInteger("query_type", qtype_);
87 if (source_.is_valid()) 39 if (source_.is_valid())
88 dict->Set("source_dependency", source_.ToValue()); 40 dict->Set("source_dependency", source_.ToValue());
89 return dict; 41 return dict;
90 } 42 }
91 43
92 private: 44 private:
93 const IPEndPoint dns_server_; 45 IPEndPoint dns_server_;
94 const DnsTransaction::Key key_; 46 std::string qname_;
47 uint16 qtype_;
95 const NetLog::Source source_; 48 const NetLog::Source source_;
96 }; 49 };
97 50
98 class DnsTransactionFinishParameters : public NetLog::EventParameters { 51 class DnsTransactionFinishParameters : public NetLog::EventParameters {
99 public: 52 public:
100 DnsTransactionFinishParameters(int net_error, 53 // TODO(szym): add rcode ?
101 const IPAddressList& ip_address_list) 54 DnsTransactionFinishParameters(int net_error, int answer_count)
102 : net_error_(net_error), ip_address_list_(ip_address_list) {} 55 : net_error_(net_error), answer_count_(answer_count) {}
103 56
104 virtual Value* ToValue() const { 57 virtual Value* ToValue() const {
105 ListValue* list = new ListValue();
106 for (IPAddressList::const_iterator it = ip_address_list_.begin();
107 it != ip_address_list_.end(); ++it)
108 list->Append(Value::CreateStringValue(IPAddressToString(*it)));
109
110 DictionaryValue* dict = new DictionaryValue(); 58 DictionaryValue* dict = new DictionaryValue();
111 if (net_error_) 59 if (net_error_)
112 dict->SetInteger("net_error", net_error_); 60 dict->SetInteger("net_error", net_error_);
113 dict->Set("address_list", list); 61 dict->SetInteger("answer_count", answer_count_);
114 return dict; 62 return dict;
115 } 63 }
116 64
117 private: 65 private:
118 const int net_error_; 66 const int net_error_;
119 const IPAddressList ip_address_list_; 67 const int answer_count_;
120 }; 68 };
121 69
122 class DnsTransactionRetryParameters : public NetLog::EventParameters { 70 class DnsTransactionRetryParameters : public NetLog::EventParameters {
123 public: 71 public:
124 DnsTransactionRetryParameters(int attempt_number, 72 DnsTransactionRetryParameters(int attempt_number,
125 const NetLog::Source& source) 73 const NetLog::Source& source)
126 : attempt_number_(attempt_number), source_(source) {} 74 : attempt_number_(attempt_number), source_(source) {}
127 75
128 virtual Value* ToValue() const { 76 virtual Value* ToValue() const {
129 DictionaryValue* dict = new DictionaryValue(); 77 DictionaryValue* dict = new DictionaryValue();
130 dict->SetInteger("attempt_number", attempt_number_); 78 dict->SetInteger("attempt_number", attempt_number_);
131 dict->Set("source_dependency", source_.ToValue()); 79 dict->Set("source_dependency", source_.ToValue());
132 return dict; 80 return dict;
133 } 81 }
134 82
135 private: 83 private:
136 const int attempt_number_; 84 const int attempt_number_;
137 const NetLog::Source source_; 85 const NetLog::Source source_;
138 }; 86 };
139 87
140 } // namespace 88 } // namespace
141 89
142 DnsTransaction::DnsTransaction(const IPEndPoint& dns_server, 90
143 const std::string& dns_name, 91 DnsTransaction::DnsTransaction(DnsSession* session,
144 uint16 query_type, 92 const base::StringPiece& qname,
145 const RandIntCallback& rand_int, 93 uint16 qtype,
146 ClientSocketFactory* socket_factory, 94 const ResultCallback& callback,
147 const BoundNetLog& source_net_log, 95 const BoundNetLog& source_net_log)
148 NetLog* net_log) 96 : session_(session),
149 : dns_server_(dns_server), 97 dns_server_(session->NextServer()),
150 key_(dns_name, query_type), 98 query_(new DnsQuery(session->NextId(), qname, qtype)),
151 delegate_(NULL), 99 callback_(callback),
152 query_(new DnsQuery(dns_name, query_type, rand_int)),
153 attempts_(0), 100 attempts_(0),
154 next_state_(STATE_NONE), 101 next_state_(STATE_NONE),
155 socket_factory_(socket_factory ? socket_factory :
156 ClientSocketFactory::GetDefaultFactory()),
157 ALLOW_THIS_IN_INITIALIZER_LIST( 102 ALLOW_THIS_IN_INITIALIZER_LIST(
158 io_callback_(this, &DnsTransaction::OnIOComplete)), 103 io_callback_(this, &DnsTransaction::OnIOComplete)),
159 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_DNS_TRANSACTION)) { 104 net_log_(BoundNetLog::Make(session->net_log(),
160 DCHECK(!rand_int.is_null()); 105 NetLog::SOURCE_DNS_TRANSACTION)) {
161 for (size_t i = 0; i < arraysize(kTimeoutsMs); ++i)
162 timeouts_ms_.push_back(base::TimeDelta::FromMilliseconds(kTimeoutsMs[i]));
163 net_log_.BeginEvent( 106 net_log_.BeginEvent(
164 NetLog::TYPE_DNS_TRANSACTION, 107 NetLog::TYPE_DNS_TRANSACTION,
165 make_scoped_refptr( 108 make_scoped_refptr(
166 new DnsTransactionStartParameters(dns_server_, key_, 109 new DnsTransactionStartParameters(dns_server_,
110 qname,
111 qtype,
167 source_net_log.source()))); 112 source_net_log.source())));
168 } 113 }
169 114
170 DnsTransaction::~DnsTransaction() { 115 DnsTransaction::~DnsTransaction() {}
171 SetDelegate(NULL);
172 }
173
174 void DnsTransaction::SetDelegate(Delegate* delegate) {
175 if (delegate == delegate_)
176 return;
177 if (delegate_)
178 delegate_->Detach(this);
179 delegate_ = delegate;
180 if (delegate_)
181 delegate_->Attach(this);
182 }
183 116
184 int DnsTransaction::Start() { 117 int DnsTransaction::Start() {
185 DCHECK_EQ(STATE_NONE, next_state_); 118 DCHECK_EQ(STATE_NONE, next_state_);
186 next_state_ = STATE_CONNECT; 119 next_state_ = STATE_CONNECT;
187 return DoLoop(OK); 120 return DoLoop(OK);
188 } 121 }
189 122
190 int DnsTransaction::DoLoop(int result) { 123 int DnsTransaction::DoLoop(int result) {
191 DCHECK_NE(STATE_NONE, next_state_); 124 DCHECK_NE(STATE_NONE, next_state_);
192 int rv = result; 125 int rv = result;
(...skipping 23 matching lines...) Expand all
216 NOTREACHED(); 149 NOTREACHED();
217 break; 150 break;
218 } 151 }
219 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 152 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
220 153
221 return rv; 154 return rv;
222 } 155 }
223 156
224 void DnsTransaction::DoCallback(int result) { 157 void DnsTransaction::DoCallback(int result) {
225 DCHECK_NE(result, ERR_IO_PENDING); 158 DCHECK_NE(result, ERR_IO_PENDING);
159 int answer_count = (result == OK) ? response()->answer_count() : 0;
226 net_log_.EndEvent( 160 net_log_.EndEvent(
227 NetLog::TYPE_DNS_TRANSACTION, 161 NetLog::TYPE_DNS_TRANSACTION,
228 make_scoped_refptr( 162 make_scoped_refptr(
229 new DnsTransactionFinishParameters(result, ip_addresses_))); 163 new DnsTransactionFinishParameters(result, answer_count)));
230 if (delegate_) 164 callback_.Run(this, result);
231 delegate_->OnTransactionComplete(result, this, ip_addresses_);
232 } 165 }
233 166
234 void DnsTransaction::OnIOComplete(int result) { 167 void DnsTransaction::OnIOComplete(int result) {
235 int rv = DoLoop(result); 168 int rv = DoLoop(result);
236 if (rv != ERR_IO_PENDING) 169 if (rv != ERR_IO_PENDING)
237 DoCallback(rv); 170 DoCallback(rv);
238 } 171 }
239 172
240 int DnsTransaction::DoConnect() { 173 int DnsTransaction::DoConnect() {
241 next_state_ = STATE_CONNECT_COMPLETE; 174 next_state_ = STATE_CONNECT_COMPLETE;
242 175
243 DCHECK_LT(attempts_, timeouts_ms_.size()); 176 StartTimer(session_->NextTimeout(attempts_));
244 StartTimer(timeouts_ms_[attempts_]); 177 ++attempts_;
245 attempts_++;
246 178
247 // TODO(agayev): keep all sockets around in case the server responds 179 // TODO(szym): keep all sockets around in case the server responds
248 // after its timeout; state machine will need to change to handle that. 180 // after its timeout; state machine will need to change to handle that.
249 socket_.reset(socket_factory_->CreateDatagramClientSocket( 181 // The current plan is to move socket management out to DnsSession.
182 // Hence also move retransmissions to DnsClient::Request.
183 socket_.reset(session_->socket_factory()->CreateDatagramClientSocket(
250 DatagramSocket::RANDOM_BIND, 184 DatagramSocket::RANDOM_BIND,
251 base::Bind(&base::RandInt), 185 base::Bind(&base::RandInt),
252 net_log_.net_log(), 186 net_log_.net_log(),
253 net_log_.source())); 187 net_log_.source()));
254 188
255 net_log_.AddEvent( 189 net_log_.AddEvent(
256 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED, 190 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED,
257 make_scoped_refptr( 191 make_scoped_refptr(
258 new DnsTransactionRetryParameters(attempts_, 192 new DnsTransactionRetryParameters(attempts_,
259 socket_->NetLog().source()))); 193 socket_->NetLog().source())));
(...skipping 14 matching lines...) Expand all
274 query_->io_buffer()->size(), 208 query_->io_buffer()->size(),
275 &io_callback_); 209 &io_callback_);
276 } 210 }
277 211
278 int DnsTransaction::DoSendQueryComplete(int rv) { 212 int DnsTransaction::DoSendQueryComplete(int rv) {
279 if (rv < 0) 213 if (rv < 0)
280 return rv; 214 return rv;
281 215
282 // Writing to UDP should not result in a partial datagram. 216 // Writing to UDP should not result in a partial datagram.
283 if (rv != query_->io_buffer()->size()) 217 if (rv != query_->io_buffer()->size())
284 return ERR_NAME_NOT_RESOLVED; 218 return ERR_MSG_TOO_BIG;
285 219
286 next_state_ = STATE_READ_RESPONSE; 220 next_state_ = STATE_READ_RESPONSE;
287 return OK; 221 return OK;
288 } 222 }
289 223
290 int DnsTransaction::DoReadResponse() { 224 int DnsTransaction::DoReadResponse() {
291 next_state_ = STATE_READ_RESPONSE_COMPLETE; 225 next_state_ = STATE_READ_RESPONSE_COMPLETE;
292 response_.reset(new DnsResponse(query_.get())); 226 response_.reset(new DnsResponse());
293 return socket_->Read(response_->io_buffer(), 227 return socket_->Read(response_->io_buffer(),
294 response_->io_buffer()->size(), 228 response_->io_buffer()->size(),
295 &io_callback_); 229 &io_callback_);
296 } 230 }
297 231
298 int DnsTransaction::DoReadResponseComplete(int rv) { 232 int DnsTransaction::DoReadResponseComplete(int rv) {
299 DCHECK_NE(ERR_IO_PENDING, rv); 233 DCHECK_NE(ERR_IO_PENDING, rv);
300 RevokeTimer(); 234 RevokeTimer();
301 if (rv < 0) 235 if (rv < 0)
302 return rv; 236 return rv;
303 237
304 DCHECK(rv); 238 DCHECK(rv);
305 // TODO(agayev): when supporting EDNS0 we may need to do multiple reads 239 if (!response_->InitParse(rv, *query_))
306 // to read the whole response. 240 return ERR_DNS_MALFORMED_RESPONSE;
307 return response_->Parse(rv, &ip_addresses_); 241 // TODO(szym): define this flag value in dns_protocol
242 if (response_->flags1() & 2)
243 return ERR_DNS_SERVER_REQUIRES_TCP;
244 // TODO(szym): move this handling out of DnsTransaction?
245 if (response_->rcode() != dns_protocol::kRcodeNOERROR &&
246 response_->rcode() != dns_protocol::kRcodeNXDOMAIN) {
247 return ERR_DNS_SERVER_FAILED;
248 }
249 // TODO(szym): add ERR_DNS_RR_NOT_FOUND?
250 if (response_->answer_count() == 0)
251 return ERR_NAME_NOT_RESOLVED;
252
253 return OK;
308 } 254 }
309 255
310 void DnsTransaction::StartTimer(base::TimeDelta delay) { 256 void DnsTransaction::StartTimer(base::TimeDelta delay) {
311 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout); 257 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout);
312 } 258 }
313 259
314 void DnsTransaction::RevokeTimer() { 260 void DnsTransaction::RevokeTimer() {
315 timer_.Stop(); 261 timer_.Stop();
316 } 262 }
317 263
318 void DnsTransaction::OnTimeout() { 264 void DnsTransaction::OnTimeout() {
319 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || 265 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE ||
320 next_state_ == STATE_READ_RESPONSE_COMPLETE); 266 next_state_ == STATE_READ_RESPONSE_COMPLETE);
321 if (attempts_ == timeouts_ms_.size()) { 267 if (attempts_ == session_->config().attempts) {
322 DoCallback(ERR_DNS_TIMED_OUT); 268 DoCallback(ERR_DNS_TIMED_OUT);
323 return; 269 return;
324 } 270 }
325 next_state_ = STATE_CONNECT; 271 next_state_ = STATE_CONNECT;
326 query_.reset(query_->CloneWithNewId()); 272 query_.reset(query_->CloneWithNewId(session_->NextId()));
327 int rv = DoLoop(OK); 273 int rv = DoLoop(OK);
328 if (rv != ERR_IO_PENDING) 274 if (rv != ERR_IO_PENDING)
329 DoCallback(rv); 275 DoCallback(rv);
330 } 276 }
331 277
332 void DnsTransaction::set_timeouts_ms(
333 const std::vector<base::TimeDelta>& timeouts_ms) {
334 DCHECK_EQ(0u, attempts_);
335 timeouts_ms_ = timeouts_ms;
336 }
337
338 } // namespace net 278 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_transaction.h ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698