dns_transaction.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 3// found in the LICENSE file. 4 5#include "net/dns/dns_transaction.h" 6 7#include <deque> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/memory/ref_counted.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/memory/scoped_vector.h" 15#include "base/memory/weak_ptr.h" 16#include "base/message_loop.h" 17#include "base/metrics/histogram.h" 18#include "base/rand_util.h" 19#include "base/stl_util.h" 20#include "base/strings/string_piece.h" 21#include "base/threading/non_thread_safe.h" 22#include "base/timer/timer.h" 23#include "base/values.h" 24#include "net/base/big_endian.h" 25#include "net/base/completion_callback.h" 26#include "net/base/dns_util.h" 27#include "net/base/io_buffer.h" 28#include "net/base/ip_endpoint.h" 29#include "net/base/net_errors.h" 30#include "net/base/net_log.h" 31#include "net/dns/dns_protocol.h" 32#include "net/dns/dns_query.h" 33#include "net/dns/dns_response.h" 34#include "net/dns/dns_session.h" 35#include "net/socket/stream_socket.h" 36#include "net/udp/datagram_client_socket.h" 37 38namespace net { 39 40namespace { 41 42// Provide a common macro to simplify code and readability. We must use a 43// macro as the underlying HISTOGRAM macro creates static variables. 44#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 45 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) 46 47// Count labels in the fully-qualified name in DNS format. 48int CountLabels(const std::string& name) { 49 size_t count = 0; 50 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1) 51 ++count; 52 return count; 53} 54 55bool IsIPLiteral(const std::string& hostname) { 56 IPAddressNumber ip; 57 return ParseIPLiteralToNumber(hostname, &ip); 58} 59 60base::Value* NetLogStartCallback(const std::string* hostname, 61 uint16 qtype, 62 NetLog::LogLevel /* log_level */) { 63 base::DictionaryValue* dict = new base::DictionaryValue(); 64 dict->SetString("hostname", *hostname); 65 dict->SetInteger("query_type", qtype); 66 return dict; 67}; 68 69// ---------------------------------------------------------------------------- 70 71// A single asynchronous DNS exchange, which consists of sending out a 72// DNS query, waiting for a response, and returning the response that it 73// matches. Logging is done in the socket and in the outer DnsTransaction. 74class DnsAttempt { 75 public: 76 explicit DnsAttempt(unsigned server_index) 77 : result_(ERR_FAILED), server_index_(server_index) {} 78 79 virtual ~DnsAttempt() {} 80 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 81 // and calls |callback| upon completion. 82 virtual int Start(const CompletionCallback& callback) = 0; 83 84 // Returns the query of this attempt. 85 virtual const DnsQuery* GetQuery() const = 0; 86 87 // Returns the response or NULL if has not received a matching response from 88 // the server. 89 virtual const DnsResponse* GetResponse() const = 0; 90 91 // Returns the net log bound to the source of the socket. 92 virtual const BoundNetLog& GetSocketNetLog() const = 0; 93 94 // Returns the index of the destination server within DnsConfig::nameservers. 95 unsigned server_index() const { return server_index_; } 96 97 // Returns a Value representing the received response, along with a reference 98 // to the NetLog source source of the UDP socket used. The request must have 99 // completed before this is called. 100 base::Value* NetLogResponseCallback(NetLog::LogLevel log_level) const { 101 DCHECK(GetResponse()->IsValid()); 102 103 base::DictionaryValue* dict = new base::DictionaryValue(); 104 dict->SetInteger("rcode", GetResponse()->rcode()); 105 dict->SetInteger("answer_count", GetResponse()->answer_count()); 106 GetSocketNetLog().source().AddToEventParameters(dict); 107 return dict; 108 } 109 110 void set_result(int result) { 111 result_ = result; 112 } 113 114 // True if current attempt is pending (waiting for server response). 115 bool is_pending() const { 116 return result_ == ERR_IO_PENDING; 117 } 118 119 // True if attempt is completed (received server response). 120 bool is_completed() const { 121 return (result_ == OK) || (result_ == ERR_NAME_NOT_RESOLVED) || 122 (result_ == ERR_DNS_SERVER_REQUIRES_TCP); 123 } 124 125 private: 126 // Result of last operation. 127 int result_; 128 129 const unsigned server_index_; 130}; 131 132class DnsUDPAttempt : public DnsAttempt { 133 public: 134 DnsUDPAttempt(unsigned server_index, 135 scoped_ptr<DnsSession::SocketLease> socket_lease, 136 scoped_ptr<DnsQuery> query) 137 : DnsAttempt(server_index), 138 next_state_(STATE_NONE), 139 received_malformed_response_(false), 140 socket_lease_(socket_lease.Pass()), 141 query_(query.Pass()) {} 142 143 // DnsAttempt: 144 virtual int Start(const CompletionCallback& callback) OVERRIDE { 145 DCHECK_EQ(STATE_NONE, next_state_); 146 callback_ = callback; 147 start_time_ = base::TimeTicks::Now(); 148 next_state_ = STATE_SEND_QUERY; 149 return DoLoop(OK); 150 } 151 152 virtual const DnsQuery* GetQuery() const OVERRIDE { 153 return query_.get(); 154 } 155 156 virtual const DnsResponse* GetResponse() const OVERRIDE { 157 const DnsResponse* resp = response_.get(); 158 return (resp != NULL && resp->IsValid()) ? resp : NULL; 159 } 160 161 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE { 162 return socket_lease_->socket()->NetLog(); 163 } 164 165 private: 166 enum State { 167 STATE_SEND_QUERY, 168 STATE_SEND_QUERY_COMPLETE, 169 STATE_READ_RESPONSE, 170 STATE_READ_RESPONSE_COMPLETE, 171 STATE_NONE, 172 }; 173 174 DatagramClientSocket* socket() { 175 return socket_lease_->socket(); 176 } 177 178 int DoLoop(int result) { 179 CHECK_NE(STATE_NONE, next_state_); 180 int rv = result; 181 do { 182 State state = next_state_; 183 next_state_ = STATE_NONE; 184 switch (state) { 185 case STATE_SEND_QUERY: 186 rv = DoSendQuery(); 187 break; 188 case STATE_SEND_QUERY_COMPLETE: 189 rv = DoSendQueryComplete(rv); 190 break; 191 case STATE_READ_RESPONSE: 192 rv = DoReadResponse(); 193 break; 194 case STATE_READ_RESPONSE_COMPLETE: 195 rv = DoReadResponseComplete(rv); 196 break; 197 default: 198 NOTREACHED(); 199 break; 200 } 201 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 202 203 set_result(rv); 204 // If we received a malformed response, and are now waiting for another one, 205 // indicate to the transaction that the server might be misbehaving. 206 if (rv == ERR_IO_PENDING && received_malformed_response_) 207 return ERR_DNS_MALFORMED_RESPONSE; 208 if (rv == OK) { 209 DCHECK_EQ(STATE_NONE, next_state_); 210 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess", 211 base::TimeTicks::Now() - start_time_); 212 } else if (rv != ERR_IO_PENDING) { 213 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", 214 base::TimeTicks::Now() - start_time_); 215 } 216 return rv; 217 } 218 219 int DoSendQuery() { 220 next_state_ = STATE_SEND_QUERY_COMPLETE; 221 return socket()->Write(query_->io_buffer(), 222 query_->io_buffer()->size(), 223 base::Bind(&DnsUDPAttempt::OnIOComplete, 224 base::Unretained(this))); 225 } 226 227 int DoSendQueryComplete(int rv) { 228 DCHECK_NE(ERR_IO_PENDING, rv); 229 if (rv < 0) 230 return rv; 231 232 // Writing to UDP should not result in a partial datagram. 233 if (rv != query_->io_buffer()->size()) 234 return ERR_MSG_TOO_BIG; 235 236 next_state_ = STATE_READ_RESPONSE; 237 return OK; 238 } 239 240 int DoReadResponse() { 241 next_state_ = STATE_READ_RESPONSE_COMPLETE; 242 response_.reset(new DnsResponse()); 243 return socket()->Read(response_->io_buffer(), 244 response_->io_buffer()->size(), 245 base::Bind(&DnsUDPAttempt::OnIOComplete, 246 base::Unretained(this))); 247 } 248 249 int DoReadResponseComplete(int rv) { 250 DCHECK_NE(ERR_IO_PENDING, rv); 251 if (rv < 0) 252 return rv; 253 254 DCHECK(rv); 255 if (!response_->InitParse(rv, *query_)) { 256 // Other implementations simply ignore mismatched responses. Since each 257 // DnsUDPAttempt binds to a different port, we might find that responses 258 // to previously timed out queries lead to failures in the future. 259 // Our solution is to make another attempt, in case the query truly 260 // failed, but keep this attempt alive, in case it was a false alarm. 261 received_malformed_response_ = true; 262 next_state_ = STATE_READ_RESPONSE; 263 return OK; 264 } 265 if (response_->flags() & dns_protocol::kFlagTC) 266 return ERR_DNS_SERVER_REQUIRES_TCP; 267 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051 268 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 269 return ERR_NAME_NOT_RESOLVED; 270 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 271 return ERR_DNS_SERVER_FAILED; 272 273 return OK; 274 } 275 276 void OnIOComplete(int rv) { 277 rv = DoLoop(rv); 278 if (rv != ERR_IO_PENDING) 279 callback_.Run(rv); 280 } 281 282 State next_state_; 283 bool received_malformed_response_; 284 base::TimeTicks start_time_; 285 286 scoped_ptr<DnsSession::SocketLease> socket_lease_; 287 scoped_ptr<DnsQuery> query_; 288 289 scoped_ptr<DnsResponse> response_; 290 291 CompletionCallback callback_; 292 293 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 294}; 295 296class DnsTCPAttempt : public DnsAttempt { 297 public: 298 DnsTCPAttempt(unsigned server_index, 299 scoped_ptr<StreamSocket> socket, 300 scoped_ptr<DnsQuery> query) 301 : DnsAttempt(server_index), 302 next_state_(STATE_NONE), 303 socket_(socket.Pass()), 304 query_(query.Pass()), 305 length_buffer_(new IOBufferWithSize(sizeof(uint16))), 306 response_length_(0) {} 307 308 // DnsAttempt: 309 virtual int Start(const CompletionCallback& callback) OVERRIDE { 310 DCHECK_EQ(STATE_NONE, next_state_); 311 callback_ = callback; 312 start_time_ = base::TimeTicks::Now(); 313 next_state_ = STATE_CONNECT_COMPLETE; 314 int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete, 315 base::Unretained(this))); 316 if (rv == ERR_IO_PENDING) { 317 set_result(rv); 318 return rv; 319 } 320 return DoLoop(rv); 321 } 322 323 virtual const DnsQuery* GetQuery() const OVERRIDE { 324 return query_.get(); 325 } 326 327 virtual const DnsResponse* GetResponse() const OVERRIDE { 328 const DnsResponse* resp = response_.get(); 329 return (resp != NULL && resp->IsValid()) ? resp : NULL; 330 } 331 332 virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE { 333 return socket_->NetLog(); 334 } 335 336 private: 337 enum State { 338 STATE_CONNECT_COMPLETE, 339 STATE_SEND_LENGTH, 340 STATE_SEND_QUERY, 341 STATE_READ_LENGTH, 342 STATE_READ_RESPONSE, 343 STATE_NONE, 344 }; 345 346 int DoLoop(int result) { 347 CHECK_NE(STATE_NONE, next_state_); 348 int rv = result; 349 do { 350 State state = next_state_; 351 next_state_ = STATE_NONE; 352 switch (state) { 353 case STATE_CONNECT_COMPLETE: 354 rv = DoConnectComplete(rv); 355 break; 356 case STATE_SEND_LENGTH: 357 rv = DoSendLength(rv); 358 break; 359 case STATE_SEND_QUERY: 360 rv = DoSendQuery(rv); 361 break; 362 case STATE_READ_LENGTH: 363 rv = DoReadLength(rv); 364 break; 365 case STATE_READ_RESPONSE: 366 rv = DoReadResponse(rv); 367 break; 368 default: 369 NOTREACHED(); 370 break; 371 } 372 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 373 374 set_result(rv); 375 if (rv == OK) { 376 DCHECK_EQ(STATE_NONE, next_state_); 377 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess", 378 base::TimeTicks::Now() - start_time_); 379 } else if (rv != ERR_IO_PENDING) { 380 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail", 381 base::TimeTicks::Now() - start_time_); 382 } 383 return rv; 384 } 385 386 int DoConnectComplete(int rv) { 387 DCHECK_NE(ERR_IO_PENDING, rv); 388 if (rv < 0) 389 return rv; 390 391 WriteBigEndian<uint16>(length_buffer_->data(), query_->io_buffer()->size()); 392 buffer_ = 393 new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); 394 next_state_ = STATE_SEND_LENGTH; 395 return OK; 396 } 397 398 int DoSendLength(int rv) { 399 DCHECK_NE(ERR_IO_PENDING, rv); 400 if (rv < 0) 401 return rv; 402 403 buffer_->DidConsume(rv); 404 if (buffer_->BytesRemaining() > 0) { 405 next_state_ = STATE_SEND_LENGTH; 406 return socket_->Write( 407 buffer_.get(), 408 buffer_->BytesRemaining(), 409 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 410 } 411 buffer_ = new DrainableIOBuffer(query_->io_buffer(), 412 query_->io_buffer()->size()); 413 next_state_ = STATE_SEND_QUERY; 414 return OK; 415 } 416 417 int DoSendQuery(int rv) { 418 DCHECK_NE(ERR_IO_PENDING, rv); 419 if (rv < 0) 420 return rv; 421 422 buffer_->DidConsume(rv); 423 if (buffer_->BytesRemaining() > 0) { 424 next_state_ = STATE_SEND_QUERY; 425 return socket_->Write( 426 buffer_.get(), 427 buffer_->BytesRemaining(), 428 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 429 } 430 buffer_ = 431 new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); 432 next_state_ = STATE_READ_LENGTH; 433 return OK; 434 } 435 436 int DoReadLength(int rv) { 437 DCHECK_NE(ERR_IO_PENDING, rv); 438 if (rv < 0) 439 return rv; 440 441 buffer_->DidConsume(rv); 442 if (buffer_->BytesRemaining() > 0) { 443 next_state_ = STATE_READ_LENGTH; 444 return socket_->Read( 445 buffer_.get(), 446 buffer_->BytesRemaining(), 447 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 448 } 449 ReadBigEndian<uint16>(length_buffer_->data(), &response_length_); 450 // Check if advertised response is too short. (Optimization only.) 451 if (response_length_ < query_->io_buffer()->size()) 452 return ERR_DNS_MALFORMED_RESPONSE; 453 // Allocate more space so that DnsResponse::InitParse sanity check passes. 454 response_.reset(new DnsResponse(response_length_ + 1)); 455 buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_); 456 next_state_ = STATE_READ_RESPONSE; 457 return OK; 458 } 459 460 int DoReadResponse(int rv) { 461 DCHECK_NE(ERR_IO_PENDING, rv); 462 if (rv < 0) 463 return rv; 464 465 buffer_->DidConsume(rv); 466 if (buffer_->BytesRemaining() > 0) { 467 next_state_ = STATE_READ_RESPONSE; 468 return socket_->Read( 469 buffer_.get(), 470 buffer_->BytesRemaining(), 471 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 472 } 473 if (!response_->InitParse(buffer_->BytesConsumed(), *query_)) 474 return ERR_DNS_MALFORMED_RESPONSE; 475 if (response_->flags() & dns_protocol::kFlagTC) 476 return ERR_UNEXPECTED; 477 // TODO(szym): Frankly, none of these are expected. 478 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 479 return ERR_NAME_NOT_RESOLVED; 480 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 481 return ERR_DNS_SERVER_FAILED; 482 483 return OK; 484 } 485 486 void OnIOComplete(int rv) { 487 rv = DoLoop(rv); 488 if (rv != ERR_IO_PENDING) 489 callback_.Run(rv); 490 } 491 492 State next_state_; 493 base::TimeTicks start_time_; 494 495 scoped_ptr<StreamSocket> socket_; 496 scoped_ptr<DnsQuery> query_; 497 scoped_refptr<IOBufferWithSize> length_buffer_; 498 scoped_refptr<DrainableIOBuffer> buffer_; 499 500 uint16 response_length_; 501 scoped_ptr<DnsResponse> response_; 502 503 CompletionCallback callback_; 504 505 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt); 506}; 507 508// ---------------------------------------------------------------------------- 509 510// Implements DnsTransaction. Configuration is supplied by DnsSession. 511// The suffix list is built according to the DnsConfig from the session. 512// The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. 513// The first server to attempt on each query is given by 514// DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. 515// Each server is attempted DnsConfig::attempts times. 516class DnsTransactionImpl : public DnsTransaction, 517 public base::NonThreadSafe, 518 public base::SupportsWeakPtr<DnsTransactionImpl> { 519 public: 520 DnsTransactionImpl(DnsSession* session, 521 const std::string& hostname, 522 uint16 qtype, 523 const DnsTransactionFactory::CallbackType& callback, 524 const BoundNetLog& net_log) 525 : session_(session), 526 hostname_(hostname), 527 qtype_(qtype), 528 callback_(callback), 529 net_log_(net_log), 530 qnames_initial_size_(0), 531 had_tcp_attempt_(false), 532 first_server_index_(0) { 533 DCHECK(session_.get()); 534 DCHECK(!hostname_.empty()); 535 DCHECK(!callback_.is_null()); 536 DCHECK(!IsIPLiteral(hostname_)); 537 } 538 539 virtual ~DnsTransactionImpl() { 540 if (!callback_.is_null()) { 541 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 542 ERR_ABORTED); 543 } // otherwise logged in DoCallback or Start 544 } 545 546 virtual const std::string& GetHostname() const OVERRIDE { 547 DCHECK(CalledOnValidThread()); 548 return hostname_; 549 } 550 551 virtual uint16 GetType() const OVERRIDE { 552 DCHECK(CalledOnValidThread()); 553 return qtype_; 554 } 555 556 virtual int Start() OVERRIDE { 557 DCHECK(!callback_.is_null()); 558 DCHECK(attempts_.empty()); 559 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, 560 base::Bind(&NetLogStartCallback, &hostname_, qtype_)); 561 int rv = PrepareSearch(); 562 if (rv == OK) { 563 qnames_initial_size_ = qnames_.size(); 564 if (qtype_ == dns_protocol::kTypeA) 565 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size()); 566 AttemptResult result = ProcessAttemptResult(StartQuery()); 567 if (result.rv == OK) { 568 // DnsTransaction must never succeed synchronously. 569 base::MessageLoop::current()->PostTask( 570 FROM_HERE, 571 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result)); 572 return ERR_IO_PENDING; 573 } 574 rv = result.rv; 575 } 576 if (rv != ERR_IO_PENDING) { 577 callback_.Reset(); 578 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv); 579 } 580 DCHECK_NE(OK, rv); 581 return rv; 582 } 583 584 private: 585 // Wrapper for the result of a DnsUDPAttempt. 586 struct AttemptResult { 587 AttemptResult(int rv, const DnsAttempt* attempt) 588 : rv(rv), attempt(attempt) {} 589 590 int rv; 591 const DnsAttempt* attempt; 592 }; 593 594 // Prepares |qnames_| according to the DnsConfig. 595 int PrepareSearch() { 596 const DnsConfig& config = session_->config(); 597 598 std::string labeled_hostname; 599 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 600 return ERR_INVALID_ARGUMENT; 601 602 if (hostname_[hostname_.size() - 1] == '.') { 603 // It's a fully-qualified name, no suffix search. 604 qnames_.push_back(labeled_hostname); 605 return OK; 606 } 607 608 int ndots = CountLabels(labeled_hostname) - 1; 609 610 if (ndots > 0 && !config.append_to_multi_label_name) { 611 qnames_.push_back(labeled_hostname); 612 return OK; 613 } 614 615 // Set true when |labeled_hostname| is put on the list. 616 bool had_hostname = false; 617 618 if (ndots >= config.ndots) { 619 qnames_.push_back(labeled_hostname); 620 had_hostname = true; 621 } 622 623 std::string qname; 624 for (size_t i = 0; i < config.search.size(); ++i) { 625 // Ignore invalid (too long) combinations. 626 if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname)) 627 continue; 628 if (qname.size() == labeled_hostname.size()) { 629 if (had_hostname) 630 continue; 631 had_hostname = true; 632 } 633 qnames_.push_back(qname); 634 } 635 636 if (ndots > 0 && !had_hostname) 637 qnames_.push_back(labeled_hostname); 638 639 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK; 640 } 641 642 void DoCallback(AttemptResult result) { 643 DCHECK(!callback_.is_null()); 644 DCHECK_NE(ERR_IO_PENDING, result.rv); 645 const DnsResponse* response = result.attempt ? 646 result.attempt->GetResponse() : NULL; 647 CHECK(result.rv != OK || response != NULL); 648 649 timer_.Stop(); 650 RecordLostPacketsIfAny(); 651 652 if (response && qtype_ == dns_protocol::kTypeA) { 653 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size()); 654 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone", 655 qnames_initial_size_ - qnames_.size()); 656 } 657 658 DnsTransactionFactory::CallbackType callback = callback_; 659 callback_.Reset(); 660 661 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 662 callback.Run(this, result.rv, response); 663 } 664 665 // Makes another attempt at the current name, |qnames_.front()|, using the 666 // next nameserver. 667 AttemptResult MakeAttempt() { 668 unsigned attempt_number = attempts_.size(); 669 670 uint16 id = session_->NextQueryId(); 671 scoped_ptr<DnsQuery> query; 672 if (attempts_.empty()) { 673 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 674 } else { 675 query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id)); 676 } 677 678 const DnsConfig& config = session_->config(); 679 680 unsigned server_index = 681 (first_server_index_ + attempt_number) % config.nameservers.size(); 682 // Skip over known failed servers. 683 server_index = session_->NextGoodServerIndex(server_index); 684 685 scoped_ptr<DnsSession::SocketLease> lease = 686 session_->AllocateSocket(server_index, net_log_.source()); 687 688 bool got_socket = !!lease.get(); 689 690 DnsUDPAttempt* attempt = 691 new DnsUDPAttempt(server_index, lease.Pass(), query.Pass()); 692 693 attempts_.push_back(attempt); 694 695 if (!got_socket) 696 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 697 698 net_log_.AddEvent( 699 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 700 attempt->GetSocketNetLog().source().ToEventParametersCallback()); 701 702 int rv = attempt->Start( 703 base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete, 704 base::Unretained(this), attempt_number, 705 base::TimeTicks::Now())); 706 if (rv == ERR_IO_PENDING) { 707 base::TimeDelta timeout = session_->NextTimeout(server_index, 708 attempt_number); 709 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 710 } 711 return AttemptResult(rv, attempt); 712 } 713 714 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) { 715 DCHECK(previous_attempt); 716 DCHECK(!had_tcp_attempt_); 717 718 unsigned server_index = previous_attempt->server_index(); 719 720 scoped_ptr<StreamSocket> socket( 721 session_->CreateTCPSocket(server_index, net_log_.source())); 722 723 // TODO(szym): Reuse the same id to help the server? 724 uint16 id = session_->NextQueryId(); 725 scoped_ptr<DnsQuery> query( 726 previous_attempt->GetQuery()->CloneWithNewId(id)); 727 728 RecordLostPacketsIfAny(); 729 // Cancel all other attempts, no point waiting on them. 730 attempts_.clear(); 731 732 unsigned attempt_number = attempts_.size(); 733 734 DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(), 735 query.Pass()); 736 737 attempts_.push_back(attempt); 738 had_tcp_attempt_ = true; 739 740 net_log_.AddEvent( 741 NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT, 742 attempt->GetSocketNetLog().source().ToEventParametersCallback()); 743 744 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete, 745 base::Unretained(this), 746 attempt_number)); 747 if (rv == ERR_IO_PENDING) { 748 // Custom timeout for TCP attempt. 749 base::TimeDelta timeout = timer_.GetCurrentDelay() * 2; 750 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 751 } 752 return AttemptResult(rv, attempt); 753 } 754 755 // Begins query for the current name. Makes the first attempt. 756 AttemptResult StartQuery() { 757 std::string dotted_qname = DNSDomainToString(qnames_.front()); 758 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY, 759 NetLog::StringCallback("qname", &dotted_qname)); 760 761 first_server_index_ = session_->NextFirstServerIndex(); 762 RecordLostPacketsIfAny(); 763 attempts_.clear(); 764 had_tcp_attempt_ = false; 765 return MakeAttempt(); 766 } 767 768 void OnUdpAttemptComplete(unsigned attempt_number, 769 base::TimeTicks start, 770 int rv) { 771 DCHECK_LT(attempt_number, attempts_.size()); 772 const DnsAttempt* attempt = attempts_[attempt_number]; 773 if (attempt->GetResponse()) { 774 session_->RecordRTT(attempt->server_index(), 775 base::TimeTicks::Now() - start); 776 } 777 OnAttemptComplete(attempt_number, rv); 778 } 779 780 void OnAttemptComplete(unsigned attempt_number, int rv) { 781 if (callback_.is_null()) 782 return; 783 DCHECK_LT(attempt_number, attempts_.size()); 784 const DnsAttempt* attempt = attempts_[attempt_number]; 785 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt)); 786 if (result.rv != ERR_IO_PENDING) 787 DoCallback(result); 788 } 789 790 // Record packet loss for any incomplete attempts. 791 void RecordLostPacketsIfAny() { 792 // Loop through attempts until we find first that is completed 793 size_t first_completed = 0; 794 for (first_completed = 0; first_completed < attempts_.size(); 795 ++first_completed) { 796 if (attempts_[first_completed]->is_completed()) 797 break; 798 } 799 // If there were no completed attempts, then we must be offline, so don't 800 // record any attempts as lost packets. 801 if (first_completed == attempts_.size()) 802 return; 803 804 size_t num_servers = session_->config().nameservers.size(); 805 std::vector<int> server_attempts(num_servers); 806 for (size_t i = 0; i < first_completed; ++i) { 807 unsigned server_index = attempts_[i]->server_index(); 808 int server_attempt = server_attempts[server_index]++; 809 // Don't record lost packet unless attempt is in pending state. 810 if (!attempts_[i]->is_pending()) 811 continue; 812 session_->RecordLostPacket(server_index, server_attempt); 813 } 814 } 815 816 void LogResponse(const DnsAttempt* attempt) { 817 if (attempt && attempt->GetResponse()) { 818 net_log_.AddEvent( 819 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 820 base::Bind(&DnsAttempt::NetLogResponseCallback, 821 base::Unretained(attempt))); 822 } 823 } 824 825 bool MoreAttemptsAllowed() const { 826 if (had_tcp_attempt_) 827 return false; 828 const DnsConfig& config = session_->config(); 829 return attempts_.size() < config.attempts * config.nameservers.size(); 830 } 831 832 // Resolves the result of a DnsAttempt until a terminal result is reached 833 // or it will complete asynchronously (ERR_IO_PENDING). 834 AttemptResult ProcessAttemptResult(AttemptResult result) { 835 while (result.rv != ERR_IO_PENDING) { 836 LogResponse(result.attempt); 837 838 switch (result.rv) { 839 case OK: 840 session_->RecordServerSuccess(result.attempt->server_index()); 841 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY, 842 result.rv); 843 DCHECK(result.attempt); 844 DCHECK(result.attempt->GetResponse()); 845 return result; 846 case ERR_NAME_NOT_RESOLVED: 847 session_->RecordServerSuccess(result.attempt->server_index()); 848 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY, 849 result.rv); 850 // Try next suffix. 851 qnames_.pop_front(); 852 if (qnames_.empty()) { 853 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 854 } else { 855 result = StartQuery(); 856 } 857 break; 858 case ERR_CONNECTION_REFUSED: 859 case ERR_DNS_TIMED_OUT: 860 if (result.attempt) 861 session_->RecordServerFailure(result.attempt->server_index()); 862 if (MoreAttemptsAllowed()) { 863 result = MakeAttempt(); 864 } else { 865 return result; 866 } 867 break; 868 case ERR_DNS_SERVER_REQUIRES_TCP: 869 result = MakeTCPAttempt(result.attempt); 870 break; 871 default: 872 // Server failure. 873 DCHECK(result.attempt); 874 if (result.attempt != attempts_.back()) { 875 // This attempt already timed out. Ignore it. 876 session_->RecordServerFailure(result.attempt->server_index()); 877 return AttemptResult(ERR_IO_PENDING, NULL); 878 } 879 if (MoreAttemptsAllowed()) { 880 result = MakeAttempt(); 881 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE && 882 !had_tcp_attempt_) { 883 // For UDP only, ignore the response and wait until the last attempt 884 // times out. 885 return AttemptResult(ERR_IO_PENDING, NULL); 886 } else { 887 return AttemptResult(result.rv, NULL); 888 } 889 break; 890 } 891 } 892 return result; 893 } 894 895 void OnTimeout() { 896 if (callback_.is_null()) 897 return; 898 AttemptResult result = ProcessAttemptResult( 899 AttemptResult(ERR_DNS_TIMED_OUT, NULL)); 900 if (result.rv != ERR_IO_PENDING) 901 DoCallback(result); 902 } 903 904 scoped_refptr<DnsSession> session_; 905 std::string hostname_; 906 uint16 qtype_; 907 // Cleared in DoCallback. 908 DnsTransactionFactory::CallbackType callback_; 909 910 BoundNetLog net_log_; 911 912 // Search list of fully-qualified DNS names to query next (in DNS format). 913 std::deque<std::string> qnames_; 914 size_t qnames_initial_size_; 915 916 // List of attempts for the current name. 917 ScopedVector<DnsAttempt> attempts_; 918 bool had_tcp_attempt_; 919 920 // Index of the first server to try on each search query. 921 int first_server_index_; 922 923 base::OneShotTimer<DnsTransactionImpl> timer_; 924 925 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 926}; 927 928// ---------------------------------------------------------------------------- 929 930// Implementation of DnsTransactionFactory that returns instances of 931// DnsTransactionImpl. 932class DnsTransactionFactoryImpl : public DnsTransactionFactory { 933 public: 934 explicit DnsTransactionFactoryImpl(DnsSession* session) { 935 session_ = session; 936 } 937 938 virtual scoped_ptr<DnsTransaction> CreateTransaction( 939 const std::string& hostname, 940 uint16 qtype, 941 const CallbackType& callback, 942 const BoundNetLog& net_log) OVERRIDE { 943 return scoped_ptr<DnsTransaction>(new DnsTransactionImpl( 944 session_.get(), hostname, qtype, callback, net_log)); 945 } 946 947 private: 948 scoped_refptr<DnsSession> session_; 949}; 950 951} // namespace 952 953// static 954scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 955 DnsSession* session) { 956 return scoped_ptr<DnsTransactionFactory>( 957 new DnsTransactionFactoryImpl(session)); 958} 959 960} // namespace net 961