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

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

Issue 11573012: patch from issue 10878090 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 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
« no previous file with comments | « net/dns/dns_socket_pool.cc ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 13 matching lines...) Expand all
24 #include "net/base/completion_callback.h" 24 #include "net/base/completion_callback.h"
25 #include "net/base/dns_util.h" 25 #include "net/base/dns_util.h"
26 #include "net/base/io_buffer.h" 26 #include "net/base/io_buffer.h"
27 #include "net/base/ip_endpoint.h" 27 #include "net/base/ip_endpoint.h"
28 #include "net/base/net_errors.h" 28 #include "net/base/net_errors.h"
29 #include "net/base/net_log.h" 29 #include "net/base/net_log.h"
30 #include "net/dns/dns_protocol.h" 30 #include "net/dns/dns_protocol.h"
31 #include "net/dns/dns_query.h" 31 #include "net/dns/dns_query.h"
32 #include "net/dns/dns_response.h" 32 #include "net/dns/dns_response.h"
33 #include "net/dns/dns_session.h" 33 #include "net/dns/dns_session.h"
34 #include "net/socket/client_socket_factory.h"
35 #include "net/udp/datagram_client_socket.h" 34 #include "net/udp/datagram_client_socket.h"
36 35
37 namespace net { 36 namespace net {
38 37
39 namespace { 38 namespace {
40 39
41 // Provide a common macro to simplify code and readability. We must use a 40 // Provide a common macro to simplify code and readability. We must use a
42 // macro as the underlying HISTOGRAM macro creates static variables. 41 // macro as the underlying HISTOGRAM macro creates static variables.
43 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
44 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) 43 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
(...skipping 20 matching lines...) Expand all
65 return dict; 64 return dict;
66 }; 65 };
67 66
68 // ---------------------------------------------------------------------------- 67 // ----------------------------------------------------------------------------
69 68
70 // A single asynchronous DNS exchange over UDP, which consists of sending out a 69 // A single asynchronous DNS exchange over UDP, which consists of sending out a
71 // DNS query, waiting for a response, and returning the response that it 70 // DNS query, waiting for a response, and returning the response that it
72 // matches. Logging is done in the socket and in the outer DnsTransaction. 71 // matches. Logging is done in the socket and in the outer DnsTransaction.
73 class DnsUDPAttempt { 72 class DnsUDPAttempt {
74 public: 73 public:
75 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, 74 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease,
76 const IPEndPoint& server,
77 scoped_ptr<DnsQuery> query, 75 scoped_ptr<DnsQuery> query,
78 const CompletionCallback& callback) 76 const CompletionCallback& callback)
79 : next_state_(STATE_NONE), 77 : next_state_(STATE_NONE),
80 received_malformed_response_(false), 78 received_malformed_response_(false),
81 socket_(socket.Pass()), 79 socket_lease_(socket_lease.Pass()),
82 server_(server),
83 query_(query.Pass()), 80 query_(query.Pass()),
84 callback_(callback) { 81 callback_(callback) {
85 } 82 }
86 83
87 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 84 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
88 // and calls |callback| upon completion. 85 // and calls |callback| upon completion.
89 int Start() { 86 int Start() {
90 DCHECK_EQ(STATE_NONE, next_state_); 87 DCHECK_EQ(STATE_NONE, next_state_);
91 int rv = socket_->Connect(server_);
92 DCHECK_NE(ERR_IO_PENDING, rv);
93 if (rv < 0)
94 return rv;
95 start_time_ = base::TimeTicks::Now(); 88 start_time_ = base::TimeTicks::Now();
96 next_state_ = STATE_SEND_QUERY; 89 next_state_ = STATE_SEND_QUERY;
97 return DoLoop(OK); 90 return DoLoop(OK);
98 } 91 }
99 92
100 const DnsQuery* query() const { 93 const DnsQuery* query() const {
101 return query_.get(); 94 return query_.get();
102 } 95 }
103 96
104 const DatagramClientSocket* socket() const { 97 const BoundNetLog& socket_net_log() const {
105 return socket_.get(); 98 return socket_lease_->socket()->NetLog();
106 } 99 }
107 100
108 // Returns the response or NULL if has not received a matching response from 101 // Returns the response or NULL if has not received a matching response from
109 // the server. 102 // the server.
110 const DnsResponse* response() const { 103 const DnsResponse* response() const {
111 const DnsResponse* resp = response_.get(); 104 const DnsResponse* resp = response_.get();
112 return (resp != NULL && resp->IsValid()) ? resp : NULL; 105 return (resp != NULL && resp->IsValid()) ? resp : NULL;
113 } 106 }
114 107
115 // Returns a Value representing the received response, along with a reference 108 // Returns a Value representing the received response, along with a reference
116 // to the NetLog source source of the UDP socket used. The request must have 109 // to the NetLog source source of the UDP socket used. The request must have
117 // completed before this is called. 110 // completed before this is called.
118 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { 111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
119 DCHECK(response_->IsValid()); 112 DCHECK(response_->IsValid());
120 113
121 DictionaryValue* dict = new DictionaryValue(); 114 DictionaryValue* dict = new DictionaryValue();
122 dict->SetInteger("rcode", response_->rcode()); 115 dict->SetInteger("rcode", response_->rcode());
123 dict->SetInteger("answer_count", response_->answer_count()); 116 dict->SetInteger("answer_count", response_->answer_count());
124 socket_->NetLog().source().AddToEventParameters(dict); 117 socket_net_log().source().AddToEventParameters(dict);
125 return dict; 118 return dict;
126 } 119 }
127 120
128 private: 121 private:
129 enum State { 122 enum State {
130 STATE_SEND_QUERY, 123 STATE_SEND_QUERY,
131 STATE_SEND_QUERY_COMPLETE, 124 STATE_SEND_QUERY_COMPLETE,
132 STATE_READ_RESPONSE, 125 STATE_READ_RESPONSE,
133 STATE_READ_RESPONSE_COMPLETE, 126 STATE_READ_RESPONSE_COMPLETE,
134 STATE_NONE, 127 STATE_NONE,
135 }; 128 };
136 129
130 DatagramClientSocket* socket() {
131 return socket_lease_->socket();
132 }
133
137 int DoLoop(int result) { 134 int DoLoop(int result) {
138 CHECK_NE(STATE_NONE, next_state_); 135 CHECK_NE(STATE_NONE, next_state_);
139 int rv = result; 136 int rv = result;
140 do { 137 do {
141 State state = next_state_; 138 State state = next_state_;
142 next_state_ = STATE_NONE; 139 next_state_ = STATE_NONE;
143 switch (state) { 140 switch (state) {
144 case STATE_SEND_QUERY: 141 case STATE_SEND_QUERY:
145 rv = DoSendQuery(); 142 rv = DoSendQuery();
146 break; 143 break;
(...skipping 20 matching lines...) Expand all
167 base::TimeTicks::Now() - start_time_); 164 base::TimeTicks::Now() - start_time_);
168 } else if (rv != ERR_IO_PENDING) { 165 } else if (rv != ERR_IO_PENDING) {
169 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail", 166 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
170 base::TimeTicks::Now() - start_time_); 167 base::TimeTicks::Now() - start_time_);
171 } 168 }
172 return rv; 169 return rv;
173 } 170 }
174 171
175 int DoSendQuery() { 172 int DoSendQuery() {
176 next_state_ = STATE_SEND_QUERY_COMPLETE; 173 next_state_ = STATE_SEND_QUERY_COMPLETE;
177 return socket_->Write(query_->io_buffer(), 174 return socket()->Write(query_->io_buffer(),
178 query_->io_buffer()->size(), 175 query_->io_buffer()->size(),
179 base::Bind(&DnsUDPAttempt::OnIOComplete, 176 base::Bind(&DnsUDPAttempt::OnIOComplete,
180 base::Unretained(this))); 177 base::Unretained(this)));
181 } 178 }
182 179
183 int DoSendQueryComplete(int rv) { 180 int DoSendQueryComplete(int rv) {
184 DCHECK_NE(ERR_IO_PENDING, rv); 181 DCHECK_NE(ERR_IO_PENDING, rv);
185 if (rv < 0) 182 if (rv < 0)
186 return rv; 183 return rv;
187 184
188 // Writing to UDP should not result in a partial datagram. 185 // Writing to UDP should not result in a partial datagram.
189 if (rv != query_->io_buffer()->size()) 186 if (rv != query_->io_buffer()->size())
190 return ERR_MSG_TOO_BIG; 187 return ERR_MSG_TOO_BIG;
191 188
192 next_state_ = STATE_READ_RESPONSE; 189 next_state_ = STATE_READ_RESPONSE;
193 return OK; 190 return OK;
194 } 191 }
195 192
196 int DoReadResponse() { 193 int DoReadResponse() {
197 next_state_ = STATE_READ_RESPONSE_COMPLETE; 194 next_state_ = STATE_READ_RESPONSE_COMPLETE;
198 response_.reset(new DnsResponse()); 195 response_.reset(new DnsResponse());
199 return socket_->Read(response_->io_buffer(), 196 return socket()->Read(response_->io_buffer(),
200 response_->io_buffer()->size(), 197 response_->io_buffer()->size(),
201 base::Bind(&DnsUDPAttempt::OnIOComplete, 198 base::Bind(&DnsUDPAttempt::OnIOComplete,
202 base::Unretained(this))); 199 base::Unretained(this)));
203 } 200 }
204 201
205 int DoReadResponseComplete(int rv) { 202 int DoReadResponseComplete(int rv) {
206 DCHECK_NE(ERR_IO_PENDING, rv); 203 DCHECK_NE(ERR_IO_PENDING, rv);
207 if (rv < 0) 204 if (rv < 0)
208 return rv; 205 return rv;
209 206
210 DCHECK(rv); 207 DCHECK(rv);
211 if (!response_->InitParse(rv, *query_)) { 208 if (!response_->InitParse(rv, *query_)) {
212 // Other implementations simply ignore mismatched responses. Since each 209 // Other implementations simply ignore mismatched responses. Since each
(...skipping 20 matching lines...) Expand all
233 void OnIOComplete(int rv) { 230 void OnIOComplete(int rv) {
234 rv = DoLoop(rv); 231 rv = DoLoop(rv);
235 if (rv != ERR_IO_PENDING) 232 if (rv != ERR_IO_PENDING)
236 callback_.Run(rv); 233 callback_.Run(rv);
237 } 234 }
238 235
239 State next_state_; 236 State next_state_;
240 bool received_malformed_response_; 237 bool received_malformed_response_;
241 base::TimeTicks start_time_; 238 base::TimeTicks start_time_;
242 239
243 scoped_ptr<DatagramClientSocket> socket_; 240 scoped_ptr<DnsSession::SocketLease> socket_lease_;
244 IPEndPoint server_;
245 scoped_ptr<DnsQuery> query_; 241 scoped_ptr<DnsQuery> query_;
246 242
247 scoped_ptr<DnsResponse> response_; 243 scoped_ptr<DnsResponse> response_;
248 244
249 CompletionCallback callback_; 245 CompletionCallback callback_;
250 246
251 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 247 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
252 }; 248 };
253 249
254 // ---------------------------------------------------------------------------- 250 // ----------------------------------------------------------------------------
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 390
395 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 391 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
396 callback.Run(this, result.rv, response); 392 callback.Run(this, result.rv, response);
397 } 393 }
398 394
399 // Makes another attempt at the current name, |qnames_.front()|, using the 395 // Makes another attempt at the current name, |qnames_.front()|, using the
400 // next nameserver. 396 // next nameserver.
401 AttemptResult MakeAttempt() { 397 AttemptResult MakeAttempt() {
402 unsigned attempt_number = attempts_.size(); 398 unsigned attempt_number = attempts_.size();
403 399
404 #if defined(OS_WIN)
405 // Avoid the Windows firewall warning about explicit UDP binding.
406 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413
407 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND;
408 #else
409 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND;
410 #endif
411
412 scoped_ptr<DatagramClientSocket> socket(
413 session_->socket_factory()->CreateDatagramClientSocket(
414 bind_type,
415 base::Bind(&base::RandInt),
416 net_log_.net_log(),
417 net_log_.source()));
418
419 uint16 id = session_->NextQueryId(); 400 uint16 id = session_->NextQueryId();
420 scoped_ptr<DnsQuery> query; 401 scoped_ptr<DnsQuery> query;
421 if (attempts_.empty()) { 402 if (attempts_.empty()) {
422 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 403 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
423 } else { 404 } else {
424 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 405 query.reset(attempts_[0]->query()->CloneWithNewId(id));
425 } 406 }
426 407
427 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
428 socket->NetLog().source().ToEventParametersCallback());
429
430 const DnsConfig& config = session_->config(); 408 const DnsConfig& config = session_->config();
431 409
432 unsigned server_index = first_server_index_ + 410 unsigned server_index = first_server_index_ +
433 (attempt_number % config.nameservers.size()); 411 (attempt_number % config.nameservers.size());
434 412
413 scoped_ptr<DnsSession::SocketLease> lease =
414 session_->AllocateSocket(server_index, net_log_.source());
415
416 bool got_socket = !!lease.get();
417
435 DnsUDPAttempt* attempt = new DnsUDPAttempt( 418 DnsUDPAttempt* attempt = new DnsUDPAttempt(
436 socket.Pass(), 419 lease.Pass(),
437 config.nameservers[server_index],
438 query.Pass(), 420 query.Pass(),
439 base::Bind(&DnsTransactionImpl::OnAttemptComplete, 421 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
440 base::Unretained(this), 422 base::Unretained(this),
441 attempt_number)); 423 attempt_number));
442 424
443 attempts_.push_back(attempt); 425 attempts_.push_back(attempt);
444 426
427 if (!got_socket)
428 return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
429
430 net_log_.AddEvent(
431 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
432 attempt->socket_net_log().source().ToEventParametersCallback());
433
445 int rv = attempt->Start(); 434 int rv = attempt->Start();
446 if (rv == ERR_IO_PENDING) { 435 if (rv == ERR_IO_PENDING) {
447 timer_.Stop(); 436 timer_.Stop();
448 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 437 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
449 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 438 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
450 } 439 }
451 return AttemptResult(rv, attempt); 440 return AttemptResult(rv, attempt);
452 } 441 }
453 442
454 // Begins query for the current name. Makes the first attempt. 443 // Begins query for the current name. Makes the first attempt.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 net_log_.EndEventWithNetErrorCode( 493 net_log_.EndEventWithNetErrorCode(
505 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 494 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
506 // Try next suffix. 495 // Try next suffix.
507 qnames_.pop_front(); 496 qnames_.pop_front();
508 if (qnames_.empty()) { 497 if (qnames_.empty()) {
509 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 498 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
510 } else { 499 } else {
511 result = StartQuery(); 500 result = StartQuery();
512 } 501 }
513 break; 502 break;
503 case ERR_CONNECTION_REFUSED:
514 case ERR_DNS_TIMED_OUT: 504 case ERR_DNS_TIMED_OUT:
515 if (MoreAttemptsAllowed()) { 505 if (MoreAttemptsAllowed()) {
516 result = MakeAttempt(); 506 result = MakeAttempt();
517 } else { 507 } else {
518 return result; 508 return result;
519 } 509 }
520 break; 510 break;
521 default: 511 default:
522 // Server failure. 512 // Server failure.
523 DCHECK(result.attempt); 513 DCHECK(result.attempt);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 } // namespace 589 } // namespace
600 590
601 // static 591 // static
602 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
603 DnsSession* session) { 593 DnsSession* session) {
604 return scoped_ptr<DnsTransactionFactory>( 594 return scoped_ptr<DnsTransactionFactory>(
605 new DnsTransactionFactoryImpl(session)); 595 new DnsTransactionFactoryImpl(session));
606 } 596 }
607 597
608 } // namespace net 598 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_socket_pool.cc ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698