| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
| 9 #include "base/values.h" | 9 #include "base/values.h" |
| 10 #include "net/base/dns_util.h" | |
| 11 #include "net/base/io_buffer.h" | 10 #include "net/base/io_buffer.h" |
| 12 #include "net/base/net_errors.h" | 11 #include "net/base/net_errors.h" |
| 12 #include "net/dns/dns_protocol.h" |
| 13 #include "net/dns/dns_query.h" | 13 #include "net/dns/dns_query.h" |
| 14 #include "net/dns/dns_response.h" | 14 #include "net/dns/dns_response.h" |
| 15 #include "net/dns/dns_session.h" |
| 15 #include "net/socket/client_socket_factory.h" | 16 #include "net/socket/client_socket_factory.h" |
| 16 #include "net/udp/datagram_client_socket.h" | 17 #include "net/udp/datagram_client_socket.h" |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 20 namespace { | 21 namespace { |
| 21 | 22 |
| 22 // Retry timeouts. | |
| 23 const int kTimeoutsMs[] = {3000, 5000, 11000}; | |
| 24 const int kMaxAttempts = arraysize(kTimeoutsMs); | |
| 25 | |
| 26 // Returns the string representation of an IPAddressNumber. | |
| 27 std::string IPAddressToString(const IPAddressNumber& ip_address) { | |
| 28 IPEndPoint ip_endpoint(ip_address, 0); | |
| 29 struct sockaddr_storage addr; | |
| 30 size_t addr_len = sizeof(addr); | |
| 31 struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr); | |
| 32 if (!ip_endpoint.ToSockAddr(sockaddr, &addr_len)) | |
| 33 return ""; | |
| 34 return NetAddressToString(sockaddr, addr_len); | |
| 35 } | |
| 36 | |
| 37 } | |
| 38 | |
| 39 DnsTransaction::Delegate::Delegate() { | |
| 40 } | |
| 41 | |
| 42 DnsTransaction::Delegate::~Delegate() { | |
| 43 while (!registered_transactions_.empty()) { | |
| 44 DnsTransaction* transaction = *registered_transactions_.begin(); | |
| 45 transaction->SetDelegate(NULL); | |
| 46 } | |
| 47 DCHECK(registered_transactions_.empty()); | |
| 48 } | |
| 49 | |
| 50 void DnsTransaction::Delegate::OnTransactionComplete( | |
| 51 int result, | |
| 52 const DnsTransaction* transaction, | |
| 53 const IPAddressList& ip_addresses) { | |
| 54 } | |
| 55 | |
| 56 void DnsTransaction::Delegate::Attach(DnsTransaction* transaction) { | |
| 57 DCHECK(registered_transactions_.find(transaction) == | |
| 58 registered_transactions_.end()); | |
| 59 registered_transactions_.insert(transaction); | |
| 60 } | |
| 61 | |
| 62 void DnsTransaction::Delegate::Detach(DnsTransaction* transaction) { | |
| 63 DCHECK(registered_transactions_.find(transaction) != | |
| 64 registered_transactions_.end()); | |
| 65 registered_transactions_.erase(transaction); | |
| 66 } | |
| 67 | |
| 68 namespace { | |
| 69 | |
| 70 class DnsTransactionStartParameters : public NetLog::EventParameters { | 23 class DnsTransactionStartParameters : public NetLog::EventParameters { |
| 71 public: | 24 public: |
| 72 DnsTransactionStartParameters(const IPEndPoint& dns_server, | 25 DnsTransactionStartParameters(const IPEndPoint& dns_server, |
| 73 const DnsTransaction::Key& key, | 26 const base::StringPiece& qname, |
| 27 uint16 qtype, |
| 74 const NetLog::Source& source) | 28 const NetLog::Source& source) |
| 75 : dns_server_(dns_server), key_(key), source_(source) {} | 29 : dns_server_(dns_server), |
| 30 qname_(qname.data(), qname.length()), |
| 31 qtype_(qtype), |
| 32 source_(source) {} |
| 76 | 33 |
| 77 virtual Value* ToValue() const { | 34 virtual Value* ToValue() const { |
| 78 std::string hostname; | |
| 79 DnsResponseBuffer( | |
| 80 reinterpret_cast<const uint8*>(key_.first.c_str()), key_.first.size()). | |
| 81 DNSName(&hostname); | |
| 82 | |
| 83 DictionaryValue* dict = new DictionaryValue(); | 35 DictionaryValue* dict = new DictionaryValue(); |
| 84 dict->SetString("dns_server", dns_server_.ToString()); | 36 dict->SetString("dns_server", dns_server_.ToString()); |
| 85 dict->SetString("hostname", hostname); | 37 dict->SetString("hostname", qname_); |
| 86 dict->SetInteger("query_type", key_.second); | 38 dict->SetInteger("query_type", qtype_); |
| 87 if (source_.is_valid()) | 39 if (source_.is_valid()) |
| 88 dict->Set("source_dependency", source_.ToValue()); | 40 dict->Set("source_dependency", source_.ToValue()); |
| 89 return dict; | 41 return dict; |
| 90 } | 42 } |
| 91 | 43 |
| 92 private: | 44 private: |
| 93 const IPEndPoint dns_server_; | 45 IPEndPoint dns_server_; |
| 94 const DnsTransaction::Key key_; | 46 std::string qname_; |
| 47 uint16 qtype_; |
| 95 const NetLog::Source source_; | 48 const NetLog::Source source_; |
| 96 }; | 49 }; |
| 97 | 50 |
| 98 class DnsTransactionFinishParameters : public NetLog::EventParameters { | 51 class DnsTransactionFinishParameters : public NetLog::EventParameters { |
| 99 public: | 52 public: |
| 100 DnsTransactionFinishParameters(int net_error, | 53 // TODO(szym): add rcode ? |
| 101 const IPAddressList& ip_address_list) | 54 DnsTransactionFinishParameters(int net_error, int answer_count) |
| 102 : net_error_(net_error), ip_address_list_(ip_address_list) {} | 55 : net_error_(net_error), answer_count_(answer_count) {} |
| 103 | 56 |
| 104 virtual Value* ToValue() const { | 57 virtual Value* ToValue() const { |
| 105 ListValue* list = new ListValue(); | |
| 106 for (IPAddressList::const_iterator it = ip_address_list_.begin(); | |
| 107 it != ip_address_list_.end(); ++it) | |
| 108 list->Append(Value::CreateStringValue(IPAddressToString(*it))); | |
| 109 | |
| 110 DictionaryValue* dict = new DictionaryValue(); | 58 DictionaryValue* dict = new DictionaryValue(); |
| 111 if (net_error_) | 59 if (net_error_) |
| 112 dict->SetInteger("net_error", net_error_); | 60 dict->SetInteger("net_error", net_error_); |
| 113 dict->Set("address_list", list); | 61 dict->SetInteger("answer_count", answer_count_); |
| 114 return dict; | 62 return dict; |
| 115 } | 63 } |
| 116 | 64 |
| 117 private: | 65 private: |
| 118 const int net_error_; | 66 const int net_error_; |
| 119 const IPAddressList ip_address_list_; | 67 const int answer_count_; |
| 120 }; | 68 }; |
| 121 | 69 |
| 122 class DnsTransactionRetryParameters : public NetLog::EventParameters { | 70 class DnsTransactionRetryParameters : public NetLog::EventParameters { |
| 123 public: | 71 public: |
| 124 DnsTransactionRetryParameters(int attempt_number, | 72 DnsTransactionRetryParameters(int attempt_number, |
| 125 const NetLog::Source& source) | 73 const NetLog::Source& source) |
| 126 : attempt_number_(attempt_number), source_(source) {} | 74 : attempt_number_(attempt_number), source_(source) {} |
| 127 | 75 |
| 128 virtual Value* ToValue() const { | 76 virtual Value* ToValue() const { |
| 129 DictionaryValue* dict = new DictionaryValue(); | 77 DictionaryValue* dict = new DictionaryValue(); |
| 130 dict->SetInteger("attempt_number", attempt_number_); | 78 dict->SetInteger("attempt_number", attempt_number_); |
| 131 dict->Set("source_dependency", source_.ToValue()); | 79 dict->Set("source_dependency", source_.ToValue()); |
| 132 return dict; | 80 return dict; |
| 133 } | 81 } |
| 134 | 82 |
| 135 private: | 83 private: |
| 136 const int attempt_number_; | 84 const int attempt_number_; |
| 137 const NetLog::Source source_; | 85 const NetLog::Source source_; |
| 138 }; | 86 }; |
| 139 | 87 |
| 140 } // namespace | 88 } // namespace |
| 141 | 89 |
| 142 DnsTransaction::DnsTransaction(const IPEndPoint& dns_server, | 90 |
| 143 const std::string& dns_name, | 91 DnsTransaction::DnsTransaction(DnsSession* session, |
| 144 uint16 query_type, | 92 const base::StringPiece& qname, |
| 145 const RandIntCallback& rand_int, | 93 uint16 qtype, |
| 146 ClientSocketFactory* socket_factory, | 94 const ResultCallback& callback, |
| 147 const BoundNetLog& source_net_log, | 95 const BoundNetLog& source_net_log) |
| 148 NetLog* net_log) | 96 : session_(session), |
| 149 : dns_server_(dns_server), | 97 dns_server_(session->NextServer()), |
| 150 key_(dns_name, query_type), | 98 query_(new DnsQuery(session->NextId(), qname, qtype)), |
| 151 delegate_(NULL), | 99 callback_(callback), |
| 152 query_(new DnsQuery(dns_name, query_type, rand_int)), | |
| 153 attempts_(0), | 100 attempts_(0), |
| 154 next_state_(STATE_NONE), | 101 next_state_(STATE_NONE), |
| 155 socket_factory_(socket_factory ? socket_factory : | |
| 156 ClientSocketFactory::GetDefaultFactory()), | |
| 157 ALLOW_THIS_IN_INITIALIZER_LIST( | 102 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 158 io_callback_(this, &DnsTransaction::OnIOComplete)), | 103 io_callback_(this, &DnsTransaction::OnIOComplete)), |
| 159 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_DNS_TRANSACTION)) { | 104 net_log_(BoundNetLog::Make(session->net_log(), |
| 160 DCHECK(!rand_int.is_null()); | 105 NetLog::SOURCE_DNS_TRANSACTION)) { |
| 161 for (size_t i = 0; i < arraysize(kTimeoutsMs); ++i) | |
| 162 timeouts_ms_.push_back(base::TimeDelta::FromMilliseconds(kTimeoutsMs[i])); | |
| 163 net_log_.BeginEvent( | 106 net_log_.BeginEvent( |
| 164 NetLog::TYPE_DNS_TRANSACTION, | 107 NetLog::TYPE_DNS_TRANSACTION, |
| 165 make_scoped_refptr( | 108 make_scoped_refptr( |
| 166 new DnsTransactionStartParameters(dns_server_, key_, | 109 new DnsTransactionStartParameters(dns_server_, |
| 110 qname, |
| 111 qtype, |
| 167 source_net_log.source()))); | 112 source_net_log.source()))); |
| 168 } | 113 } |
| 169 | 114 |
| 170 DnsTransaction::~DnsTransaction() { | 115 DnsTransaction::~DnsTransaction() {} |
| 171 SetDelegate(NULL); | |
| 172 } | |
| 173 | |
| 174 void DnsTransaction::SetDelegate(Delegate* delegate) { | |
| 175 if (delegate == delegate_) | |
| 176 return; | |
| 177 if (delegate_) | |
| 178 delegate_->Detach(this); | |
| 179 delegate_ = delegate; | |
| 180 if (delegate_) | |
| 181 delegate_->Attach(this); | |
| 182 } | |
| 183 | 116 |
| 184 int DnsTransaction::Start() { | 117 int DnsTransaction::Start() { |
| 185 DCHECK_EQ(STATE_NONE, next_state_); | 118 DCHECK_EQ(STATE_NONE, next_state_); |
| 186 next_state_ = STATE_CONNECT; | 119 next_state_ = STATE_CONNECT; |
| 187 return DoLoop(OK); | 120 return DoLoop(OK); |
| 188 } | 121 } |
| 189 | 122 |
| 190 int DnsTransaction::DoLoop(int result) { | 123 int DnsTransaction::DoLoop(int result) { |
| 191 DCHECK_NE(STATE_NONE, next_state_); | 124 DCHECK_NE(STATE_NONE, next_state_); |
| 192 int rv = result; | 125 int rv = result; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 216 NOTREACHED(); | 149 NOTREACHED(); |
| 217 break; | 150 break; |
| 218 } | 151 } |
| 219 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 152 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 220 | 153 |
| 221 return rv; | 154 return rv; |
| 222 } | 155 } |
| 223 | 156 |
| 224 void DnsTransaction::DoCallback(int result) { | 157 void DnsTransaction::DoCallback(int result) { |
| 225 DCHECK_NE(result, ERR_IO_PENDING); | 158 DCHECK_NE(result, ERR_IO_PENDING); |
| 159 int answer_count = (result == OK) ? response()->answer_count() : 0; |
| 226 net_log_.EndEvent( | 160 net_log_.EndEvent( |
| 227 NetLog::TYPE_DNS_TRANSACTION, | 161 NetLog::TYPE_DNS_TRANSACTION, |
| 228 make_scoped_refptr( | 162 make_scoped_refptr( |
| 229 new DnsTransactionFinishParameters(result, ip_addresses_))); | 163 new DnsTransactionFinishParameters(result, answer_count))); |
| 230 if (delegate_) | 164 callback_.Run(this, result); |
| 231 delegate_->OnTransactionComplete(result, this, ip_addresses_); | |
| 232 } | 165 } |
| 233 | 166 |
| 234 void DnsTransaction::OnIOComplete(int result) { | 167 void DnsTransaction::OnIOComplete(int result) { |
| 235 int rv = DoLoop(result); | 168 int rv = DoLoop(result); |
| 236 if (rv != ERR_IO_PENDING) | 169 if (rv != ERR_IO_PENDING) |
| 237 DoCallback(rv); | 170 DoCallback(rv); |
| 238 } | 171 } |
| 239 | 172 |
| 240 int DnsTransaction::DoConnect() { | 173 int DnsTransaction::DoConnect() { |
| 241 next_state_ = STATE_CONNECT_COMPLETE; | 174 next_state_ = STATE_CONNECT_COMPLETE; |
| 242 | 175 |
| 243 DCHECK_LT(attempts_, timeouts_ms_.size()); | 176 StartTimer(session_->NextTimeout(attempts_)); |
| 244 StartTimer(timeouts_ms_[attempts_]); | 177 ++attempts_; |
| 245 attempts_++; | |
| 246 | 178 |
| 247 // TODO(agayev): keep all sockets around in case the server responds | 179 // TODO(szym): keep all sockets around in case the server responds |
| 248 // after its timeout; state machine will need to change to handle that. | 180 // after its timeout; state machine will need to change to handle that. |
| 249 socket_.reset(socket_factory_->CreateDatagramClientSocket( | 181 // The current plan is to move socket management out to DnsSession. |
| 182 // Hence also move retransmissions to DnsClient::Request. |
| 183 socket_.reset(session_->socket_factory()->CreateDatagramClientSocket( |
| 250 DatagramSocket::RANDOM_BIND, | 184 DatagramSocket::RANDOM_BIND, |
| 251 base::Bind(&base::RandInt), | 185 base::Bind(&base::RandInt), |
| 252 net_log_.net_log(), | 186 net_log_.net_log(), |
| 253 net_log_.source())); | 187 net_log_.source())); |
| 254 | 188 |
| 255 net_log_.AddEvent( | 189 net_log_.AddEvent( |
| 256 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED, | 190 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED, |
| 257 make_scoped_refptr( | 191 make_scoped_refptr( |
| 258 new DnsTransactionRetryParameters(attempts_, | 192 new DnsTransactionRetryParameters(attempts_, |
| 259 socket_->NetLog().source()))); | 193 socket_->NetLog().source()))); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 274 query_->io_buffer()->size(), | 208 query_->io_buffer()->size(), |
| 275 &io_callback_); | 209 &io_callback_); |
| 276 } | 210 } |
| 277 | 211 |
| 278 int DnsTransaction::DoSendQueryComplete(int rv) { | 212 int DnsTransaction::DoSendQueryComplete(int rv) { |
| 279 if (rv < 0) | 213 if (rv < 0) |
| 280 return rv; | 214 return rv; |
| 281 | 215 |
| 282 // Writing to UDP should not result in a partial datagram. | 216 // Writing to UDP should not result in a partial datagram. |
| 283 if (rv != query_->io_buffer()->size()) | 217 if (rv != query_->io_buffer()->size()) |
| 284 return ERR_NAME_NOT_RESOLVED; | 218 return ERR_MSG_TOO_BIG; |
| 285 | 219 |
| 286 next_state_ = STATE_READ_RESPONSE; | 220 next_state_ = STATE_READ_RESPONSE; |
| 287 return OK; | 221 return OK; |
| 288 } | 222 } |
| 289 | 223 |
| 290 int DnsTransaction::DoReadResponse() { | 224 int DnsTransaction::DoReadResponse() { |
| 291 next_state_ = STATE_READ_RESPONSE_COMPLETE; | 225 next_state_ = STATE_READ_RESPONSE_COMPLETE; |
| 292 response_.reset(new DnsResponse(query_.get())); | 226 response_.reset(new DnsResponse()); |
| 293 return socket_->Read(response_->io_buffer(), | 227 return socket_->Read(response_->io_buffer(), |
| 294 response_->io_buffer()->size(), | 228 response_->io_buffer()->size(), |
| 295 &io_callback_); | 229 &io_callback_); |
| 296 } | 230 } |
| 297 | 231 |
| 298 int DnsTransaction::DoReadResponseComplete(int rv) { | 232 int DnsTransaction::DoReadResponseComplete(int rv) { |
| 299 DCHECK_NE(ERR_IO_PENDING, rv); | 233 DCHECK_NE(ERR_IO_PENDING, rv); |
| 300 RevokeTimer(); | 234 RevokeTimer(); |
| 301 if (rv < 0) | 235 if (rv < 0) |
| 302 return rv; | 236 return rv; |
| 303 | 237 |
| 304 DCHECK(rv); | 238 DCHECK(rv); |
| 305 // TODO(agayev): when supporting EDNS0 we may need to do multiple reads | 239 if (!response_->InitParse(rv, *query_)) |
| 306 // to read the whole response. | 240 return ERR_DNS_MALFORMED_RESPONSE; |
| 307 return response_->Parse(rv, &ip_addresses_); | 241 // TODO(szym): define this flag value in dns_protocol |
| 242 if (response_->flags1() & 2) |
| 243 return ERR_DNS_SERVER_REQUIRES_TCP; |
| 244 // TODO(szym): move this handling out of DnsTransaction? |
| 245 if (response_->rcode() != dns_protocol::kRcodeNOERROR && |
| 246 response_->rcode() != dns_protocol::kRcodeNXDOMAIN) { |
| 247 return ERR_DNS_SERVER_FAILED; |
| 248 } |
| 249 // TODO(szym): add ERR_DNS_RR_NOT_FOUND? |
| 250 if (response_->answer_count() == 0) |
| 251 return ERR_NAME_NOT_RESOLVED; |
| 252 |
| 253 return OK; |
| 308 } | 254 } |
| 309 | 255 |
| 310 void DnsTransaction::StartTimer(base::TimeDelta delay) { | 256 void DnsTransaction::StartTimer(base::TimeDelta delay) { |
| 311 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout); | 257 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout); |
| 312 } | 258 } |
| 313 | 259 |
| 314 void DnsTransaction::RevokeTimer() { | 260 void DnsTransaction::RevokeTimer() { |
| 315 timer_.Stop(); | 261 timer_.Stop(); |
| 316 } | 262 } |
| 317 | 263 |
| 318 void DnsTransaction::OnTimeout() { | 264 void DnsTransaction::OnTimeout() { |
| 319 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || | 265 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || |
| 320 next_state_ == STATE_READ_RESPONSE_COMPLETE); | 266 next_state_ == STATE_READ_RESPONSE_COMPLETE); |
| 321 if (attempts_ == timeouts_ms_.size()) { | 267 if (attempts_ == session_->config().attempts) { |
| 322 DoCallback(ERR_DNS_TIMED_OUT); | 268 DoCallback(ERR_DNS_TIMED_OUT); |
| 323 return; | 269 return; |
| 324 } | 270 } |
| 325 next_state_ = STATE_CONNECT; | 271 next_state_ = STATE_CONNECT; |
| 326 query_.reset(query_->CloneWithNewId()); | 272 query_.reset(query_->CloneWithNewId(session_->NextId())); |
| 327 int rv = DoLoop(OK); | 273 int rv = DoLoop(OK); |
| 328 if (rv != ERR_IO_PENDING) | 274 if (rv != ERR_IO_PENDING) |
| 329 DoCallback(rv); | 275 DoCallback(rv); |
| 330 } | 276 } |
| 331 | 277 |
| 332 void DnsTransaction::set_timeouts_ms( | |
| 333 const std::vector<base::TimeDelta>& timeouts_ms) { | |
| 334 DCHECK_EQ(0u, attempts_); | |
| 335 timeouts_ms_ = timeouts_ms; | |
| 336 } | |
| 337 | |
| 338 } // namespace net | 278 } // namespace net |
| OLD | NEW |