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