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/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 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_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. 516 class 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 attempts_count_(0), 532 had_tcp_attempt_(false), 533 first_server_index_(0) { 534 DCHECK(session_.get()); 535 DCHECK(!hostname_.empty()); 536 DCHECK(!callback_.is_null()); 537 DCHECK(!IsIPLiteral(hostname_)); 538 } 539 540 virtual ~DnsTransactionImpl() { 541 if (!callback_.is_null()) { 542 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 543 ERR_ABORTED); 544 } // otherwise logged in DoCallback or Start 545 } 546 547 virtual const std::string& GetHostname() const OVERRIDE { 548 DCHECK(CalledOnValidThread()); 549 return hostname_; 550 } 551 552 virtual uint16 GetType() const OVERRIDE { 553 DCHECK(CalledOnValidThread()); 554 return qtype_; 555 } 556 557 virtual void Start() OVERRIDE { 558 DCHECK(!callback_.is_null()); 559 DCHECK(attempts_.empty()); 560 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, 561 base::Bind(&NetLogStartCallback, &hostname_, qtype_)); 562 AttemptResult result(PrepareSearch(), NULL); 563 if (result.rv == OK) { 564 qnames_initial_size_ = qnames_.size(); 565 if (qtype_ == dns_protocol::kTypeA) 566 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size()); 567 result = ProcessAttemptResult(StartQuery()); 568 } 569 570 // Must always return result asynchronously, to avoid reentrancy. 571 if (result.rv != ERR_IO_PENDING) { 572 base::MessageLoop::current()->PostTask( 573 FROM_HERE, 574 base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result)); 575 } 576 } 577 578 private: 579 // Wrapper for the result of a DnsUDPAttempt. 580 struct AttemptResult { 581 AttemptResult(int rv, const DnsAttempt* attempt) 582 : rv(rv), attempt(attempt) {} 583 584 int rv; 585 const DnsAttempt* attempt; 586 }; 587 588 // Prepares |qnames_| according to the DnsConfig. 589 int PrepareSearch() { 590 const DnsConfig& config = session_->config(); 591 592 std::string labeled_hostname; 593 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 594 return ERR_INVALID_ARGUMENT; 595 596 if (hostname_[hostname_.size() - 1] == '.') { 597 // It's a fully-qualified name, no suffix search. 598 qnames_.push_back(labeled_hostname); 599 return OK; 600 } 601 602 int ndots = CountLabels(labeled_hostname) - 1; 603 604 if (ndots > 0 && !config.append_to_multi_label_name) { 605 qnames_.push_back(labeled_hostname); 606 return OK; 607 } 608 609 // Set true when |labeled_hostname| is put on the list. 610 bool had_hostname = false; 611 612 if (ndots >= config.ndots) { 613 qnames_.push_back(labeled_hostname); 614 had_hostname = true; 615 } 616 617 std::string qname; 618 for (size_t i = 0; i < config.search.size(); ++i) { 619 // Ignore invalid (too long) combinations. 620 if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname)) 621 continue; 622 if (qname.size() == labeled_hostname.size()) { 623 if (had_hostname) 624 continue; 625 had_hostname = true; 626 } 627 qnames_.push_back(qname); 628 } 629 630 if (ndots > 0 && !had_hostname) 631 qnames_.push_back(labeled_hostname); 632 633 return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK; 634 } 635 636 void DoCallback(AttemptResult result) { 637 DCHECK(!callback_.is_null()); 638 DCHECK_NE(ERR_IO_PENDING, result.rv); 639 const DnsResponse* response = result.attempt ? 640 result.attempt->GetResponse() : NULL; 641 CHECK(result.rv != OK || response != NULL); 642 643 timer_.Stop(); 644 RecordLostPacketsIfAny(); 645 if (result.rv == OK) 646 UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_); 647 else 648 UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_); 649 650 if (response && qtype_ == dns_protocol::kTypeA) { 651 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size()); 652 UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone", 653 qnames_initial_size_ - qnames_.size()); 654 } 655 656 DnsTransactionFactory::CallbackType callback = callback_; 657 callback_.Reset(); 658 659 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 660 callback.Run(this, result.rv, response); 661 } 662 663 // Makes another attempt at the current name, |qnames_.front()|, using the 664 // next nameserver. 665 AttemptResult MakeAttempt() { 666 unsigned attempt_number = attempts_.size(); 667 668 uint16 id = session_->NextQueryId(); 669 scoped_ptr<DnsQuery> query; 670 if (attempts_.empty()) { 671 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 672 } else { 673 query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id)); 674 } 675 676 const DnsConfig& config = session_->config(); 677 678 unsigned server_index = 679 (first_server_index_ + attempt_number) % config.nameservers.size(); 680 // Skip over known failed servers. 681 server_index = session_->NextGoodServerIndex(server_index); 682 683 scoped_ptr<DnsSession::SocketLease> lease = 684 session_->AllocateSocket(server_index, net_log_.source()); 685 686 bool got_socket = !!lease.get(); 687 688 DnsUDPAttempt* attempt = 689 new DnsUDPAttempt(server_index, lease.Pass(), query.Pass()); 690 691 attempts_.push_back(attempt); 692 ++attempts_count_; 693 694 if (!got_socket) 695 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 696 697 net_log_.AddEvent( 698 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 699 attempt->GetSocketNetLog().source().ToEventParametersCallback()); 700 701 int rv = attempt->Start( 702 base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete, 703 base::Unretained(this), attempt_number, 704 base::TimeTicks::Now())); 705 if (rv == ERR_IO_PENDING) { 706 base::TimeDelta timeout = session_->NextTimeout(server_index, 707 attempt_number); 708 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 709 } 710 return AttemptResult(rv, attempt); 711 } 712 713 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) { 714 DCHECK(previous_attempt); 715 DCHECK(!had_tcp_attempt_); 716 717 unsigned server_index = previous_attempt->server_index(); 718 719 scoped_ptr<StreamSocket> socket( 720 session_->CreateTCPSocket(server_index, net_log_.source())); 721 722 // TODO(szym): Reuse the same id to help the server? 723 uint16 id = session_->NextQueryId(); 724 scoped_ptr<DnsQuery> query( 725 previous_attempt->GetQuery()->CloneWithNewId(id)); 726 727 RecordLostPacketsIfAny(); 728 // Cancel all other attempts, no point waiting on them. 729 attempts_.clear(); 730 731 unsigned attempt_number = attempts_.size(); 732 733 DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(), 734 query.Pass()); 735 736 attempts_.push_back(attempt); 737 ++attempts_count_; 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 DCHECK(!attempts_.empty()); 899 AttemptResult result = ProcessAttemptResult( 900 AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back())); 901 if (result.rv != ERR_IO_PENDING) 902 DoCallback(result); 903 } 904 905 scoped_refptr<DnsSession> session_; 906 std::string hostname_; 907 uint16 qtype_; 908 // Cleared in DoCallback. 909 DnsTransactionFactory::CallbackType callback_; 910 911 BoundNetLog net_log_; 912 913 // Search list of fully-qualified DNS names to query next (in DNS format). 914 std::deque<std::string> qnames_; 915 size_t qnames_initial_size_; 916 917 // List of attempts for the current name. 918 ScopedVector<DnsAttempt> attempts_; 919 // Count of attempts, not reset when |attempts_| vector is cleared. 920 int attempts_count_; 921 bool had_tcp_attempt_; 922 923 // Index of the first server to try on each search query. 924 int first_server_index_; 925 926 base::OneShotTimer<DnsTransactionImpl> timer_; 927 928 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 929 }; 930 931 // ---------------------------------------------------------------------------- 932 933 // Implementation of DnsTransactionFactory that returns instances of 934 // DnsTransactionImpl. 935 class DnsTransactionFactoryImpl : public DnsTransactionFactory { 936 public: 937 explicit DnsTransactionFactoryImpl(DnsSession* session) { 938 session_ = session; 939 } 940 941 virtual scoped_ptr<DnsTransaction> CreateTransaction( 942 const std::string& hostname, 943 uint16 qtype, 944 const CallbackType& callback, 945 const BoundNetLog& net_log) OVERRIDE { 946 return scoped_ptr<DnsTransaction>(new DnsTransactionImpl( 947 session_.get(), hostname, qtype, callback, net_log)); 948 } 949 950 private: 951 scoped_refptr<DnsSession> session_; 952 }; 953 954 } // namespace 955 956 // static 957 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 958 DnsSession* session) { 959 return scoped_ptr<DnsTransactionFactory>( 960 new DnsTransactionFactoryImpl(session)); 961 } 962 963 } // namespace net 964