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

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

Issue 11567031: [net/dns] Handle TC bit on DNS response in DnsTransaction. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: respond to 2nd review Created 8 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_socket_pool.cc ('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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <deque> 7 #include <deque>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/memory/ref_counted.h" 12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h" 14 #include "base/memory/scoped_vector.h"
15 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop.h" 16 #include "base/message_loop.h"
17 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "base/rand_util.h" 18 #include "base/rand_util.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/string_piece.h" 20 #include "base/string_piece.h"
21 #include "base/threading/non_thread_safe.h" 21 #include "base/threading/non_thread_safe.h"
22 #include "base/timer.h" 22 #include "base/timer.h"
23 #include "base/values.h" 23 #include "base/values.h"
24 #include "net/base/big_endian.h"
24 #include "net/base/completion_callback.h" 25 #include "net/base/completion_callback.h"
25 #include "net/base/dns_util.h" 26 #include "net/base/dns_util.h"
26 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
27 #include "net/base/ip_endpoint.h" 28 #include "net/base/ip_endpoint.h"
28 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
29 #include "net/base/net_log.h" 30 #include "net/base/net_log.h"
30 #include "net/dns/dns_protocol.h" 31 #include "net/dns/dns_protocol.h"
31 #include "net/dns/dns_query.h" 32 #include "net/dns/dns_query.h"
32 #include "net/dns/dns_response.h" 33 #include "net/dns/dns_response.h"
33 #include "net/dns/dns_session.h" 34 #include "net/dns/dns_session.h"
35 #include "net/socket/stream_socket.h"
34 #include "net/udp/datagram_client_socket.h" 36 #include "net/udp/datagram_client_socket.h"
35 37
36 namespace net { 38 namespace net {
37 39
38 namespace { 40 namespace {
39 41
40 // Provide a common macro to simplify code and readability. We must use a 42 // Provide a common macro to simplify code and readability. We must use a
41 // macro as the underlying HISTOGRAM macro creates static variables. 43 // macro as the underlying HISTOGRAM macro creates static variables.
42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 44 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
43 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) 45 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
(...skipping 15 matching lines...) Expand all
59 uint16 qtype, 61 uint16 qtype,
60 NetLog::LogLevel /* log_level */) { 62 NetLog::LogLevel /* log_level */) {
61 DictionaryValue* dict = new DictionaryValue(); 63 DictionaryValue* dict = new DictionaryValue();
62 dict->SetString("hostname", *hostname); 64 dict->SetString("hostname", *hostname);
63 dict->SetInteger("query_type", qtype); 65 dict->SetInteger("query_type", qtype);
64 return dict; 66 return dict;
65 }; 67 };
66 68
67 // ---------------------------------------------------------------------------- 69 // ----------------------------------------------------------------------------
68 70
69 // A single asynchronous DNS exchange over UDP, which consists of sending out a 71 // A single asynchronous DNS exchange, which consists of sending out a
70 // DNS query, waiting for a response, and returning the response that it 72 // DNS query, waiting for a response, and returning the response that it
71 // matches. Logging is done in the socket and in the outer DnsTransaction. 73 // matches. Logging is done in the socket and in the outer DnsTransaction.
72 class DnsUDPAttempt { 74 class DnsAttempt {
75 public:
76 virtual ~DnsAttempt() {}
77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
78 // and calls |callback| upon completion.
79 virtual int Start(const CompletionCallback& callback) = 0;
80
81 // Returns the query of this attempt.
82 virtual const DnsQuery* GetQuery() const = 0;
83
84 // Returns the response or NULL if has not received a matching response from
85 // the server.
86 virtual const DnsResponse* GetResponse() const = 0;
87
88 // Returns the net log bound to the source of the socket.
89 virtual const BoundNetLog& GetSocketNetLog() const = 0;
90
91 // Returns the index of the destination server within DnsConfig::nameservers.
92 virtual unsigned GetServerIndex() const = 0;
93
94 // Returns a Value representing the received response, along with a reference
95 // to the NetLog source source of the UDP socket used. The request must have
96 // completed before this is called.
97 Value* NetLogResponseCallback(NetLog::LogLevel log_level) const {
98 DCHECK(GetResponse()->IsValid());
99
100 DictionaryValue* dict = new DictionaryValue();
101 dict->SetInteger("rcode", GetResponse()->rcode());
102 dict->SetInteger("answer_count", GetResponse()->answer_count());
103 GetSocketNetLog().source().AddToEventParameters(dict);
104 return dict;
105 }
106 };
107
108 class DnsUDPAttempt : public DnsAttempt {
73 public: 109 public:
74 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, 110 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease,
75 scoped_ptr<DnsQuery> query, 111 scoped_ptr<DnsQuery> query)
76 const CompletionCallback& callback)
77 : next_state_(STATE_NONE), 112 : next_state_(STATE_NONE),
78 received_malformed_response_(false), 113 received_malformed_response_(false),
79 socket_lease_(socket_lease.Pass()), 114 socket_lease_(socket_lease.Pass()),
80 query_(query.Pass()), 115 query_(query.Pass()) {
81 callback_(callback) {
82 } 116 }
83 117
84 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 118 // DnsAttempt:
85 // and calls |callback| upon completion. 119 virtual int Start(const CompletionCallback& callback) OVERRIDE {
86 int Start() {
87 DCHECK_EQ(STATE_NONE, next_state_); 120 DCHECK_EQ(STATE_NONE, next_state_);
121 callback_ = callback;
88 start_time_ = base::TimeTicks::Now(); 122 start_time_ = base::TimeTicks::Now();
89 next_state_ = STATE_SEND_QUERY; 123 next_state_ = STATE_SEND_QUERY;
90 return DoLoop(OK); 124 return DoLoop(OK);
91 } 125 }
92 126
93 const DnsQuery* query() const { 127 virtual const DnsQuery* GetQuery() const OVERRIDE {
94 return query_.get(); 128 return query_.get();
95 } 129 }
96 130
97 const BoundNetLog& socket_net_log() const { 131 virtual const DnsResponse* GetResponse() const OVERRIDE {
98 return socket_lease_->socket()->NetLog();
99 }
100
101 // Returns the response or NULL if has not received a matching response from
102 // the server.
103 const DnsResponse* response() const {
104 const DnsResponse* resp = response_.get(); 132 const DnsResponse* resp = response_.get();
105 return (resp != NULL && resp->IsValid()) ? resp : NULL; 133 return (resp != NULL && resp->IsValid()) ? resp : NULL;
106 } 134 }
107 135
108 // Returns a Value representing the received response, along with a reference 136 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
109 // to the NetLog source source of the UDP socket used. The request must have 137 return socket_lease_->socket()->NetLog();
110 // completed before this is called. 138 }
111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
112 DCHECK(response_->IsValid());
113 139
114 DictionaryValue* dict = new DictionaryValue(); 140 virtual unsigned GetServerIndex() const OVERRIDE {
115 dict->SetInteger("rcode", response_->rcode()); 141 return socket_lease_->server_index();
116 dict->SetInteger("answer_count", response_->answer_count());
117 socket_net_log().source().AddToEventParameters(dict);
118 return dict;
119 } 142 }
120 143
121 private: 144 private:
122 enum State { 145 enum State {
123 STATE_SEND_QUERY, 146 STATE_SEND_QUERY,
124 STATE_SEND_QUERY_COMPLETE, 147 STATE_SEND_QUERY_COMPLETE,
125 STATE_READ_RESPONSE, 148 STATE_READ_RESPONSE,
126 STATE_READ_RESPONSE_COMPLETE, 149 STATE_READ_RESPONSE_COMPLETE,
127 STATE_NONE, 150 STATE_NONE,
128 }; 151 };
(...skipping 24 matching lines...) Expand all
153 default: 176 default:
154 NOTREACHED(); 177 NOTREACHED();
155 break; 178 break;
156 } 179 }
157 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 180 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
158 // If we received a malformed response, and are now waiting for another one, 181 // If we received a malformed response, and are now waiting for another one,
159 // indicate to the transaction that the server might be misbehaving. 182 // indicate to the transaction that the server might be misbehaving.
160 if (rv == ERR_IO_PENDING && received_malformed_response_) 183 if (rv == ERR_IO_PENDING && received_malformed_response_)
161 return ERR_DNS_MALFORMED_RESPONSE; 184 return ERR_DNS_MALFORMED_RESPONSE;
162 if (rv == OK) { 185 if (rv == OK) {
186 DCHECK_EQ(STATE_NONE, next_state_);
163 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess", 187 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
164 base::TimeTicks::Now() - start_time_); 188 base::TimeTicks::Now() - start_time_);
165 } else if (rv != ERR_IO_PENDING) { 189 } else if (rv != ERR_IO_PENDING) {
166 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", 190 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
167 base::TimeTicks::Now() - start_time_); 191 base::TimeTicks::Now() - start_time_);
168 } 192 }
169 return rv; 193 return rv;
170 } 194 }
171 195
172 int DoSendQuery() { 196 int DoSendQuery() {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 return OK; 240 return OK;
217 } 241 }
218 if (response_->flags() & dns_protocol::kFlagTC) 242 if (response_->flags() & dns_protocol::kFlagTC)
219 return ERR_DNS_SERVER_REQUIRES_TCP; 243 return ERR_DNS_SERVER_REQUIRES_TCP;
220 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 244 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
221 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 245 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
222 return ERR_NAME_NOT_RESOLVED; 246 return ERR_NAME_NOT_RESOLVED;
223 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 247 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
224 return ERR_DNS_SERVER_FAILED; 248 return ERR_DNS_SERVER_FAILED;
225 249
226 CHECK(response());
227 return OK; 250 return OK;
228 } 251 }
229 252
230 void OnIOComplete(int rv) { 253 void OnIOComplete(int rv) {
231 rv = DoLoop(rv); 254 rv = DoLoop(rv);
232 if (rv != ERR_IO_PENDING) 255 if (rv != ERR_IO_PENDING)
233 callback_.Run(rv); 256 callback_.Run(rv);
234 } 257 }
235 258
236 State next_state_; 259 State next_state_;
237 bool received_malformed_response_; 260 bool received_malformed_response_;
238 base::TimeTicks start_time_; 261 base::TimeTicks start_time_;
239 262
240 scoped_ptr<DnsSession::SocketLease> socket_lease_; 263 scoped_ptr<DnsSession::SocketLease> socket_lease_;
241 scoped_ptr<DnsQuery> query_; 264 scoped_ptr<DnsQuery> query_;
242 265
243 scoped_ptr<DnsResponse> response_; 266 scoped_ptr<DnsResponse> response_;
244 267
245 CompletionCallback callback_; 268 CompletionCallback callback_;
246 269
247 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 270 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
248 }; 271 };
249 272
273 class DnsTCPAttempt : public DnsAttempt {
274 public:
275 DnsTCPAttempt(scoped_ptr<StreamSocket> socket,
276 scoped_ptr<DnsQuery> query)
277 : next_state_(STATE_NONE),
278 socket_(socket.Pass()),
279 query_(query.Pass()),
280 length_buffer_(new IOBufferWithSize(sizeof(uint16))),
281 response_length_(0) {
282 }
283
284 // DnsAttempt:
285 virtual int Start(const CompletionCallback& callback) OVERRIDE {
286 DCHECK_EQ(STATE_NONE, next_state_);
287 callback_ = callback;
288 start_time_ = base::TimeTicks::Now();
289 next_state_ = STATE_CONNECT_COMPLETE;
290 int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
291 base::Unretained(this)));
292 if (rv == ERR_IO_PENDING)
293 return rv;
294 return DoLoop(rv);
295 }
296
297 virtual const DnsQuery* GetQuery() const OVERRIDE {
298 return query_.get();
299 }
300
301 virtual const DnsResponse* GetResponse() const OVERRIDE {
302 const DnsResponse* resp = response_.get();
303 return (resp != NULL && resp->IsValid()) ? resp : NULL;
304 }
305
306 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
307 return socket_->NetLog();
308 }
309
310 virtual unsigned GetServerIndex() const OVERRIDE {
311 NOTREACHED();
312 return 0;
313 }
314
315 private:
316 enum State {
317 STATE_CONNECT_COMPLETE,
318 STATE_SEND_LENGTH,
319 STATE_SEND_QUERY,
320 STATE_READ_LENGTH,
321 STATE_READ_RESPONSE,
322 STATE_NONE,
323 };
324
325 int DoLoop(int result) {
326 CHECK_NE(STATE_NONE, next_state_);
327 int rv = result;
328 do {
329 State state = next_state_;
330 next_state_ = STATE_NONE;
331 switch (state) {
332 case STATE_CONNECT_COMPLETE:
333 rv = DoConnectComplete(rv);
334 break;
335 case STATE_SEND_LENGTH:
336 rv = DoSendLength(rv);
337 break;
338 case STATE_SEND_QUERY:
339 rv = DoSendQuery(rv);
340 break;
341 case STATE_READ_LENGTH:
342 rv = DoReadLength(rv);
343 break;
344 case STATE_READ_RESPONSE:
345 rv = DoReadResponse(rv);
346 break;
347 default:
348 NOTREACHED();
349 break;
350 }
351 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
352 if (rv == OK) {
353 DCHECK_EQ(STATE_NONE, next_state_);
354 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
355 base::TimeTicks::Now() - start_time_);
356 } else if (rv != ERR_IO_PENDING) {
357 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
358 base::TimeTicks::Now() - start_time_);
359 }
360 return rv;
361 }
362
363 int DoConnectComplete(int rv) {
364 DCHECK_NE(ERR_IO_PENDING, rv);
365 if (rv < 0)
366 return rv;
367
368 WriteBigEndian<uint16>(length_buffer_->data(), query_->io_buffer()->size());
369 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
370 next_state_ = STATE_SEND_LENGTH;
371 return OK;
372 }
373
374 int DoSendLength(int rv) {
375 DCHECK_NE(ERR_IO_PENDING, rv);
376 if (rv < 0)
377 return rv;
378
379 buffer_->DidConsume(rv);
380 if (buffer_->BytesRemaining() > 0) {
381 next_state_ = STATE_SEND_LENGTH;
382 return socket_->Write(buffer_,
383 buffer_->BytesRemaining(),
384 base::Bind(&DnsTCPAttempt::OnIOComplete,
385 base::Unretained(this)));
386 }
387 buffer_ = new DrainableIOBuffer(query_->io_buffer(),
388 query_->io_buffer()->size());
389 next_state_ = STATE_SEND_QUERY;
390 return OK;
391 }
392
393 int DoSendQuery(int rv) {
394 DCHECK_NE(ERR_IO_PENDING, rv);
395 if (rv < 0)
396 return rv;
397
398 buffer_->DidConsume(rv);
399 if (buffer_->BytesRemaining() > 0) {
400 next_state_ = STATE_SEND_QUERY;
401 return socket_->Write(buffer_,
402 buffer_->BytesRemaining(),
403 base::Bind(&DnsTCPAttempt::OnIOComplete,
404 base::Unretained(this)));
405 }
406 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
407 next_state_ = STATE_READ_LENGTH;
408 return OK;
409 }
410
411 int DoReadLength(int rv) {
412 DCHECK_NE(ERR_IO_PENDING, rv);
413 if (rv < 0)
414 return rv;
415
416 buffer_->DidConsume(rv);
417 if (buffer_->BytesRemaining() > 0) {
418 next_state_ = STATE_READ_LENGTH;
419 return socket_->Read(buffer_,
420 buffer_->BytesRemaining(),
421 base::Bind(&DnsTCPAttempt::OnIOComplete,
422 base::Unretained(this)));
423 }
424 ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
425 // Check if advertised response is too short. (Optimization only.)
426 if (response_length_ < query_->io_buffer()->size())
427 return ERR_DNS_MALFORMED_RESPONSE;
428 // Allocate more space so that DnsResponse::InitParse sanity check passes.
429 response_.reset(new DnsResponse(response_length_ + 1));
430 buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
431 next_state_ = STATE_READ_RESPONSE;
432 return OK;
433 }
434
435 int DoReadResponse(int rv) {
436 DCHECK_NE(ERR_IO_PENDING, rv);
437 if (rv < 0)
438 return rv;
439
440 buffer_->DidConsume(rv);
441 if (buffer_->BytesRemaining() > 0) {
442 next_state_ = STATE_READ_RESPONSE;
443 return socket_->Read(buffer_,
444 buffer_->BytesRemaining(),
445 base::Bind(&DnsTCPAttempt::OnIOComplete,
446 base::Unretained(this)));
447 }
448 if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
449 return ERR_DNS_MALFORMED_RESPONSE;
450 if (response_->flags() & dns_protocol::kFlagTC)
451 return ERR_UNEXPECTED;
452 // TODO(szym): Frankly, none of these are expected.
453 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
454 return ERR_NAME_NOT_RESOLVED;
455 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
456 return ERR_DNS_SERVER_FAILED;
457
458 return OK;
459 }
460
461 void OnIOComplete(int rv) {
462 rv = DoLoop(rv);
463 if (rv != ERR_IO_PENDING)
464 callback_.Run(rv);
465 }
466
467 State next_state_;
468 base::TimeTicks start_time_;
469
470 scoped_ptr<StreamSocket> socket_;
471 scoped_ptr<DnsQuery> query_;
472 scoped_refptr<IOBufferWithSize> length_buffer_;
473 scoped_refptr<DrainableIOBuffer> buffer_;
474
475 uint16 response_length_;
476 scoped_ptr<DnsResponse> response_;
477
478 CompletionCallback callback_;
479
480 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
481 };
482
250 // ---------------------------------------------------------------------------- 483 // ----------------------------------------------------------------------------
251 484
252 // Implements DnsTransaction. Configuration is supplied by DnsSession. 485 // Implements DnsTransaction. Configuration is supplied by DnsSession.
253 // The suffix list is built according to the DnsConfig from the session. 486 // The suffix list is built according to the DnsConfig from the session.
254 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. 487 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
255 // The first server to attempt on each query is given by 488 // The first server to attempt on each query is given by
256 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. 489 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
257 // Each server is attempted DnsConfig::attempts times. 490 // Each server is attempted DnsConfig::attempts times.
258 class DnsTransactionImpl : public DnsTransaction, 491 class DnsTransactionImpl : public DnsTransaction,
259 public base::NonThreadSafe, 492 public base::NonThreadSafe,
260 public base::SupportsWeakPtr<DnsTransactionImpl> { 493 public base::SupportsWeakPtr<DnsTransactionImpl> {
261 public: 494 public:
262 DnsTransactionImpl(DnsSession* session, 495 DnsTransactionImpl(DnsSession* session,
263 const std::string& hostname, 496 const std::string& hostname,
264 uint16 qtype, 497 uint16 qtype,
265 const DnsTransactionFactory::CallbackType& callback, 498 const DnsTransactionFactory::CallbackType& callback,
266 const BoundNetLog& net_log) 499 const BoundNetLog& net_log)
267 : session_(session), 500 : session_(session),
268 hostname_(hostname), 501 hostname_(hostname),
269 qtype_(qtype), 502 qtype_(qtype),
270 callback_(callback), 503 callback_(callback),
271 net_log_(net_log), 504 net_log_(net_log),
505 had_tcp_attempt_(false),
272 first_server_index_(0) { 506 first_server_index_(0) {
273 DCHECK(session_); 507 DCHECK(session_);
274 DCHECK(!hostname_.empty()); 508 DCHECK(!hostname_.empty());
275 DCHECK(!callback_.is_null()); 509 DCHECK(!callback_.is_null());
276 DCHECK(!IsIPLiteral(hostname_)); 510 DCHECK(!IsIPLiteral(hostname_));
277 } 511 }
278 512
279 virtual ~DnsTransactionImpl() { 513 virtual ~DnsTransactionImpl() {
280 if (!callback_.is_null()) { 514 if (!callback_.is_null()) {
281 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 515 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 callback_.Reset(); 548 callback_.Reset();
315 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv); 549 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv);
316 } 550 }
317 DCHECK_NE(OK, rv); 551 DCHECK_NE(OK, rv);
318 return rv; 552 return rv;
319 } 553 }
320 554
321 private: 555 private:
322 // Wrapper for the result of a DnsUDPAttempt. 556 // Wrapper for the result of a DnsUDPAttempt.
323 struct AttemptResult { 557 struct AttemptResult {
324 AttemptResult(int rv, const DnsUDPAttempt* attempt) 558 AttemptResult(int rv, const DnsAttempt* attempt)
325 : rv(rv), attempt(attempt) {} 559 : rv(rv), attempt(attempt) {}
326 560
327 int rv; 561 int rv;
328 const DnsUDPAttempt* attempt; 562 const DnsAttempt* attempt;
329 }; 563 };
330 564
331 // Prepares |qnames_| according to the DnsConfig. 565 // Prepares |qnames_| according to the DnsConfig.
332 int PrepareSearch() { 566 int PrepareSearch() {
333 const DnsConfig& config = session_->config(); 567 const DnsConfig& config = session_->config();
334 568
335 std::string labeled_hostname; 569 std::string labeled_hostname;
336 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 570 if (!DNSDomainFromDot(hostname_, &labeled_hostname))
337 return ERR_INVALID_ARGUMENT; 571 return ERR_INVALID_ARGUMENT;
338 572
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 if (ndots > 0 && !had_hostname) 607 if (ndots > 0 && !had_hostname)
374 qnames_.push_back(labeled_hostname); 608 qnames_.push_back(labeled_hostname);
375 609
376 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK; 610 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
377 } 611 }
378 612
379 void DoCallback(AttemptResult result) { 613 void DoCallback(AttemptResult result) {
380 DCHECK(!callback_.is_null()); 614 DCHECK(!callback_.is_null());
381 DCHECK_NE(ERR_IO_PENDING, result.rv); 615 DCHECK_NE(ERR_IO_PENDING, result.rv);
382 const DnsResponse* response = result.attempt ? 616 const DnsResponse* response = result.attempt ?
383 result.attempt->response() : NULL; 617 result.attempt->GetResponse() : NULL;
384 CHECK(result.rv != OK || response != NULL); 618 CHECK(result.rv != OK || response != NULL);
385 619
386 timer_.Stop(); 620 timer_.Stop();
387 621
388 DnsTransactionFactory::CallbackType callback = callback_; 622 DnsTransactionFactory::CallbackType callback = callback_;
389 callback_.Reset(); 623 callback_.Reset();
390 624
391 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 625 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
392 callback.Run(this, result.rv, response); 626 callback.Run(this, result.rv, response);
393 } 627 }
394 628
395 // Makes another attempt at the current name, |qnames_.front()|, using the 629 // Makes another attempt at the current name, |qnames_.front()|, using the
396 // next nameserver. 630 // next nameserver.
397 AttemptResult MakeAttempt() { 631 AttemptResult MakeAttempt() {
398 unsigned attempt_number = attempts_.size(); 632 unsigned attempt_number = attempts_.size();
399 633
400 uint16 id = session_->NextQueryId(); 634 uint16 id = session_->NextQueryId();
401 scoped_ptr<DnsQuery> query; 635 scoped_ptr<DnsQuery> query;
402 if (attempts_.empty()) { 636 if (attempts_.empty()) {
403 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 637 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
404 } else { 638 } else {
405 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 639 query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
406 } 640 }
407 641
408 const DnsConfig& config = session_->config(); 642 const DnsConfig& config = session_->config();
409 643
410 unsigned server_index = first_server_index_ + 644 unsigned server_index = first_server_index_ +
411 (attempt_number % config.nameservers.size()); 645 (attempt_number % config.nameservers.size());
412 646
413 scoped_ptr<DnsSession::SocketLease> lease = 647 scoped_ptr<DnsSession::SocketLease> lease =
414 session_->AllocateSocket(server_index, net_log_.source()); 648 session_->AllocateSocket(server_index, net_log_.source());
415 649
416 bool got_socket = !!lease.get(); 650 bool got_socket = !!lease.get();
417 651
418 DnsUDPAttempt* attempt = new DnsUDPAttempt( 652 DnsUDPAttempt* attempt = new DnsUDPAttempt(lease.Pass(), query.Pass());
419 lease.Pass(),
420 query.Pass(),
421 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
422 base::Unretained(this),
423 attempt_number));
424 653
425 attempts_.push_back(attempt); 654 attempts_.push_back(attempt);
426 655
427 if (!got_socket) 656 if (!got_socket)
428 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 657 return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
429 658
430 net_log_.AddEvent( 659 net_log_.AddEvent(
431 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 660 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
432 attempt->socket_net_log().source().ToEventParametersCallback()); 661 attempt->GetSocketNetLog().source().ToEventParametersCallback());
433 662
434 int rv = attempt->Start(); 663 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
664 base::Unretained(this),
665 attempt_number));
435 if (rv == ERR_IO_PENDING) { 666 if (rv == ERR_IO_PENDING) {
436 timer_.Stop();
437 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 667 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
438 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 668 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
439 } 669 }
440 return AttemptResult(rv, attempt); 670 return AttemptResult(rv, attempt);
441 } 671 }
442 672
673 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
674 DCHECK(previous_attempt);
675 DCHECK(!had_tcp_attempt_);
676
677 scoped_ptr<StreamSocket> socket(
678 session_->CreateTCPSocket(previous_attempt->GetServerIndex(),
679 net_log_.source()));
680
681 // TODO(szym): Reuse the same id to help the server?
682 uint16 id = session_->NextQueryId();
683 scoped_ptr<DnsQuery> query(
684 previous_attempt->GetQuery()->CloneWithNewId(id));
685
686 // Cancel all other attempts, no point waiting on them.
687 attempts_.clear();
688
689 unsigned attempt_number = attempts_.size();
690
691 DnsTCPAttempt* attempt = new DnsTCPAttempt(socket.Pass(), query.Pass());
692
693 attempts_.push_back(attempt);
694 had_tcp_attempt_ = true;
695
696 net_log_.AddEvent(
697 NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
698 attempt->GetSocketNetLog().source().ToEventParametersCallback());
699
700 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
701 base::Unretained(this),
702 attempt_number));
703 if (rv == ERR_IO_PENDING) {
704 // Custom timeout for TCP attempt.
705 base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
706 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
707 }
708 return AttemptResult(rv, attempt);
709 }
710
443 // Begins query for the current name. Makes the first attempt. 711 // Begins query for the current name. Makes the first attempt.
444 AttemptResult StartQuery() { 712 AttemptResult StartQuery() {
445 std::string dotted_qname = DNSDomainToString(qnames_.front()); 713 std::string dotted_qname = DNSDomainToString(qnames_.front());
446 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY, 714 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
447 NetLog::StringCallback("qname", &dotted_qname)); 715 NetLog::StringCallback("qname", &dotted_qname));
448 716
449 first_server_index_ = session_->NextFirstServerIndex(); 717 first_server_index_ = session_->NextFirstServerIndex();
450 718
451 attempts_.clear(); 719 attempts_.clear();
720 had_tcp_attempt_ = false;
452 return MakeAttempt(); 721 return MakeAttempt();
453 } 722 }
454 723
455 void OnAttemptComplete(unsigned attempt_number, int rv) { 724 void OnAttemptComplete(unsigned attempt_number, int rv) {
456 if (callback_.is_null()) 725 if (callback_.is_null())
457 return; 726 return;
458 DCHECK_LT(attempt_number, attempts_.size()); 727 DCHECK_LT(attempt_number, attempts_.size());
459 const DnsUDPAttempt* attempt = attempts_[attempt_number]; 728 const DnsAttempt* attempt = attempts_[attempt_number];
460 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt)); 729 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
461 if (result.rv != ERR_IO_PENDING) 730 if (result.rv != ERR_IO_PENDING)
462 DoCallback(result); 731 DoCallback(result);
463 } 732 }
464 733
465 void LogResponse(const DnsUDPAttempt* attempt) { 734 void LogResponse(const DnsAttempt* attempt) {
466 if (attempt && attempt->response()) { 735 if (attempt && attempt->GetResponse()) {
467 net_log_.AddEvent( 736 net_log_.AddEvent(
468 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 737 NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
469 base::Bind(&DnsUDPAttempt::NetLogResponseCallback, 738 base::Bind(&DnsAttempt::NetLogResponseCallback,
470 base::Unretained(attempt))); 739 base::Unretained(attempt)));
471 } 740 }
472 } 741 }
473 742
474 bool MoreAttemptsAllowed() const { 743 bool MoreAttemptsAllowed() const {
744 if (had_tcp_attempt_)
745 return false;
475 const DnsConfig& config = session_->config(); 746 const DnsConfig& config = session_->config();
476 return attempts_.size() < config.attempts * config.nameservers.size(); 747 return attempts_.size() < config.attempts * config.nameservers.size();
477 } 748 }
478 749
479 // Resolves the result of a DnsUDPAttempt until a terminal result is reached 750 // Resolves the result of a DnsAttempt until a terminal result is reached
480 // or it will complete asynchronously (ERR_IO_PENDING). 751 // or it will complete asynchronously (ERR_IO_PENDING).
481 AttemptResult ProcessAttemptResult(AttemptResult result) { 752 AttemptResult ProcessAttemptResult(AttemptResult result) {
482 while (result.rv != ERR_IO_PENDING) { 753 while (result.rv != ERR_IO_PENDING) {
483 LogResponse(result.attempt); 754 LogResponse(result.attempt);
484 755
485 switch (result.rv) { 756 switch (result.rv) {
486 case OK: 757 case OK:
487 net_log_.EndEventWithNetErrorCode( 758 net_log_.EndEventWithNetErrorCode(
488 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 759 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
489 DCHECK(result.attempt); 760 DCHECK(result.attempt);
490 DCHECK(result.attempt->response()); 761 DCHECK(result.attempt->GetResponse());
491 return result; 762 return result;
492 case ERR_NAME_NOT_RESOLVED: 763 case ERR_NAME_NOT_RESOLVED:
493 net_log_.EndEventWithNetErrorCode( 764 net_log_.EndEventWithNetErrorCode(
494 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 765 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
495 // Try next suffix. 766 // Try next suffix.
496 qnames_.pop_front(); 767 qnames_.pop_front();
497 if (qnames_.empty()) { 768 if (qnames_.empty()) {
498 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 769 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
499 } else { 770 } else {
500 result = StartQuery(); 771 result = StartQuery();
501 } 772 }
502 break; 773 break;
503 case ERR_CONNECTION_REFUSED: 774 case ERR_CONNECTION_REFUSED:
504 case ERR_DNS_TIMED_OUT: 775 case ERR_DNS_TIMED_OUT:
505 if (MoreAttemptsAllowed()) { 776 if (MoreAttemptsAllowed()) {
506 result = MakeAttempt(); 777 result = MakeAttempt();
507 } else { 778 } else {
508 return result; 779 return result;
509 } 780 }
510 break; 781 break;
782 case ERR_DNS_SERVER_REQUIRES_TCP:
783 result = MakeTCPAttempt(result.attempt);
784 break;
511 default: 785 default:
512 // Server failure. 786 // Server failure.
513 DCHECK(result.attempt); 787 DCHECK(result.attempt);
514 if (result.attempt != attempts_.back()) { 788 if (result.attempt != attempts_.back()) {
515 // This attempt already timed out. Ignore it. 789 // This attempt already timed out. Ignore it.
516 return AttemptResult(ERR_IO_PENDING, NULL); 790 return AttemptResult(ERR_IO_PENDING, NULL);
517 } 791 }
518 if (MoreAttemptsAllowed()) { 792 if (MoreAttemptsAllowed()) {
519 result = MakeAttempt(); 793 result = MakeAttempt();
520 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE) { 794 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
521 // Wait until the last attempt times out. 795 !had_tcp_attempt_) {
796 // For UDP only, ignore the response and wait until the last attempt
797 // times out.
522 return AttemptResult(ERR_IO_PENDING, NULL); 798 return AttemptResult(ERR_IO_PENDING, NULL);
523 } else { 799 } else {
524 return AttemptResult(result.rv, NULL); 800 return AttemptResult(result.rv, NULL);
525 } 801 }
526 break; 802 break;
527 } 803 }
528 } 804 }
529 return result; 805 return result;
530 } 806 }
531 807
(...skipping 11 matching lines...) Expand all
543 uint16 qtype_; 819 uint16 qtype_;
544 // Cleared in DoCallback. 820 // Cleared in DoCallback.
545 DnsTransactionFactory::CallbackType callback_; 821 DnsTransactionFactory::CallbackType callback_;
546 822
547 BoundNetLog net_log_; 823 BoundNetLog net_log_;
548 824
549 // Search list of fully-qualified DNS names to query next (in DNS format). 825 // Search list of fully-qualified DNS names to query next (in DNS format).
550 std::deque<std::string> qnames_; 826 std::deque<std::string> qnames_;
551 827
552 // List of attempts for the current name. 828 // List of attempts for the current name.
553 ScopedVector<DnsUDPAttempt> attempts_; 829 ScopedVector<DnsAttempt> attempts_;
830 bool had_tcp_attempt_;
554 831
555 // Index of the first server to try on each search query. 832 // Index of the first server to try on each search query.
556 int first_server_index_; 833 int first_server_index_;
557 834
558 base::OneShotTimer<DnsTransactionImpl> timer_; 835 base::OneShotTimer<DnsTransactionImpl> timer_;
559 836
560 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 837 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
561 }; 838 };
562 839
563 // ---------------------------------------------------------------------------- 840 // ----------------------------------------------------------------------------
(...skipping 25 matching lines...) Expand all
589 } // namespace 866 } // namespace
590 867
591 // static 868 // static
592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 869 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
593 DnsSession* session) { 870 DnsSession* session) {
594 return scoped_ptr<DnsTransactionFactory>( 871 return scoped_ptr<DnsTransactionFactory>(
595 new DnsTransactionFactoryImpl(session)); 872 new DnsTransactionFactoryImpl(session));
596 } 873 }
597 874
598 } // namespace net 875 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_socket_pool.cc ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698