Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: net/dns/dns_transaction.cc

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

Powered by Google App Engine
This is Rietveld 408576698