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