Chromium Code Reviews| 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 received_malformed_response_(false), | 71 received_malformed_response_(false), | 
| 75 socket_(socket.Pass()), | 72 socket_lease_(socket_lease.Pass()), | 
| 76 server_(server), | |
| 77 query_(query.Pass()), | 73 query_(query.Pass()), | 
| 78 callback_(callback) { | 74 callback_(callback) { | 
| 79 } | 75 } | 
| 80 | 76 | 
| 81 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | 77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously | 
| 82 // and calls |callback| upon completion. | 78 // and calls |callback| upon completion. | 
| 83 int Start() { | 79 int Start() { | 
| 84 DCHECK_EQ(STATE_NONE, next_state_); | 80 DCHECK_EQ(STATE_NONE, next_state_); | 
| 85 next_state_ = STATE_CONNECT; | 81 next_state_ = STATE_SEND_QUERY; | 
| 86 return DoLoop(OK); | 82 return DoLoop(OK); | 
| 87 } | 83 } | 
| 88 | 84 | 
| 89 const DnsQuery* query() const { | 85 const DnsQuery* query() const { | 
| 90 return query_.get(); | 86 return query_.get(); | 
| 91 } | 87 } | 
| 92 | 88 | 
| 93 const DatagramClientSocket* socket() const { | 89 const DatagramClientSocket* socket() const { | 
| 
 
szym
2012/09/26 11:16:12
This is used only to get the NetLog::Source. While
 
Deprecated (see juliatuttle)
2012/09/26 20:44:50
Done.
 
 | |
| 94 return socket_.get(); | 90 return socket_lease_->socket(); | 
| 95 } | 91 } | 
| 96 | 92 | 
| 97 // Returns the response or NULL if has not received a matching response from | 93 // Returns the response or NULL if has not received a matching response from | 
| 98 // the server. | 94 // the server. | 
| 99 const DnsResponse* response() const { | 95 const DnsResponse* response() const { | 
| 100 const DnsResponse* resp = response_.get(); | 96 const DnsResponse* resp = response_.get(); | 
| 101 return (resp != NULL && resp->IsValid()) ? resp : NULL; | 97 return (resp != NULL && resp->IsValid()) ? resp : NULL; | 
| 102 } | 98 } | 
| 103 | 99 | 
| 104 // Returns a Value representing the received response, along with a reference | 100 // Returns a Value representing the received response, along with a reference | 
| 105 // to the NetLog source source of the UDP socket used. The request must have | 101 // to the NetLog source source of the UDP socket used. The request must have | 
| 106 // completed before this is called. | 102 // completed before this is called. | 
| 107 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { | 103 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { | 
| 108 DCHECK(response_->IsValid()); | 104 DCHECK(response_->IsValid()); | 
| 109 | 105 | 
| 110 DictionaryValue* dict = new DictionaryValue(); | 106 DictionaryValue* dict = new DictionaryValue(); | 
| 111 dict->SetInteger("rcode", response_->rcode()); | 107 dict->SetInteger("rcode", response_->rcode()); | 
| 112 dict->SetInteger("answer_count", response_->answer_count()); | 108 dict->SetInteger("answer_count", response_->answer_count()); | 
| 113 socket_->NetLog().source().AddToEventParameters(dict); | 109 socket()->NetLog().source().AddToEventParameters(dict); | 
| 114 return dict; | 110 return dict; | 
| 115 } | 111 } | 
| 116 | 112 | 
| 117 private: | 113 private: | 
| 118 enum State { | 114 enum State { | 
| 119 STATE_CONNECT, | |
| 120 STATE_SEND_QUERY, | 115 STATE_SEND_QUERY, | 
| 121 STATE_SEND_QUERY_COMPLETE, | 116 STATE_SEND_QUERY_COMPLETE, | 
| 122 STATE_READ_RESPONSE, | 117 STATE_READ_RESPONSE, | 
| 123 STATE_READ_RESPONSE_COMPLETE, | 118 STATE_READ_RESPONSE_COMPLETE, | 
| 124 STATE_NONE, | 119 STATE_NONE, | 
| 125 }; | 120 }; | 
| 126 | 121 | 
| 122 DatagramClientSocket* my_socket() { | |
| 123 return socket_lease_->socket(); | |
| 124 } | |
| 125 | |
| 127 int DoLoop(int result) { | 126 int DoLoop(int result) { | 
| 128 CHECK_NE(STATE_NONE, next_state_); | 127 CHECK_NE(STATE_NONE, next_state_); | 
| 129 int rv = result; | 128 int rv = result; | 
| 130 do { | 129 do { | 
| 131 State state = next_state_; | 130 State state = next_state_; | 
| 132 next_state_ = STATE_NONE; | 131 next_state_ = STATE_NONE; | 
| 133 switch (state) { | 132 switch (state) { | 
| 134 case STATE_CONNECT: | |
| 135 rv = DoConnect(); | |
| 136 break; | |
| 137 case STATE_SEND_QUERY: | 133 case STATE_SEND_QUERY: | 
| 138 rv = DoSendQuery(); | 134 rv = DoSendQuery(); | 
| 139 break; | 135 break; | 
| 140 case STATE_SEND_QUERY_COMPLETE: | 136 case STATE_SEND_QUERY_COMPLETE: | 
| 141 rv = DoSendQueryComplete(rv); | 137 rv = DoSendQueryComplete(rv); | 
| 142 break; | 138 break; | 
| 143 case STATE_READ_RESPONSE: | 139 case STATE_READ_RESPONSE: | 
| 144 rv = DoReadResponse(); | 140 rv = DoReadResponse(); | 
| 145 break; | 141 break; | 
| 146 case STATE_READ_RESPONSE_COMPLETE: | 142 case STATE_READ_RESPONSE_COMPLETE: | 
| 147 rv = DoReadResponseComplete(rv); | 143 rv = DoReadResponseComplete(rv); | 
| 148 break; | 144 break; | 
| 149 default: | 145 default: | 
| 150 NOTREACHED(); | 146 NOTREACHED(); | 
| 151 break; | 147 break; | 
| 152 } | 148 } | 
| 153 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 149 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 
| 154 // If we received a malformed response, and are now waiting for another one, | 150 // If we received a malformed response, and are now waiting for another one, | 
| 155 // indicate to the transaction that the server might be misbehaving. | 151 // indicate to the transaction that the server might be misbehaving. | 
| 156 if (rv == ERR_IO_PENDING && received_malformed_response_) | 152 if (rv == ERR_IO_PENDING && received_malformed_response_) | 
| 157 return ERR_DNS_MALFORMED_RESPONSE; | 153 return ERR_DNS_MALFORMED_RESPONSE; | 
| 158 return rv; | 154 return rv; | 
| 159 } | 155 } | 
| 160 | 156 | 
| 161 int DoConnect() { | |
| 162 next_state_ = STATE_SEND_QUERY; | |
| 163 return socket_->Connect(server_); | |
| 164 } | |
| 165 | |
| 166 int DoSendQuery() { | 157 int DoSendQuery() { | 
| 167 next_state_ = STATE_SEND_QUERY_COMPLETE; | 158 next_state_ = STATE_SEND_QUERY_COMPLETE; | 
| 168 return socket_->Write(query_->io_buffer(), | 159 return my_socket()->Write(query_->io_buffer(), | 
| 169 query_->io_buffer()->size(), | 160 query_->io_buffer()->size(), | 
| 170 base::Bind(&DnsUDPAttempt::OnIOComplete, | 161 base::Bind(&DnsUDPAttempt::OnIOComplete, | 
| 171 base::Unretained(this))); | 162 base::Unretained(this))); | 
| 172 } | 163 } | 
| 173 | 164 | 
| 174 int DoSendQueryComplete(int rv) { | 165 int DoSendQueryComplete(int rv) { | 
| 175 DCHECK_NE(ERR_IO_PENDING, rv); | 166 DCHECK_NE(ERR_IO_PENDING, rv); | 
| 176 if (rv < 0) | 167 if (rv < 0) | 
| 177 return rv; | 168 return rv; | 
| 178 | 169 | 
| 179 // Writing to UDP should not result in a partial datagram. | 170 // Writing to UDP should not result in a partial datagram. | 
| 180 if (rv != query_->io_buffer()->size()) | 171 if (rv != query_->io_buffer()->size()) | 
| 181 return ERR_MSG_TOO_BIG; | 172 return ERR_MSG_TOO_BIG; | 
| 182 | 173 | 
| 183 next_state_ = STATE_READ_RESPONSE; | 174 next_state_ = STATE_READ_RESPONSE; | 
| 184 return OK; | 175 return OK; | 
| 185 } | 176 } | 
| 186 | 177 | 
| 187 int DoReadResponse() { | 178 int DoReadResponse() { | 
| 188 next_state_ = STATE_READ_RESPONSE_COMPLETE; | 179 next_state_ = STATE_READ_RESPONSE_COMPLETE; | 
| 189 response_.reset(new DnsResponse()); | 180 response_.reset(new DnsResponse()); | 
| 190 return socket_->Read(response_->io_buffer(), | 181 return my_socket()->Read(response_->io_buffer(), | 
| 191 response_->io_buffer()->size(), | 182 response_->io_buffer()->size(), | 
| 192 base::Bind(&DnsUDPAttempt::OnIOComplete, | 183 base::Bind(&DnsUDPAttempt::OnIOComplete, | 
| 193 base::Unretained(this))); | 184 base::Unretained(this))); | 
| 194 } | 185 } | 
| 195 | 186 | 
| 196 int DoReadResponseComplete(int rv) { | 187 int DoReadResponseComplete(int rv) { | 
| 197 DCHECK_NE(ERR_IO_PENDING, rv); | 188 DCHECK_NE(ERR_IO_PENDING, rv); | 
| 198 if (rv < 0) | 189 if (rv < 0) | 
| 199 return rv; | 190 return rv; | 
| 200 | 191 | 
| 201 DCHECK(rv); | 192 DCHECK(rv); | 
| 202 if (!response_->InitParse(rv, *query_)) { | 193 if (!response_->InitParse(rv, *query_)) { | 
| 203 // Other implementations simply ignore mismatched responses. Since each | 194 // Other implementations simply ignore mismatched responses. Since each | 
| (...skipping 19 matching lines...) Expand all Loading... | |
| 223 | 214 | 
| 224 void OnIOComplete(int rv) { | 215 void OnIOComplete(int rv) { | 
| 225 rv = DoLoop(rv); | 216 rv = DoLoop(rv); | 
| 226 if (rv != ERR_IO_PENDING) | 217 if (rv != ERR_IO_PENDING) | 
| 227 callback_.Run(rv); | 218 callback_.Run(rv); | 
| 228 } | 219 } | 
| 229 | 220 | 
| 230 State next_state_; | 221 State next_state_; | 
| 231 bool received_malformed_response_; | 222 bool received_malformed_response_; | 
| 232 | 223 | 
| 233 scoped_ptr<DatagramClientSocket> socket_; | 224 scoped_ptr<DnsSession::SocketLease> socket_lease_; | 
| 234 IPEndPoint server_; | |
| 235 scoped_ptr<DnsQuery> query_; | 225 scoped_ptr<DnsQuery> query_; | 
| 236 | 226 | 
| 237 scoped_ptr<DnsResponse> response_; | 227 scoped_ptr<DnsResponse> response_; | 
| 238 | 228 | 
| 239 CompletionCallback callback_; | 229 CompletionCallback callback_; | 
| 240 | 230 | 
| 241 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 231 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); | 
| 242 }; | 232 }; | 
| 243 | 233 | 
| 244 // ---------------------------------------------------------------------------- | 234 // ---------------------------------------------------------------------------- | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 384 | 374 | 
| 385 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); | 375 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); | 
| 386 callback.Run(this, result.rv, response); | 376 callback.Run(this, result.rv, response); | 
| 387 } | 377 } | 
| 388 | 378 | 
| 389 // Makes another attempt at the current name, |qnames_.front()|, using the | 379 // Makes another attempt at the current name, |qnames_.front()|, using the | 
| 390 // next nameserver. | 380 // next nameserver. | 
| 391 AttemptResult MakeAttempt() { | 381 AttemptResult MakeAttempt() { | 
| 392 unsigned attempt_number = attempts_.size(); | 382 unsigned attempt_number = attempts_.size(); | 
| 393 | 383 | 
| 394 #if defined(OS_WIN) | |
| 395 // Avoid the Windows firewall warning about explicit UDP binding. | |
| 396 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413 | |
| 397 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND; | |
| 398 #else | |
| 399 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND; | |
| 400 #endif | |
| 401 | |
| 402 scoped_ptr<DatagramClientSocket> socket( | |
| 403 session_->socket_factory()->CreateDatagramClientSocket( | |
| 404 bind_type, | |
| 405 base::Bind(&base::RandInt), | |
| 406 net_log_.net_log(), | |
| 407 net_log_.source())); | |
| 408 | |
| 409 uint16 id = session_->NextQueryId(); | 384 uint16 id = session_->NextQueryId(); | 
| 410 scoped_ptr<DnsQuery> query; | 385 scoped_ptr<DnsQuery> query; | 
| 411 if (attempts_.empty()) { | 386 if (attempts_.empty()) { | 
| 412 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | 387 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); | 
| 413 } else { | 388 } else { | 
| 414 query.reset(attempts_[0]->query()->CloneWithNewId(id)); | 389 query.reset(attempts_[0]->query()->CloneWithNewId(id)); | 
| 415 } | 390 } | 
| 416 | 391 | 
| 417 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, | |
| 418 socket->NetLog().source().ToEventParametersCallback()); | |
| 419 | |
| 420 const DnsConfig& config = session_->config(); | 392 const DnsConfig& config = session_->config(); | 
| 421 | 393 | 
| 422 unsigned server_index = first_server_index_ + | 394 unsigned server_index = first_server_index_ + | 
| 423 (attempt_number % config.nameservers.size()); | 395 (attempt_number % config.nameservers.size()); | 
| 424 | 396 | 
| 425 DnsUDPAttempt* attempt = new DnsUDPAttempt( | 397 DnsUDPAttempt* attempt = new DnsUDPAttempt( | 
| 426 socket.Pass(), | 398 session_->AllocateSocket(server_index, net_log_.source()), | 
| 427 config.nameservers[server_index], | |
| 428 query.Pass(), | 399 query.Pass(), | 
| 429 base::Bind(&DnsTransactionImpl::OnAttemptComplete, | 400 base::Bind(&DnsTransactionImpl::OnAttemptComplete, | 
| 430 base::Unretained(this), | 401 base::Unretained(this), | 
| 431 attempt_number)); | 402 attempt_number)); | 
| 432 | 403 | 
| 404 net_log_.AddEvent( | |
| 405 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, | |
| 406 attempt->socket()->NetLog().source().ToEventParametersCallback()); | |
| 407 | |
| 433 attempts_.push_back(attempt); | 408 attempts_.push_back(attempt); | 
| 434 | 409 | 
| 435 int rv = attempt->Start(); | 410 int rv = attempt->Start(); | 
| 436 if (rv == ERR_IO_PENDING) { | 411 if (rv == ERR_IO_PENDING) { | 
| 437 timer_.Stop(); | 412 timer_.Stop(); | 
| 438 base::TimeDelta timeout = session_->NextTimeout(attempt_number); | 413 base::TimeDelta timeout = session_->NextTimeout(attempt_number); | 
| 439 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | 414 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); | 
| 440 } | 415 } | 
| 441 return AttemptResult(rv, attempt); | 416 return AttemptResult(rv, attempt); | 
| 442 } | 417 } | 
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 } // namespace | 564 } // namespace | 
| 590 | 565 | 
| 591 // static | 566 // static | 
| 592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 567 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( | 
| 593 DnsSession* session) { | 568 DnsSession* session) { | 
| 594 return scoped_ptr<DnsTransactionFactory>( | 569 return scoped_ptr<DnsTransactionFactory>( | 
| 595 new DnsTransactionFactoryImpl(session)); | 570 new DnsTransactionFactoryImpl(session)); | 
| 596 } | 571 } | 
| 597 | 572 | 
| 598 } // namespace net | 573 } // namespace net | 
| OLD | NEW |