| 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 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
| 13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/memory/scoped_vector.h" | 14 #include "base/memory/scoped_vector.h" |
| 15 #include "base/memory/weak_ptr.h" | 15 #include "base/memory/weak_ptr.h" |
| 16 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
| 17 #include "base/rand_util.h" | |
| 18 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 19 #include "base/string_piece.h" | 18 #include "base/string_piece.h" |
| 20 #include "base/threading/non_thread_safe.h" | 19 #include "base/threading/non_thread_safe.h" |
| 21 #include "base/timer.h" | 20 #include "base/timer.h" |
| 22 #include "base/values.h" | 21 #include "base/values.h" |
| 23 #include "net/base/completion_callback.h" | 22 #include "net/base/completion_callback.h" |
| 24 #include "net/base/dns_util.h" | 23 #include "net/base/dns_util.h" |
| 25 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
| 26 #include "net/base/ip_endpoint.h" | 25 #include "net/base/ip_endpoint.h" |
| 27 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 28 #include "net/base/net_log.h" | 27 #include "net/base/net_log.h" |
| 29 #include "net/dns/dns_protocol.h" | 28 #include "net/dns/dns_protocol.h" |
| 30 #include "net/dns/dns_query.h" | 29 #include "net/dns/dns_query.h" |
| 31 #include "net/dns/dns_response.h" | 30 #include "net/dns/dns_response.h" |
| 32 #include "net/dns/dns_session.h" | 31 #include "net/dns/dns_session.h" |
| 33 #include "net/socket/client_socket_factory.h" | |
| 34 #include "net/udp/datagram_client_socket.h" | 32 #include "net/udp/datagram_client_socket.h" |
| 35 | 33 |
| 36 namespace net { | 34 namespace net { |
| 37 | 35 |
| 38 namespace { | 36 namespace { |
| 39 | 37 |
| 40 // Count labels in the fully-qualified name in DNS format. | 38 // Count labels in the fully-qualified name in DNS format. |
| 41 int CountLabels(const std::string& name) { | 39 int CountLabels(const std::string& name) { |
| 42 size_t count = 0; | 40 size_t count = 0; |
| 43 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1) | 41 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 59 return dict; | 57 return dict; |
| 60 }; | 58 }; |
| 61 | 59 |
| 62 // ---------------------------------------------------------------------------- | 60 // ---------------------------------------------------------------------------- |
| 63 | 61 |
| 64 // A single asynchronous DNS exchange over UDP, which consists of sending out a | 62 // A single asynchronous DNS exchange over UDP, which consists of sending out a |
| 65 // DNS query, waiting for a response, and returning the response that it | 63 // DNS query, waiting for a response, and returning the response that it |
| 66 // matches. Logging is done in the socket and in the outer DnsTransaction. | 64 // matches. Logging is done in the socket and in the outer DnsTransaction. |
| 67 class DnsUDPAttempt { | 65 class DnsUDPAttempt { |
| 68 public: | 66 public: |
| 69 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, | 67 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, |
| 70 const IPEndPoint& server, | |
| 71 scoped_ptr<DnsQuery> query, | 68 scoped_ptr<DnsQuery> query, |
| 72 const CompletionCallback& callback) | 69 const CompletionCallback& callback) |
| 73 : next_state_(STATE_NONE), | 70 : next_state_(STATE_NONE), |
| 74 socket_(socket.Pass()), | 71 socket_lease_(socket_lease.Pass()), |
| 75 server_(server), | |
| 76 query_(query.Pass()), | 72 query_(query.Pass()), |
| 77 callback_(callback) { | 73 callback_(callback) { |
| 78 } | 74 } |
| 79 | 75 |
| 80 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | 76 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously |
| 81 // and calls |callback| upon completion. | 77 // and calls |callback| upon completion. |
| 82 int Start() { | 78 int Start() { |
| 83 DCHECK_EQ(STATE_NONE, next_state_); | 79 DCHECK_EQ(STATE_NONE, next_state_); |
| 84 next_state_ = STATE_CONNECT; | 80 next_state_ = STATE_SEND_QUERY; |
| 85 return DoLoop(OK); | 81 return DoLoop(OK); |
| 86 } | 82 } |
| 87 | 83 |
| 88 const DnsQuery* query() const { | 84 const DnsQuery* query() const { |
| 89 return query_.get(); | 85 return query_.get(); |
| 90 } | 86 } |
| 91 | 87 |
| 92 const DatagramClientSocket* socket() const { | 88 const DatagramClientSocket* socket() const { |
| 93 return socket_.get(); | 89 return socket_lease_->socket(); |
| 94 } | 90 } |
| 95 | 91 |
| 96 // Returns the response or NULL if has not received a matching response from | 92 // Returns the response or NULL if has not received a matching response from |
| 97 // the server. | 93 // the server. |
| 98 const DnsResponse* response() const { | 94 const DnsResponse* response() const { |
| 99 const DnsResponse* resp = response_.get(); | 95 const DnsResponse* resp = response_.get(); |
| 100 return (resp != NULL && resp->IsValid()) ? resp : NULL; | 96 return (resp != NULL && resp->IsValid()) ? resp : NULL; |
| 101 } | 97 } |
| 102 | 98 |
| 103 // Returns a Value representing the received response, along with a reference | 99 // Returns a Value representing the received response, along with a reference |
| 104 // to the NetLog source source of the UDP socket used. The request must have | 100 // to the NetLog source source of the UDP socket used. The request must have |
| 105 // completed before this is called. | 101 // completed before this is called. |
| 106 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { | 102 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { |
| 107 DCHECK(response_->IsValid()); | 103 DCHECK(response_->IsValid()); |
| 108 | 104 |
| 109 DictionaryValue* dict = new DictionaryValue(); | 105 DictionaryValue* dict = new DictionaryValue(); |
| 110 dict->SetInteger("rcode", response_->rcode()); | 106 dict->SetInteger("rcode", response_->rcode()); |
| 111 dict->SetInteger("answer_count", response_->answer_count()); | 107 dict->SetInteger("answer_count", response_->answer_count()); |
| 112 socket_->NetLog().source().AddToEventParameters(dict); | 108 socket()->NetLog().source().AddToEventParameters(dict); |
| 113 return dict; | 109 return dict; |
| 114 } | 110 } |
| 115 | 111 |
| 116 private: | 112 private: |
| 117 enum State { | 113 enum State { |
| 118 STATE_CONNECT, | |
| 119 STATE_SEND_QUERY, | 114 STATE_SEND_QUERY, |
| 120 STATE_SEND_QUERY_COMPLETE, | 115 STATE_SEND_QUERY_COMPLETE, |
| 121 STATE_READ_RESPONSE, | 116 STATE_READ_RESPONSE, |
| 122 STATE_READ_RESPONSE_COMPLETE, | 117 STATE_READ_RESPONSE_COMPLETE, |
| 123 STATE_NONE, | 118 STATE_NONE, |
| 124 }; | 119 }; |
| 125 | 120 |
| 121 DatagramClientSocket* my_socket() { |
| 122 return socket_lease_->socket(); |
| 123 } |
| 124 |
| 126 int DoLoop(int result) { | 125 int DoLoop(int result) { |
| 127 CHECK_NE(STATE_NONE, next_state_); | 126 CHECK_NE(STATE_NONE, next_state_); |
| 128 int rv = result; | 127 int rv = result; |
| 129 do { | 128 do { |
| 130 State state = next_state_; | 129 State state = next_state_; |
| 131 next_state_ = STATE_NONE; | 130 next_state_ = STATE_NONE; |
| 132 switch (state) { | 131 switch (state) { |
| 133 case STATE_CONNECT: | |
| 134 rv = DoConnect(); | |
| 135 break; | |
| 136 case STATE_SEND_QUERY: | 132 case STATE_SEND_QUERY: |
| 137 rv = DoSendQuery(); | 133 rv = DoSendQuery(); |
| 138 break; | 134 break; |
| 139 case STATE_SEND_QUERY_COMPLETE: | 135 case STATE_SEND_QUERY_COMPLETE: |
| 140 rv = DoSendQueryComplete(rv); | 136 rv = DoSendQueryComplete(rv); |
| 141 break; | 137 break; |
| 142 case STATE_READ_RESPONSE: | 138 case STATE_READ_RESPONSE: |
| 143 rv = DoReadResponse(); | 139 rv = DoReadResponse(); |
| 144 break; | 140 break; |
| 145 case STATE_READ_RESPONSE_COMPLETE: | 141 case STATE_READ_RESPONSE_COMPLETE: |
| 146 rv = DoReadResponseComplete(rv); | 142 rv = DoReadResponseComplete(rv); |
| 147 break; | 143 break; |
| 148 default: | 144 default: |
| 149 NOTREACHED(); | 145 NOTREACHED(); |
| 150 break; | 146 break; |
| 151 } | 147 } |
| 152 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 148 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 153 | 149 |
| 154 return rv; | 150 return rv; |
| 155 } | 151 } |
| 156 | 152 |
| 157 int DoConnect() { | |
| 158 next_state_ = STATE_SEND_QUERY; | |
| 159 return socket_->Connect(server_); | |
| 160 } | |
| 161 | |
| 162 int DoSendQuery() { | 153 int DoSendQuery() { |
| 163 next_state_ = STATE_SEND_QUERY_COMPLETE; | 154 next_state_ = STATE_SEND_QUERY_COMPLETE; |
| 164 return socket_->Write(query_->io_buffer(), | 155 return my_socket()->Write(query_->io_buffer(), |
| 165 query_->io_buffer()->size(), | 156 query_->io_buffer()->size(), |
| 166 base::Bind(&DnsUDPAttempt::OnIOComplete, | 157 base::Bind(&DnsUDPAttempt::OnIOComplete, |
| 167 base::Unretained(this))); | 158 base::Unretained(this))); |
| 168 } | 159 } |
| 169 | 160 |
| 170 int DoSendQueryComplete(int rv) { | 161 int DoSendQueryComplete(int rv) { |
| 171 DCHECK_NE(ERR_IO_PENDING, rv); | 162 DCHECK_NE(ERR_IO_PENDING, rv); |
| 172 if (rv < 0) | 163 if (rv < 0) |
| 173 return rv; | 164 return rv; |
| 174 | 165 |
| 175 // Writing to UDP should not result in a partial datagram. | 166 // Writing to UDP should not result in a partial datagram. |
| 176 if (rv != query_->io_buffer()->size()) | 167 if (rv != query_->io_buffer()->size()) |
| 177 return ERR_MSG_TOO_BIG; | 168 return ERR_MSG_TOO_BIG; |
| 178 | 169 |
| 179 next_state_ = STATE_READ_RESPONSE; | 170 next_state_ = STATE_READ_RESPONSE; |
| 180 return OK; | 171 return OK; |
| 181 } | 172 } |
| 182 | 173 |
| 183 int DoReadResponse() { | 174 int DoReadResponse() { |
| 184 next_state_ = STATE_READ_RESPONSE_COMPLETE; | 175 next_state_ = STATE_READ_RESPONSE_COMPLETE; |
| 185 response_.reset(new DnsResponse()); | 176 response_.reset(new DnsResponse()); |
| 186 return socket_->Read(response_->io_buffer(), | 177 return my_socket()->Read(response_->io_buffer(), |
| 187 response_->io_buffer()->size(), | 178 response_->io_buffer()->size(), |
| 188 base::Bind(&DnsUDPAttempt::OnIOComplete, | 179 base::Bind(&DnsUDPAttempt::OnIOComplete, |
| 189 base::Unretained(this))); | 180 base::Unretained(this))); |
| 190 } | 181 } |
| 191 | 182 |
| 192 int DoReadResponseComplete(int rv) { | 183 int DoReadResponseComplete(int rv) { |
| 193 DCHECK_NE(ERR_IO_PENDING, rv); | 184 DCHECK_NE(ERR_IO_PENDING, rv); |
| 194 if (rv < 0) | 185 if (rv < 0) |
| 195 return rv; | 186 return rv; |
| 196 | 187 |
| 197 DCHECK(rv); | 188 DCHECK(rv); |
| 198 if (!response_->InitParse(rv, *query_)) { | 189 if (!response_->InitParse(rv, *query_)) { |
| 199 // TODO(szym): Consider making this reaction less aggressive. | 190 // TODO(szym): Consider making this reaction less aggressive. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 216 } | 207 } |
| 217 | 208 |
| 218 void OnIOComplete(int rv) { | 209 void OnIOComplete(int rv) { |
| 219 rv = DoLoop(rv); | 210 rv = DoLoop(rv); |
| 220 if (rv != ERR_IO_PENDING) | 211 if (rv != ERR_IO_PENDING) |
| 221 callback_.Run(rv); | 212 callback_.Run(rv); |
| 222 } | 213 } |
| 223 | 214 |
| 224 State next_state_; | 215 State next_state_; |
| 225 | 216 |
| 226 scoped_ptr<DatagramClientSocket> socket_; | 217 scoped_ptr<DnsSession::SocketLease> socket_lease_; |
| 227 IPEndPoint server_; | |
| 228 scoped_ptr<DnsQuery> query_; | 218 scoped_ptr<DnsQuery> query_; |
| 229 | 219 |
| 230 scoped_ptr<DnsResponse> response_; | 220 scoped_ptr<DnsResponse> response_; |
| 231 | 221 |
| 232 CompletionCallback callback_; | 222 CompletionCallback callback_; |
| 233 | 223 |
| 234 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 224 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); |
| 235 }; | 225 }; |
| 236 | 226 |
| 237 // ---------------------------------------------------------------------------- | 227 // ---------------------------------------------------------------------------- |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 | 367 |
| 378 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); | 368 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); |
| 379 callback.Run(this, result.rv, response); | 369 callback.Run(this, result.rv, response); |
| 380 } | 370 } |
| 381 | 371 |
| 382 // Makes another attempt at the current name, |qnames_.front()|, using the | 372 // Makes another attempt at the current name, |qnames_.front()|, using the |
| 383 // next nameserver. | 373 // next nameserver. |
| 384 AttemptResult MakeAttempt() { | 374 AttemptResult MakeAttempt() { |
| 385 unsigned attempt_number = attempts_.size(); | 375 unsigned attempt_number = attempts_.size(); |
| 386 | 376 |
| 387 #if defined(OS_WIN) | |
| 388 // Avoid the Windows firewall warning about explicit UDP binding. | |
| 389 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413 | |
| 390 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND; | |
| 391 #else | |
| 392 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND; | |
| 393 #endif | |
| 394 | |
| 395 scoped_ptr<DatagramClientSocket> socket( | |
| 396 session_->socket_factory()->CreateDatagramClientSocket( | |
| 397 bind_type, | |
| 398 base::Bind(&base::RandInt), | |
| 399 net_log_.net_log(), | |
| 400 net_log_.source())); | |
| 401 | |
| 402 uint16 id = session_->NextQueryId(); | 377 uint16 id = session_->NextQueryId(); |
| 403 scoped_ptr<DnsQuery> query; | 378 scoped_ptr<DnsQuery> query; |
| 404 if (attempts_.empty()) { | 379 if (attempts_.empty()) { |
| 405 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | 380 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); |
| 406 } else { | 381 } else { |
| 407 query.reset(attempts_[0]->query()->CloneWithNewId(id)); | 382 query.reset(attempts_[0]->query()->CloneWithNewId(id)); |
| 408 } | 383 } |
| 409 | 384 |
| 410 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, | |
| 411 socket->NetLog().source().ToEventParametersCallback()); | |
| 412 | |
| 413 const DnsConfig& config = session_->config(); | 385 const DnsConfig& config = session_->config(); |
| 414 | 386 |
| 415 unsigned server_index = first_server_index_ + | 387 unsigned server_index = first_server_index_ + |
| 416 (attempt_number % config.nameservers.size()); | 388 (attempt_number % config.nameservers.size()); |
| 417 | 389 |
| 418 DnsUDPAttempt* attempt = new DnsUDPAttempt( | 390 DnsUDPAttempt* attempt = new DnsUDPAttempt( |
| 419 socket.Pass(), | 391 session_->AllocateSocket(server_index), |
| 420 config.nameservers[server_index], | |
| 421 query.Pass(), | 392 query.Pass(), |
| 422 base::Bind(&DnsTransactionImpl::OnAttemptComplete, | 393 base::Bind(&DnsTransactionImpl::OnAttemptComplete, |
| 423 base::Unretained(this), | 394 base::Unretained(this), |
| 424 attempt_number)); | 395 attempt_number)); |
| 425 | 396 |
| 397 net_log_.AddEvent( |
| 398 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, |
| 399 attempt->socket()->NetLog().source().ToEventParametersCallback()); |
| 400 |
| 426 attempts_.push_back(attempt); | 401 attempts_.push_back(attempt); |
| 427 | 402 |
| 428 int rv = attempt->Start(); | 403 int rv = attempt->Start(); |
| 429 if (rv == ERR_IO_PENDING) { | 404 if (rv == ERR_IO_PENDING) { |
| 430 timer_.Stop(); | 405 timer_.Stop(); |
| 431 base::TimeDelta timeout = session_->NextTimeout(attempt_number); | 406 base::TimeDelta timeout = session_->NextTimeout(attempt_number); |
| 432 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | 407 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); |
| 433 } | 408 } |
| 434 return AttemptResult(rv, attempt); | 409 return AttemptResult(rv, attempt); |
| 435 } | 410 } |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 579 } // namespace | 554 } // namespace |
| 580 | 555 |
| 581 // static | 556 // static |
| 582 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 557 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( |
| 583 DnsSession* session) { | 558 DnsSession* session) { |
| 584 return scoped_ptr<DnsTransactionFactory>( | 559 return scoped_ptr<DnsTransactionFactory>( |
| 585 new DnsTransactionFactoryImpl(session)); | 560 new DnsTransactionFactoryImpl(session)); |
| 586 } | 561 } |
| 587 | 562 |
| 588 } // namespace net | 563 } // namespace net |
| OLD | NEW |