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/big_endian.h" 12 #include "base/bind.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_vector.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/metrics/histogram.h" 19 #include "base/rand_util.h" 20 #include "base/stl_util.h" 21 #include "base/strings/string_piece.h" 22 #include "base/threading/non_thread_safe.h" 23 #include "base/timer/timer.h" 24 #include "base/values.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 38 namespace net { 39 40 namespace { 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. 48 int 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 55 bool IsIPLiteral(const std::string& hostname) { 56 IPAddressNumber ip; 57 return ParseIPLiteralToNumber(hostname, &ip); 58 } 59 60 base::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. 74 class 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 132 class 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 296 class 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_LENGTH_COMPLETE, 343 STATE_READ_RESPONSE, 344 STATE_READ_RESPONSE_COMPLETE, 345 STATE_NONE, 346 }; 347 348 int DoLoop(int result) { 349 CHECK_NE(STATE_NONE, next_state_); 350 int rv = result; 351 do { 352 State state = next_state_; 353 next_state_ = STATE_NONE; 354 switch (state) { 355 case STATE_CONNECT_COMPLETE: 356 rv = DoConnectComplete(rv); 357 break; 358 case STATE_SEND_LENGTH: 359 rv = DoSendLength(rv); 360 break; 361 case STATE_SEND_QUERY: 362 rv = DoSendQuery(rv); 363 break; 364 case STATE_READ_LENGTH: 365 rv = DoReadLength(rv); 366 break; 367 case STATE_READ_LENGTH_COMPLETE: 368 rv = DoReadLengthComplete(rv); 369 break; 370 case STATE_READ_RESPONSE: 371 rv = DoReadResponse(rv); 372 break; 373 case STATE_READ_RESPONSE_COMPLETE: 374 rv = DoReadResponseComplete(rv); 375 break; 376 default: 377 NOTREACHED(); 378 break; 379 } 380 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 381 382 set_result(rv); 383 if (rv == OK) { 384 DCHECK_EQ(STATE_NONE, next_state_); 385 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess", 386 base::TimeTicks::Now() - start_time_); 387 } else if (rv != ERR_IO_PENDING) { 388 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail", 389 base::TimeTicks::Now() - start_time_); 390 } 391 return rv; 392 } 393 394 int DoConnectComplete(int rv) { 395 DCHECK_NE(ERR_IO_PENDING, rv); 396 if (rv < 0) 397 return rv; 398 399 base::WriteBigEndian<uint16>(length_buffer_->data(), 400 query_->io_buffer()->size()); 401 buffer_ = 402 new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); 403 next_state_ = STATE_SEND_LENGTH; 404 return OK; 405 } 406 407 int DoSendLength(int rv) { 408 DCHECK_NE(ERR_IO_PENDING, rv); 409 if (rv < 0) 410 return rv; 411 412 buffer_->DidConsume(rv); 413 if (buffer_->BytesRemaining() > 0) { 414 next_state_ = STATE_SEND_LENGTH; 415 return socket_->Write( 416 buffer_.get(), 417 buffer_->BytesRemaining(), 418 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 419 } 420 buffer_ = new DrainableIOBuffer(query_->io_buffer(), 421 query_->io_buffer()->size()); 422 next_state_ = STATE_SEND_QUERY; 423 return OK; 424 } 425 426 int DoSendQuery(int rv) { 427 DCHECK_NE(ERR_IO_PENDING, rv); 428 if (rv < 0) 429 return rv; 430 431 buffer_->DidConsume(rv); 432 if (buffer_->BytesRemaining() > 0) { 433 next_state_ = STATE_SEND_QUERY; 434 return socket_->Write( 435 buffer_.get(), 436 buffer_->BytesRemaining(), 437 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 438 } 439 buffer_ = 440 new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); 441 next_state_ = STATE_READ_LENGTH; 442 return OK; 443 } 444 445 int DoReadLength(int rv) { 446 DCHECK_EQ(OK, rv); 447 448 next_state_ = STATE_READ_LENGTH_COMPLETE; 449 return ReadIntoBuffer(); 450 } 451 452 int DoReadLengthComplete(int rv) { 453 DCHECK_NE(ERR_IO_PENDING, rv); 454 if (rv < 0) 455 return rv; 456 if (rv == 0) 457 return ERR_CONNECTION_CLOSED; 458 459 buffer_->DidConsume(rv); 460 if (buffer_->BytesRemaining() > 0) { 461 next_state_ = STATE_READ_LENGTH; 462 return OK; 463 } 464 465 base::ReadBigEndian<uint16>(length_buffer_->data(), &response_length_); 466 // Check if advertised response is too short. (Optimization only.) 467 if (response_length_ < query_->io_buffer()->size()) 468 return ERR_DNS_MALFORMED_RESPONSE; 469 // Allocate more space so that DnsResponse::InitParse sanity check passes. 470 response_.reset(new DnsResponse(response_length_ + 1)); 471 buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_); 472 next_state_ = STATE_READ_RESPONSE; 473 return OK; 474 } 475 476 int DoReadResponse(int rv) { 477 DCHECK_EQ(OK, rv); 478 479 next_state_ = STATE_READ_RESPONSE_COMPLETE; 480 return ReadIntoBuffer(); 481 } 482 483 int DoReadResponseComplete(int rv) { 484 DCHECK_NE(ERR_IO_PENDING, rv); 485 if (rv < 0) 486 return rv; 487 if (rv == 0) 488 return ERR_CONNECTION_CLOSED; 489 490 buffer_->DidConsume(rv); 491 if (buffer_->BytesRemaining() > 0) { 492 next_state_ = STATE_READ_RESPONSE; 493 return OK; 494 } 495 496 if (!response_->InitParse(buffer_->BytesConsumed(), *query_)) 497 return ERR_DNS_MALFORMED_RESPONSE; 498 if (response_->flags() & dns_protocol::kFlagTC) 499 return ERR_UNEXPECTED; 500 // TODO(szym): Frankly, none of these are expected. 501 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN) 502 return ERR_NAME_NOT_RESOLVED; 503 if (response_->rcode() != dns_protocol::kRcodeNOERROR) 504 return ERR_DNS_SERVER_FAILED; 505 506 return OK; 507 } 508 509 void OnIOComplete(int rv) { 510 rv = DoLoop(rv); 511 if (rv != ERR_IO_PENDING) 512 callback_.Run(rv); 513 } 514 515 int ReadIntoBuffer() { 516 return socket_->Read( 517 buffer_.get(), 518 buffer_->BytesRemaining(), 519 base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this))); 520 } 521 522 State next_state_; 523 base::TimeTicks start_time_; 524 525 scoped_ptr<StreamSocket> socket_; 526 scoped_ptr<DnsQuery> query_; 527 scoped_refptr<IOBufferWithSize> length_buffer_; 528 scoped_refptr<DrainableIOBuffer> buffer_; 529 530 uint16 response_length_; 531 scoped_ptr<DnsResponse> response_; 532 533 CompletionCallback callback_; 534 535 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt); 536 }; 537 538 // ---------------------------------------------------------------------------- 539 540 // Implements DnsTransaction. Configuration is supplied by DnsSession. 541 // The suffix list is built according to the DnsConfig from the session. 542 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. 543 // The first server to attempt on each query is given by 544 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. 545 // Each server is attempted DnsConfig::attempts times. 546 class DnsTransactionImpl : public DnsTransaction, 547 public base::NonThreadSafe, 548 public base::SupportsWeakPtr<DnsTransactionImpl> { 549 public: 550 DnsTransactionImpl(DnsSession* session, 551 const std::string& hostname, 552 uint16 qtype, 553 const DnsTransactionFactory::CallbackType& callback, 554 const BoundNetLog& net_log) 555 : session_(session), 556 hostname_(hostname), 557 qtype_(qtype), 558 callback_(callback), 559 net_log_(net_log), 560 qnames_initial_size_(0), 561 attempts_count_(0), 562 had_tcp_attempt_(false), 563 first_server_index_(0) { 564 DCHECK(session_.get()); 565 DCHECK(!hostname_.empty()); 566 DCHECK(!callback_.is_null()); 567 DCHECK(!IsIPLiteral(hostname_)); 568 } 569 570 virtual ~DnsTransactionImpl() { 571 if (!callback_.is_null()) { 572 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 573 ERR_ABORTED); 574 } // otherwise logged in DoCallback or Start 575 } 576 577 virtual const std::string& GetHostname() const OVERRIDE { 578 DCHECK(CalledOnValidThread()); 579 return hostname_; 580 } 581 582 virtual uint16 GetType() const OVERRIDE { 583 DCHECK(CalledOnValidThread()); 584 return qtype_; 585 } 586 587 virtual void Start() OVERRIDE { 588 DCHECK(!callback_.is_null()); 589 DCHECK(attempts_.empty()); 590 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, 591 base::Bind(&NetLogStartCallback, &hostname_, qtype_)); 592 AttemptResult result(PrepareSearch(), NULL); 593 if (result.rv == OK) { 594 qnames_initial_size_ = qnames_.size(); 595 if (qtype_ == dns_protocol::kTypeA) 596 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size()); 597 result = ProcessAttemptResult(StartQuery()); 598 } 599 600 // Must always return result asynchronously, to avoid reentrancy. 601 if (result.rv != ERR_IO_PENDING) { 602 base::MessageLoop::current()->PostTask( 603 FROM_HERE, 604 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result)); 605 } 606 } 607 608 private: 609 // Wrapper for the result of a DnsUDPAttempt. 610 struct AttemptResult { 611 AttemptResult(int rv, const DnsAttempt* attempt) 612 : rv(rv), attempt(attempt) {} 613 614 int rv; 615 const DnsAttempt* attempt; 616 }; 617 618 // Prepares |qnames_| according to the DnsConfig. 619 int PrepareSearch() { 620 const DnsConfig& config = session_->config(); 621 622 std::string labeled_hostname; 623 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 624 return ERR_INVALID_ARGUMENT; 625 626 if (hostname_[hostname_.size() - 1] == '.') { 627 // It's a fully-qualified name, no suffix search. 628 qnames_.push_back(labeled_hostname); 629 return OK; 630 } 631 632 int ndots = CountLabels(labeled_hostname) - 1; 633 634 if (ndots > 0 && !config.append_to_multi_label_name) { 635 qnames_.push_back(labeled_hostname); 636 return OK; 637 } 638 639 // Set true when |labeled_hostname| is put on the list. 640 bool had_hostname = false; 641 642 if (ndots >= config.ndots) { 643 qnames_.push_back(labeled_hostname); 644 had_hostname = true; 645 } 646 647 std::string qname; 648 for (size_t i = 0; i < config.search.size(); ++i) { 649 // Ignore invalid (too long) combinations. 650 if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname)) 651 continue; 652 if (qname.size() == labeled_hostname.size()) { 653 if (had_hostname) 654 continue; 655 had_hostname = true; 656 } 657 qnames_.push_back(qname); 658 } 659 660 if (ndots > 0 && !had_hostname) 661 qnames_.push_back(labeled_hostname); 662 663 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK; 664 } 665 666 void DoCallback(AttemptResult result) { 667 DCHECK(!callback_.is_null()); 668 DCHECK_NE(ERR_IO_PENDING, result.rv); 669 const DnsResponse* response = result.attempt ? 670 result.attempt->GetResponse() : NULL; 671 CHECK(result.rv != OK || response != NULL); 672 673 timer_.Stop(); 674 RecordLostPacketsIfAny(); 675 if (result.rv == OK) 676 UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_); 677 else 678 UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_); 679 680 if (response && qtype_ == dns_protocol::kTypeA) { 681 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size()); 682 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone", 683 qnames_initial_size_ - qnames_.size()); 684 } 685 686 DnsTransactionFactory::CallbackType callback = callback_; 687 callback_.Reset(); 688 689 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 690 callback.Run(this, result.rv, response); 691 } 692 693 // Makes another attempt at the current name, |qnames_.front()|, using the 694 // next nameserver. 695 AttemptResult MakeAttempt() { 696 unsigned attempt_number = attempts_.size(); 697 698 uint16 id = session_->NextQueryId(); 699 scoped_ptr<DnsQuery> query; 700 if (attempts_.empty()) { 701 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 702 } else { 703 query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id)); 704 } 705 706 const DnsConfig& config = session_->config(); 707 708 unsigned server_index = 709 (first_server_index_ + attempt_number) % config.nameservers.size(); 710 // Skip over known failed servers. 711 server_index = session_->NextGoodServerIndex(server_index); 712 713 scoped_ptr<DnsSession::SocketLease> lease = 714 session_->AllocateSocket(server_index, net_log_.source()); 715 716 bool got_socket = !!lease.get(); 717 718 DnsUDPAttempt* attempt = 719 new DnsUDPAttempt(server_index, lease.Pass(), query.Pass()); 720 721 attempts_.push_back(attempt); 722 ++attempts_count_; 723 724 if (!got_socket) 725 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 726 727 net_log_.AddEvent( 728 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 729 attempt->GetSocketNetLog().source().ToEventParametersCallback()); 730 731 int rv = attempt->Start( 732 base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete, 733 base::Unretained(this), attempt_number, 734 base::TimeTicks::Now())); 735 if (rv == ERR_IO_PENDING) { 736 base::TimeDelta timeout = session_->NextTimeout(server_index, 737 attempt_number); 738 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 739 } 740 return AttemptResult(rv, attempt); 741 } 742 743 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) { 744 DCHECK(previous_attempt); 745 DCHECK(!had_tcp_attempt_); 746 747 unsigned server_index = previous_attempt->server_index(); 748 749 scoped_ptr<StreamSocket> socket( 750 session_->CreateTCPSocket(server_index, net_log_.source())); 751 752 // TODO(szym): Reuse the same id to help the server? 753 uint16 id = session_->NextQueryId(); 754 scoped_ptr<DnsQuery> query( 755 previous_attempt->GetQuery()->CloneWithNewId(id)); 756 757 RecordLostPacketsIfAny(); 758 // Cancel all other attempts, no point waiting on them. 759 attempts_.clear(); 760 761 unsigned attempt_number = attempts_.size(); 762 763 DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(), 764 query.Pass()); 765 766 attempts_.push_back(attempt); 767 ++attempts_count_; 768 had_tcp_attempt_ = true; 769 770 net_log_.AddEvent( 771 NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT, 772 attempt->GetSocketNetLog().source().ToEventParametersCallback()); 773 774 int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete, 775 base::Unretained(this), 776 attempt_number)); 777 if (rv == ERR_IO_PENDING) { 778 // Custom timeout for TCP attempt. 779 base::TimeDelta timeout = timer_.GetCurrentDelay() * 2; 780 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 781 } 782 return AttemptResult(rv, attempt); 783 } 784 785 // Begins query for the current name. Makes the first attempt. 786 AttemptResult StartQuery() { 787 std::string dotted_qname = DNSDomainToString(qnames_.front()); 788 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY, 789 NetLog::StringCallback("qname", &dotted_qname)); 790 791 first_server_index_ = session_->NextFirstServerIndex(); 792 RecordLostPacketsIfAny(); 793 attempts_.clear(); 794 had_tcp_attempt_ = false; 795 return MakeAttempt(); 796 } 797 798 void OnUdpAttemptComplete(unsigned attempt_number, 799 base::TimeTicks start, 800 int rv) { 801 DCHECK_LT(attempt_number, attempts_.size()); 802 const DnsAttempt* attempt = attempts_[attempt_number]; 803 if (attempt->GetResponse()) { 804 session_->RecordRTT(attempt->server_index(), 805 base::TimeTicks::Now() - start); 806 } 807 OnAttemptComplete(attempt_number, rv); 808 } 809 810 void OnAttemptComplete(unsigned attempt_number, int rv) { 811 if (callback_.is_null()) 812 return; 813 DCHECK_LT(attempt_number, attempts_.size()); 814 const DnsAttempt* attempt = attempts_[attempt_number]; 815 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt)); 816 if (result.rv != ERR_IO_PENDING) 817 DoCallback(result); 818 } 819 820 // Record packet loss for any incomplete attempts. 821 void RecordLostPacketsIfAny() { 822 // Loop through attempts until we find first that is completed 823 size_t first_completed = 0; 824 for (first_completed = 0; first_completed < attempts_.size(); 825 ++first_completed) { 826 if (attempts_[first_completed]->is_completed()) 827 break; 828 } 829 // If there were no completed attempts, then we must be offline, so don't 830 // record any attempts as lost packets. 831 if (first_completed == attempts_.size()) 832 return; 833 834 size_t num_servers = session_->config().nameservers.size(); 835 std::vector<int> server_attempts(num_servers); 836 for (size_t i = 0; i < first_completed; ++i) { 837 unsigned server_index = attempts_[i]->server_index(); 838 int server_attempt = server_attempts[server_index]++; 839 // Don't record lost packet unless attempt is in pending state. 840 if (!attempts_[i]->is_pending()) 841 continue; 842 session_->RecordLostPacket(server_index, server_attempt); 843 } 844 } 845 846 void LogResponse(const DnsAttempt* attempt) { 847 if (attempt && attempt->GetResponse()) { 848 net_log_.AddEvent( 849 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 850 base::Bind(&DnsAttempt::NetLogResponseCallback, 851 base::Unretained(attempt))); 852 } 853 } 854 855 bool MoreAttemptsAllowed() const { 856 if (had_tcp_attempt_) 857 return false; 858 const DnsConfig& config = session_->config(); 859 return attempts_.size() < config.attempts * config.nameservers.size(); 860 } 861 862 // Resolves the result of a DnsAttempt until a terminal result is reached 863 // or it will complete asynchronously (ERR_IO_PENDING). 864 AttemptResult ProcessAttemptResult(AttemptResult result) { 865 while (result.rv != ERR_IO_PENDING) { 866 LogResponse(result.attempt); 867 868 switch (result.rv) { 869 case OK: 870 session_->RecordServerSuccess(result.attempt->server_index()); 871 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY, 872 result.rv); 873 DCHECK(result.attempt); 874 DCHECK(result.attempt->GetResponse()); 875 return result; 876 case ERR_NAME_NOT_RESOLVED: 877 session_->RecordServerSuccess(result.attempt->server_index()); 878 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY, 879 result.rv); 880 // Try next suffix. 881 qnames_.pop_front(); 882 if (qnames_.empty()) { 883 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 884 } else { 885 result = StartQuery(); 886 } 887 break; 888 case ERR_CONNECTION_REFUSED: 889 case ERR_DNS_TIMED_OUT: 890 if (result.attempt) 891 session_->RecordServerFailure(result.attempt->server_index()); 892 if (MoreAttemptsAllowed()) { 893 result = MakeAttempt(); 894 } else { 895 return result; 896 } 897 break; 898 case ERR_DNS_SERVER_REQUIRES_TCP: 899 result = MakeTCPAttempt(result.attempt); 900 break; 901 default: 902 // Server failure. 903 DCHECK(result.attempt); 904 if (result.attempt != attempts_.back()) { 905 // This attempt already timed out. Ignore it. 906 session_->RecordServerFailure(result.attempt->server_index()); 907 return AttemptResult(ERR_IO_PENDING, NULL); 908 } 909 if (MoreAttemptsAllowed()) { 910 result = MakeAttempt(); 911 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE && 912 !had_tcp_attempt_) { 913 // For UDP only, ignore the response and wait until the last attempt 914 // times out. 915 return AttemptResult(ERR_IO_PENDING, NULL); 916 } else { 917 return AttemptResult(result.rv, NULL); 918 } 919 break; 920 } 921 } 922 return result; 923 } 924 925 void OnTimeout() { 926 if (callback_.is_null()) 927 return; 928 DCHECK(!attempts_.empty()); 929 AttemptResult result = ProcessAttemptResult( 930 AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back())); 931 if (result.rv != ERR_IO_PENDING) 932 DoCallback(result); 933 } 934 935 scoped_refptr<DnsSession> session_; 936 std::string hostname_; 937 uint16 qtype_; 938 // Cleared in DoCallback. 939 DnsTransactionFactory::CallbackType callback_; 940 941 BoundNetLog net_log_; 942 943 // Search list of fully-qualified DNS names to query next (in DNS format). 944 std::deque<std::string> qnames_; 945 size_t qnames_initial_size_; 946 947 // List of attempts for the current name. 948 ScopedVector<DnsAttempt> attempts_; 949 // Count of attempts, not reset when |attempts_| vector is cleared. 950 int attempts_count_; 951 bool had_tcp_attempt_; 952 953 // Index of the first server to try on each search query. 954 int first_server_index_; 955 956 base::OneShotTimer<DnsTransactionImpl> timer_; 957 958 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 959 }; 960 961 // ---------------------------------------------------------------------------- 962 963 // Implementation of DnsTransactionFactory that returns instances of 964 // DnsTransactionImpl. 965 class DnsTransactionFactoryImpl : public DnsTransactionFactory { 966 public: 967 explicit DnsTransactionFactoryImpl(DnsSession* session) { 968 session_ = session; 969 } 970 971 virtual scoped_ptr<DnsTransaction> CreateTransaction( 972 const std::string& hostname, 973 uint16 qtype, 974 const CallbackType& callback, 975 const BoundNetLog& net_log) OVERRIDE { 976 return scoped_ptr<DnsTransaction>(new DnsTransactionImpl( 977 session_.get(), hostname, qtype, callback, net_log)); 978 } 979 980 private: 981 scoped_refptr<DnsSession> session_; 982 }; 983 984 } // namespace 985 986 // static 987 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 988 DnsSession* session) { 989 return scoped_ptr<DnsTransactionFactory>( 990 new DnsTransactionFactoryImpl(session)); 991 } 992 993 } // namespace net 994