| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/dns/dns_transaction.h" | 5 #include "net/dns/dns_transaction.h" |
| 6 | 6 |
| 7 #include <deque> | 7 #include <deque> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "net/base/completion_callback.h" | 24 #include "net/base/completion_callback.h" |
| 25 #include "net/base/dns_util.h" | 25 #include "net/base/dns_util.h" |
| 26 #include "net/base/io_buffer.h" | 26 #include "net/base/io_buffer.h" |
| 27 #include "net/base/ip_endpoint.h" | 27 #include "net/base/ip_endpoint.h" |
| 28 #include "net/base/net_errors.h" | 28 #include "net/base/net_errors.h" |
| 29 #include "net/base/net_log.h" | 29 #include "net/base/net_log.h" |
| 30 #include "net/dns/dns_protocol.h" | 30 #include "net/dns/dns_protocol.h" |
| 31 #include "net/dns/dns_query.h" | 31 #include "net/dns/dns_query.h" |
| 32 #include "net/dns/dns_response.h" | 32 #include "net/dns/dns_response.h" |
| 33 #include "net/dns/dns_session.h" | 33 #include "net/dns/dns_session.h" |
| 34 #include "net/socket/client_socket_factory.h" | |
| 35 #include "net/udp/datagram_client_socket.h" | 34 #include "net/udp/datagram_client_socket.h" |
| 36 | 35 |
| 37 namespace net { | 36 namespace net { |
| 38 | 37 |
| 39 namespace { | 38 namespace { |
| 40 | 39 |
| 41 // Provide a common macro to simplify code and readability. We must use a | 40 // Provide a common macro to simplify code and readability. We must use a |
| 42 // macro as the underlying HISTOGRAM macro creates static variables. | 41 // macro as the underlying HISTOGRAM macro creates static variables. |
| 43 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ | 42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ |
| 44 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) | 43 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 65 return dict; | 64 return dict; |
| 66 }; | 65 }; |
| 67 | 66 |
| 68 // ---------------------------------------------------------------------------- | 67 // ---------------------------------------------------------------------------- |
| 69 | 68 |
| 70 // A single asynchronous DNS exchange over UDP, which consists of sending out a | 69 // A single asynchronous DNS exchange over UDP, which consists of sending out a |
| 71 // DNS query, waiting for a response, and returning the response that it | 70 // DNS query, waiting for a response, and returning the response that it |
| 72 // matches. Logging is done in the socket and in the outer DnsTransaction. | 71 // matches. Logging is done in the socket and in the outer DnsTransaction. |
| 73 class DnsUDPAttempt { | 72 class DnsUDPAttempt { |
| 74 public: | 73 public: |
| 75 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, | 74 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, |
| 76 const IPEndPoint& server, | |
| 77 scoped_ptr<DnsQuery> query, | 75 scoped_ptr<DnsQuery> query, |
| 78 const CompletionCallback& callback) | 76 const CompletionCallback& callback) |
| 79 : next_state_(STATE_NONE), | 77 : next_state_(STATE_NONE), |
| 80 received_malformed_response_(false), | 78 received_malformed_response_(false), |
| 81 socket_(socket.Pass()), | 79 socket_lease_(socket_lease.Pass()), |
| 82 server_(server), | |
| 83 query_(query.Pass()), | 80 query_(query.Pass()), |
| 84 callback_(callback) { | 81 callback_(callback) { |
| 85 } | 82 } |
| 86 | 83 |
| 87 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | 84 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously |
| 88 // and calls |callback| upon completion. | 85 // and calls |callback| upon completion. |
| 89 int Start() { | 86 int Start() { |
| 90 DCHECK_EQ(STATE_NONE, next_state_); | 87 DCHECK_EQ(STATE_NONE, next_state_); |
| 91 int rv = socket_->Connect(server_); | |
| 92 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 93 if (rv < 0) | |
| 94 return rv; | |
| 95 start_time_ = base::TimeTicks::Now(); | 88 start_time_ = base::TimeTicks::Now(); |
| 96 next_state_ = STATE_SEND_QUERY; | 89 next_state_ = STATE_SEND_QUERY; |
| 97 return DoLoop(OK); | 90 return DoLoop(OK); |
| 98 } | 91 } |
| 99 | 92 |
| 100 const DnsQuery* query() const { | 93 const DnsQuery* query() const { |
| 101 return query_.get(); | 94 return query_.get(); |
| 102 } | 95 } |
| 103 | 96 |
| 104 const DatagramClientSocket* socket() const { | 97 const BoundNetLog& socket_net_log() const { |
| 105 return socket_.get(); | 98 return socket_lease_->socket()->NetLog(); |
| 106 } | 99 } |
| 107 | 100 |
| 108 // Returns the response or NULL if has not received a matching response from | 101 // Returns the response or NULL if has not received a matching response from |
| 109 // the server. | 102 // the server. |
| 110 const DnsResponse* response() const { | 103 const DnsResponse* response() const { |
| 111 const DnsResponse* resp = response_.get(); | 104 const DnsResponse* resp = response_.get(); |
| 112 return (resp != NULL && resp->IsValid()) ? resp : NULL; | 105 return (resp != NULL && resp->IsValid()) ? resp : NULL; |
| 113 } | 106 } |
| 114 | 107 |
| 115 // Returns a Value representing the received response, along with a reference | 108 // Returns a Value representing the received response, along with a reference |
| 116 // to the NetLog source source of the UDP socket used. The request must have | 109 // to the NetLog source source of the UDP socket used. The request must have |
| 117 // completed before this is called. | 110 // completed before this is called. |
| 118 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { | 111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { |
| 119 DCHECK(response_->IsValid()); | 112 DCHECK(response_->IsValid()); |
| 120 | 113 |
| 121 DictionaryValue* dict = new DictionaryValue(); | 114 DictionaryValue* dict = new DictionaryValue(); |
| 122 dict->SetInteger("rcode", response_->rcode()); | 115 dict->SetInteger("rcode", response_->rcode()); |
| 123 dict->SetInteger("answer_count", response_->answer_count()); | 116 dict->SetInteger("answer_count", response_->answer_count()); |
| 124 socket_->NetLog().source().AddToEventParameters(dict); | 117 socket_net_log().source().AddToEventParameters(dict); |
| 125 return dict; | 118 return dict; |
| 126 } | 119 } |
| 127 | 120 |
| 128 private: | 121 private: |
| 129 enum State { | 122 enum State { |
| 130 STATE_SEND_QUERY, | 123 STATE_SEND_QUERY, |
| 131 STATE_SEND_QUERY_COMPLETE, | 124 STATE_SEND_QUERY_COMPLETE, |
| 132 STATE_READ_RESPONSE, | 125 STATE_READ_RESPONSE, |
| 133 STATE_READ_RESPONSE_COMPLETE, | 126 STATE_READ_RESPONSE_COMPLETE, |
| 134 STATE_NONE, | 127 STATE_NONE, |
| 135 }; | 128 }; |
| 136 | 129 |
| 130 DatagramClientSocket* socket() { |
| 131 return socket_lease_->socket(); |
| 132 } |
| 133 |
| 137 int DoLoop(int result) { | 134 int DoLoop(int result) { |
| 138 CHECK_NE(STATE_NONE, next_state_); | 135 CHECK_NE(STATE_NONE, next_state_); |
| 139 int rv = result; | 136 int rv = result; |
| 140 do { | 137 do { |
| 141 State state = next_state_; | 138 State state = next_state_; |
| 142 next_state_ = STATE_NONE; | 139 next_state_ = STATE_NONE; |
| 143 switch (state) { | 140 switch (state) { |
| 144 case STATE_SEND_QUERY: | 141 case STATE_SEND_QUERY: |
| 145 rv = DoSendQuery(); | 142 rv = DoSendQuery(); |
| 146 break; | 143 break; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 167 base::TimeTicks::Now() - start_time_); | 164 base::TimeTicks::Now() - start_time_); |
| 168 } else if (rv != ERR_IO_PENDING) { | 165 } else if (rv != ERR_IO_PENDING) { |
| 169 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", | 166 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", |
| 170 base::TimeTicks::Now() - start_time_); | 167 base::TimeTicks::Now() - start_time_); |
| 171 } | 168 } |
| 172 return rv; | 169 return rv; |
| 173 } | 170 } |
| 174 | 171 |
| 175 int DoSendQuery() { | 172 int DoSendQuery() { |
| 176 next_state_ = STATE_SEND_QUERY_COMPLETE; | 173 next_state_ = STATE_SEND_QUERY_COMPLETE; |
| 177 return socket_->Write(query_->io_buffer(), | 174 return socket()->Write(query_->io_buffer(), |
| 178 query_->io_buffer()->size(), | 175 query_->io_buffer()->size(), |
| 179 base::Bind(&DnsUDPAttempt::OnIOComplete, | 176 base::Bind(&DnsUDPAttempt::OnIOComplete, |
| 180 base::Unretained(this))); | 177 base::Unretained(this))); |
| 181 } | 178 } |
| 182 | 179 |
| 183 int DoSendQueryComplete(int rv) { | 180 int DoSendQueryComplete(int rv) { |
| 184 DCHECK_NE(ERR_IO_PENDING, rv); | 181 DCHECK_NE(ERR_IO_PENDING, rv); |
| 185 if (rv < 0) | 182 if (rv < 0) |
| 186 return rv; | 183 return rv; |
| 187 | 184 |
| 188 // Writing to UDP should not result in a partial datagram. | 185 // Writing to UDP should not result in a partial datagram. |
| 189 if (rv != query_->io_buffer()->size()) | 186 if (rv != query_->io_buffer()->size()) |
| 190 return ERR_MSG_TOO_BIG; | 187 return ERR_MSG_TOO_BIG; |
| 191 | 188 |
| 192 next_state_ = STATE_READ_RESPONSE; | 189 next_state_ = STATE_READ_RESPONSE; |
| 193 return OK; | 190 return OK; |
| 194 } | 191 } |
| 195 | 192 |
| 196 int DoReadResponse() { | 193 int DoReadResponse() { |
| 197 next_state_ = STATE_READ_RESPONSE_COMPLETE; | 194 next_state_ = STATE_READ_RESPONSE_COMPLETE; |
| 198 response_.reset(new DnsResponse()); | 195 response_.reset(new DnsResponse()); |
| 199 return socket_->Read(response_->io_buffer(), | 196 return socket()->Read(response_->io_buffer(), |
| 200 response_->io_buffer()->size(), | 197 response_->io_buffer()->size(), |
| 201 base::Bind(&DnsUDPAttempt::OnIOComplete, | 198 base::Bind(&DnsUDPAttempt::OnIOComplete, |
| 202 base::Unretained(this))); | 199 base::Unretained(this))); |
| 203 } | 200 } |
| 204 | 201 |
| 205 int DoReadResponseComplete(int rv) { | 202 int DoReadResponseComplete(int rv) { |
| 206 DCHECK_NE(ERR_IO_PENDING, rv); | 203 DCHECK_NE(ERR_IO_PENDING, rv); |
| 207 if (rv < 0) | 204 if (rv < 0) |
| 208 return rv; | 205 return rv; |
| 209 | 206 |
| 210 DCHECK(rv); | 207 DCHECK(rv); |
| 211 if (!response_->InitParse(rv, *query_)) { | 208 if (!response_->InitParse(rv, *query_)) { |
| 212 // Other implementations simply ignore mismatched responses. Since each | 209 // Other implementations simply ignore mismatched responses. Since each |
| (...skipping 20 matching lines...) Expand all Loading... |
| 233 void OnIOComplete(int rv) { | 230 void OnIOComplete(int rv) { |
| 234 rv = DoLoop(rv); | 231 rv = DoLoop(rv); |
| 235 if (rv != ERR_IO_PENDING) | 232 if (rv != ERR_IO_PENDING) |
| 236 callback_.Run(rv); | 233 callback_.Run(rv); |
| 237 } | 234 } |
| 238 | 235 |
| 239 State next_state_; | 236 State next_state_; |
| 240 bool received_malformed_response_; | 237 bool received_malformed_response_; |
| 241 base::TimeTicks start_time_; | 238 base::TimeTicks start_time_; |
| 242 | 239 |
| 243 scoped_ptr<DatagramClientSocket> socket_; | 240 scoped_ptr<DnsSession::SocketLease> socket_lease_; |
| 244 IPEndPoint server_; | |
| 245 scoped_ptr<DnsQuery> query_; | 241 scoped_ptr<DnsQuery> query_; |
| 246 | 242 |
| 247 scoped_ptr<DnsResponse> response_; | 243 scoped_ptr<DnsResponse> response_; |
| 248 | 244 |
| 249 CompletionCallback callback_; | 245 CompletionCallback callback_; |
| 250 | 246 |
| 251 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 247 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); |
| 252 }; | 248 }; |
| 253 | 249 |
| 254 // ---------------------------------------------------------------------------- | 250 // ---------------------------------------------------------------------------- |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 | 390 |
| 395 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); | 391 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); |
| 396 callback.Run(this, result.rv, response); | 392 callback.Run(this, result.rv, response); |
| 397 } | 393 } |
| 398 | 394 |
| 399 // Makes another attempt at the current name, |qnames_.front()|, using the | 395 // Makes another attempt at the current name, |qnames_.front()|, using the |
| 400 // next nameserver. | 396 // next nameserver. |
| 401 AttemptResult MakeAttempt() { | 397 AttemptResult MakeAttempt() { |
| 402 unsigned attempt_number = attempts_.size(); | 398 unsigned attempt_number = attempts_.size(); |
| 403 | 399 |
| 404 #if defined(OS_WIN) | |
| 405 // Avoid the Windows firewall warning about explicit UDP binding. | |
| 406 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413 | |
| 407 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND; | |
| 408 #else | |
| 409 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND; | |
| 410 #endif | |
| 411 | |
| 412 scoped_ptr<DatagramClientSocket> socket( | |
| 413 session_->socket_factory()->CreateDatagramClientSocket( | |
| 414 bind_type, | |
| 415 base::Bind(&base::RandInt), | |
| 416 net_log_.net_log(), | |
| 417 net_log_.source())); | |
| 418 | |
| 419 uint16 id = session_->NextQueryId(); | 400 uint16 id = session_->NextQueryId(); |
| 420 scoped_ptr<DnsQuery> query; | 401 scoped_ptr<DnsQuery> query; |
| 421 if (attempts_.empty()) { | 402 if (attempts_.empty()) { |
| 422 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | 403 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); |
| 423 } else { | 404 } else { |
| 424 query.reset(attempts_[0]->query()->CloneWithNewId(id)); | 405 query.reset(attempts_[0]->query()->CloneWithNewId(id)); |
| 425 } | 406 } |
| 426 | 407 |
| 427 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, | |
| 428 socket->NetLog().source().ToEventParametersCallback()); | |
| 429 | |
| 430 const DnsConfig& config = session_->config(); | 408 const DnsConfig& config = session_->config(); |
| 431 | 409 |
| 432 unsigned server_index = first_server_index_ + | 410 unsigned server_index = first_server_index_ + |
| 433 (attempt_number % config.nameservers.size()); | 411 (attempt_number % config.nameservers.size()); |
| 434 | 412 |
| 413 scoped_ptr<DnsSession::SocketLease> lease = |
| 414 session_->AllocateSocket(server_index, net_log_.source()); |
| 415 |
| 416 bool got_socket = !!lease.get(); |
| 417 |
| 435 DnsUDPAttempt* attempt = new DnsUDPAttempt( | 418 DnsUDPAttempt* attempt = new DnsUDPAttempt( |
| 436 socket.Pass(), | 419 lease.Pass(), |
| 437 config.nameservers[server_index], | |
| 438 query.Pass(), | 420 query.Pass(), |
| 439 base::Bind(&DnsTransactionImpl::OnAttemptComplete, | 421 base::Bind(&DnsTransactionImpl::OnAttemptComplete, |
| 440 base::Unretained(this), | 422 base::Unretained(this), |
| 441 attempt_number)); | 423 attempt_number)); |
| 442 | 424 |
| 443 attempts_.push_back(attempt); | 425 attempts_.push_back(attempt); |
| 444 | 426 |
| 427 if (!got_socket) |
| 428 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); |
| 429 |
| 430 net_log_.AddEvent( |
| 431 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, |
| 432 attempt->socket_net_log().source().ToEventParametersCallback()); |
| 433 |
| 445 int rv = attempt->Start(); | 434 int rv = attempt->Start(); |
| 446 if (rv == ERR_IO_PENDING) { | 435 if (rv == ERR_IO_PENDING) { |
| 447 timer_.Stop(); | 436 timer_.Stop(); |
| 448 base::TimeDelta timeout = session_->NextTimeout(attempt_number); | 437 base::TimeDelta timeout = session_->NextTimeout(attempt_number); |
| 449 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | 438 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); |
| 450 } | 439 } |
| 451 return AttemptResult(rv, attempt); | 440 return AttemptResult(rv, attempt); |
| 452 } | 441 } |
| 453 | 442 |
| 454 // Begins query for the current name. Makes the first attempt. | 443 // Begins query for the current name. Makes the first attempt. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 net_log_.EndEventWithNetErrorCode( | 493 net_log_.EndEventWithNetErrorCode( |
| 505 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); | 494 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); |
| 506 // Try next suffix. | 495 // Try next suffix. |
| 507 qnames_.pop_front(); | 496 qnames_.pop_front(); |
| 508 if (qnames_.empty()) { | 497 if (qnames_.empty()) { |
| 509 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); | 498 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); |
| 510 } else { | 499 } else { |
| 511 result = StartQuery(); | 500 result = StartQuery(); |
| 512 } | 501 } |
| 513 break; | 502 break; |
| 503 case ERR_CONNECTION_REFUSED: |
| 514 case ERR_DNS_TIMED_OUT: | 504 case ERR_DNS_TIMED_OUT: |
| 515 if (MoreAttemptsAllowed()) { | 505 if (MoreAttemptsAllowed()) { |
| 516 result = MakeAttempt(); | 506 result = MakeAttempt(); |
| 517 } else { | 507 } else { |
| 518 return result; | 508 return result; |
| 519 } | 509 } |
| 520 break; | 510 break; |
| 521 default: | 511 default: |
| 522 // Server failure. | 512 // Server failure. |
| 523 DCHECK(result.attempt); | 513 DCHECK(result.attempt); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 } // namespace | 589 } // namespace |
| 600 | 590 |
| 601 // static | 591 // static |
| 602 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( |
| 603 DnsSession* session) { | 593 DnsSession* session) { |
| 604 return scoped_ptr<DnsTransactionFactory>( | 594 return scoped_ptr<DnsTransactionFactory>( |
| 605 new DnsTransactionFactoryImpl(session)); | 595 new DnsTransactionFactoryImpl(session)); |
| 606 } | 596 } |
| 607 | 597 |
| 608 } // namespace net | 598 } // namespace net |
| OLD | NEW |