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