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

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

Issue 10878090: Keep pool of pre-connected DNS sockets (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 2 months 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) 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
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/memory/ref_counted.h" 12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h" 14 #include "base/memory/scoped_vector.h"
15 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop.h" 16 #include "base/message_loop.h"
17 #include "base/rand_util.h"
18 #include "base/stl_util.h" 17 #include "base/stl_util.h"
19 #include "base/string_piece.h" 18 #include "base/string_piece.h"
20 #include "base/threading/non_thread_safe.h" 19 #include "base/threading/non_thread_safe.h"
21 #include "base/timer.h" 20 #include "base/timer.h"
22 #include "base/values.h" 21 #include "base/values.h"
23 #include "net/base/completion_callback.h" 22 #include "net/base/completion_callback.h"
24 #include "net/base/dns_util.h" 23 #include "net/base/dns_util.h"
25 #include "net/base/io_buffer.h" 24 #include "net/base/io_buffer.h"
26 #include "net/base/ip_endpoint.h" 25 #include "net/base/ip_endpoint.h"
27 #include "net/base/net_errors.h" 26 #include "net/base/net_errors.h"
28 #include "net/base/net_log.h" 27 #include "net/base/net_log.h"
29 #include "net/dns/dns_protocol.h" 28 #include "net/dns/dns_protocol.h"
30 #include "net/dns/dns_query.h" 29 #include "net/dns/dns_query.h"
31 #include "net/dns/dns_response.h" 30 #include "net/dns/dns_response.h"
32 #include "net/dns/dns_session.h" 31 #include "net/dns/dns_session.h"
33 #include "net/socket/client_socket_factory.h"
34 #include "net/udp/datagram_client_socket.h" 32 #include "net/udp/datagram_client_socket.h"
35 33
36 namespace net { 34 namespace net {
37 35
38 namespace { 36 namespace {
39 37
40 // Count labels in the fully-qualified name in DNS format. 38 // Count labels in the fully-qualified name in DNS format.
41 int CountLabels(const std::string& name) { 39 int CountLabels(const std::string& name) {
42 size_t count = 0; 40 size_t count = 0;
43 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1) 41 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
(...skipping 15 matching lines...) Expand all
59 return dict; 57 return dict;
60 }; 58 };
61 59
62 // ---------------------------------------------------------------------------- 60 // ----------------------------------------------------------------------------
63 61
64 // A single asynchronous DNS exchange over UDP, which consists of sending out a 62 // A single asynchronous DNS exchange over UDP, which consists of sending out a
65 // DNS query, waiting for a response, and returning the response that it 63 // DNS query, waiting for a response, and returning the response that it
66 // matches. Logging is done in the socket and in the outer DnsTransaction. 64 // matches. Logging is done in the socket and in the outer DnsTransaction.
67 class DnsUDPAttempt { 65 class DnsUDPAttempt {
68 public: 66 public:
69 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket, 67 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease,
70 const IPEndPoint& server,
71 scoped_ptr<DnsQuery> query, 68 scoped_ptr<DnsQuery> query,
72 const CompletionCallback& callback) 69 const CompletionCallback& callback)
73 : next_state_(STATE_NONE), 70 : next_state_(STATE_NONE),
74 received_malformed_response_(false), 71 received_malformed_response_(false),
75 socket_(socket.Pass()), 72 socket_lease_(socket_lease.Pass()),
76 server_(server),
77 query_(query.Pass()), 73 query_(query.Pass()),
78 callback_(callback) { 74 callback_(callback) {
79 } 75 }
80 76
81 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
82 // and calls |callback| upon completion. 78 // and calls |callback| upon completion.
83 int Start() { 79 int Start() {
84 DCHECK_EQ(STATE_NONE, next_state_); 80 DCHECK_EQ(STATE_NONE, next_state_);
85 int rv = socket_->Connect(server_);
86 DCHECK_NE(ERR_IO_PENDING, rv);
87 if (rv < 0)
88 return rv;
89 next_state_ = STATE_SEND_QUERY; 81 next_state_ = STATE_SEND_QUERY;
90 return DoLoop(OK); 82 return DoLoop(OK);
91 } 83 }
92 84
93 const DnsQuery* query() const { 85 const DnsQuery* query() const {
94 return query_.get(); 86 return query_.get();
95 } 87 }
96 88
97 const DatagramClientSocket* socket() const { 89 const BoundNetLog& socket_net_log() const {
98 return socket_.get(); 90 return socket_lease_->socket()->NetLog();
99 } 91 }
100 92
101 // Returns the response or NULL if has not received a matching response from 93 // Returns the response or NULL if has not received a matching response from
102 // the server. 94 // the server.
103 const DnsResponse* response() const { 95 const DnsResponse* response() const {
104 const DnsResponse* resp = response_.get(); 96 const DnsResponse* resp = response_.get();
105 return (resp != NULL && resp->IsValid()) ? resp : NULL; 97 return (resp != NULL && resp->IsValid()) ? resp : NULL;
106 } 98 }
107 99
108 // Returns a Value representing the received response, along with a reference 100 // Returns a Value representing the received response, along with a reference
109 // to the NetLog source source of the UDP socket used. The request must have 101 // to the NetLog source source of the UDP socket used. The request must have
110 // completed before this is called. 102 // completed before this is called.
111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { 103 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
112 DCHECK(response_->IsValid()); 104 DCHECK(response_->IsValid());
113 105
114 DictionaryValue* dict = new DictionaryValue(); 106 DictionaryValue* dict = new DictionaryValue();
115 dict->SetInteger("rcode", response_->rcode()); 107 dict->SetInteger("rcode", response_->rcode());
116 dict->SetInteger("answer_count", response_->answer_count()); 108 dict->SetInteger("answer_count", response_->answer_count());
117 socket_->NetLog().source().AddToEventParameters(dict); 109 socket_net_log().source().AddToEventParameters(dict);
118 return dict; 110 return dict;
119 } 111 }
120 112
121 private: 113 private:
122 enum State { 114 enum State {
123 STATE_SEND_QUERY, 115 STATE_SEND_QUERY,
124 STATE_SEND_QUERY_COMPLETE, 116 STATE_SEND_QUERY_COMPLETE,
125 STATE_READ_RESPONSE, 117 STATE_READ_RESPONSE,
126 STATE_READ_RESPONSE_COMPLETE, 118 STATE_READ_RESPONSE_COMPLETE,
127 STATE_NONE, 119 STATE_NONE,
128 }; 120 };
129 121
122 DatagramClientSocket* socket() {
123 return socket_lease_->socket();
124 }
125
130 int DoLoop(int result) { 126 int DoLoop(int result) {
131 CHECK_NE(STATE_NONE, next_state_); 127 CHECK_NE(STATE_NONE, next_state_);
132 int rv = result; 128 int rv = result;
133 do { 129 do {
134 State state = next_state_; 130 State state = next_state_;
135 next_state_ = STATE_NONE; 131 next_state_ = STATE_NONE;
136 switch (state) { 132 switch (state) {
137 case STATE_SEND_QUERY: 133 case STATE_SEND_QUERY:
138 rv = DoSendQuery(); 134 rv = DoSendQuery();
139 break; 135 break;
(...skipping 13 matching lines...) Expand all
153 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 149 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
154 // If we received a malformed response, and are now waiting for another one, 150 // If we received a malformed response, and are now waiting for another one,
155 // indicate to the transaction that the server might be misbehaving. 151 // indicate to the transaction that the server might be misbehaving.
156 if (rv == ERR_IO_PENDING && received_malformed_response_) 152 if (rv == ERR_IO_PENDING && received_malformed_response_)
157 return ERR_DNS_MALFORMED_RESPONSE; 153 return ERR_DNS_MALFORMED_RESPONSE;
158 return rv; 154 return rv;
159 } 155 }
160 156
161 int DoSendQuery() { 157 int DoSendQuery() {
162 next_state_ = STATE_SEND_QUERY_COMPLETE; 158 next_state_ = STATE_SEND_QUERY_COMPLETE;
163 return socket_->Write(query_->io_buffer(), 159 return socket()->Write(query_->io_buffer(),
164 query_->io_buffer()->size(), 160 query_->io_buffer()->size(),
165 base::Bind(&DnsUDPAttempt::OnIOComplete, 161 base::Bind(&DnsUDPAttempt::OnIOComplete,
166 base::Unretained(this))); 162 base::Unretained(this)));
167 } 163 }
168 164
169 int DoSendQueryComplete(int rv) { 165 int DoSendQueryComplete(int rv) {
170 DCHECK_NE(ERR_IO_PENDING, rv); 166 DCHECK_NE(ERR_IO_PENDING, rv);
171 if (rv < 0) 167 if (rv < 0)
172 return rv; 168 return rv;
173 169
174 // Writing to UDP should not result in a partial datagram. 170 // Writing to UDP should not result in a partial datagram.
175 if (rv != query_->io_buffer()->size()) 171 if (rv != query_->io_buffer()->size())
176 return ERR_MSG_TOO_BIG; 172 return ERR_MSG_TOO_BIG;
177 173
178 next_state_ = STATE_READ_RESPONSE; 174 next_state_ = STATE_READ_RESPONSE;
179 return OK; 175 return OK;
180 } 176 }
181 177
182 int DoReadResponse() { 178 int DoReadResponse() {
183 next_state_ = STATE_READ_RESPONSE_COMPLETE; 179 next_state_ = STATE_READ_RESPONSE_COMPLETE;
184 response_.reset(new DnsResponse()); 180 response_.reset(new DnsResponse());
185 return socket_->Read(response_->io_buffer(), 181 return socket()->Read(response_->io_buffer(),
186 response_->io_buffer()->size(), 182 response_->io_buffer()->size(),
187 base::Bind(&DnsUDPAttempt::OnIOComplete, 183 base::Bind(&DnsUDPAttempt::OnIOComplete,
188 base::Unretained(this))); 184 base::Unretained(this)));
189 } 185 }
190 186
191 int DoReadResponseComplete(int rv) { 187 int DoReadResponseComplete(int rv) {
192 DCHECK_NE(ERR_IO_PENDING, rv); 188 DCHECK_NE(ERR_IO_PENDING, rv);
193 if (rv < 0) 189 if (rv < 0)
194 return rv; 190 return rv;
195 191
196 DCHECK(rv); 192 DCHECK(rv);
197 if (!response_->InitParse(rv, *query_)) { 193 if (!response_->InitParse(rv, *query_)) {
198 // Other implementations simply ignore mismatched responses. Since each 194 // Other implementations simply ignore mismatched responses. Since each
(...skipping 19 matching lines...) Expand all
218 214
219 void OnIOComplete(int rv) { 215 void OnIOComplete(int rv) {
220 rv = DoLoop(rv); 216 rv = DoLoop(rv);
221 if (rv != ERR_IO_PENDING) 217 if (rv != ERR_IO_PENDING)
222 callback_.Run(rv); 218 callback_.Run(rv);
223 } 219 }
224 220
225 State next_state_; 221 State next_state_;
226 bool received_malformed_response_; 222 bool received_malformed_response_;
227 223
228 scoped_ptr<DatagramClientSocket> socket_; 224 scoped_ptr<DnsSession::SocketLease> socket_lease_;
229 IPEndPoint server_;
230 scoped_ptr<DnsQuery> query_; 225 scoped_ptr<DnsQuery> query_;
231 226
232 scoped_ptr<DnsResponse> response_; 227 scoped_ptr<DnsResponse> response_;
233 228
234 CompletionCallback callback_; 229 CompletionCallback callback_;
235 230
236 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 231 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
237 }; 232 };
238 233
239 // ---------------------------------------------------------------------------- 234 // ----------------------------------------------------------------------------
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 374
380 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 375 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
381 callback.Run(this, result.rv, response); 376 callback.Run(this, result.rv, response);
382 } 377 }
383 378
384 // Makes another attempt at the current name, |qnames_.front()|, using the 379 // Makes another attempt at the current name, |qnames_.front()|, using the
385 // next nameserver. 380 // next nameserver.
386 AttemptResult MakeAttempt() { 381 AttemptResult MakeAttempt() {
387 unsigned attempt_number = attempts_.size(); 382 unsigned attempt_number = attempts_.size();
388 383
389 #if defined(OS_WIN)
390 // Avoid the Windows firewall warning about explicit UDP binding.
391 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413
392 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND;
393 #else
394 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND;
395 #endif
396
397 scoped_ptr<DatagramClientSocket> socket(
398 session_->socket_factory()->CreateDatagramClientSocket(
399 bind_type,
400 base::Bind(&base::RandInt),
401 net_log_.net_log(),
402 net_log_.source()));
403
404 uint16 id = session_->NextQueryId(); 384 uint16 id = session_->NextQueryId();
405 scoped_ptr<DnsQuery> query; 385 scoped_ptr<DnsQuery> query;
406 if (attempts_.empty()) { 386 if (attempts_.empty()) {
407 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 387 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
408 } else { 388 } else {
409 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 389 query.reset(attempts_[0]->query()->CloneWithNewId(id));
410 } 390 }
411 391
412 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
413 socket->NetLog().source().ToEventParametersCallback());
414
415 const DnsConfig& config = session_->config(); 392 const DnsConfig& config = session_->config();
416 393
417 unsigned server_index = first_server_index_ + 394 unsigned server_index = first_server_index_ +
418 (attempt_number % config.nameservers.size()); 395 (attempt_number % config.nameservers.size());
419 396
397 scoped_ptr<DnsSession::SocketLease> lease =
398 session_->AllocateSocket(server_index, net_log_.source());
399
400 bool got_socket = !!lease.get();
401
420 DnsUDPAttempt* attempt = new DnsUDPAttempt( 402 DnsUDPAttempt* attempt = new DnsUDPAttempt(
421 socket.Pass(), 403 lease.Pass(),
422 config.nameservers[server_index],
423 query.Pass(), 404 query.Pass(),
424 base::Bind(&DnsTransactionImpl::OnAttemptComplete, 405 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
425 base::Unretained(this), 406 base::Unretained(this),
426 attempt_number)); 407 attempt_number));
427 408
428 attempts_.push_back(attempt); 409 attempts_.push_back(attempt);
429 410
411 if (!got_socket)
412 return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
413
414 net_log_.AddEvent(
415 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
416 attempt->socket_net_log().source().ToEventParametersCallback());
417
430 int rv = attempt->Start(); 418 int rv = attempt->Start();
431 if (rv == ERR_IO_PENDING) { 419 if (rv == ERR_IO_PENDING) {
432 timer_.Stop(); 420 timer_.Stop();
433 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 421 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
434 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 422 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
435 } 423 }
436 return AttemptResult(rv, attempt); 424 return AttemptResult(rv, attempt);
437 } 425 }
438 426
439 // Begins query for the current name. Makes the first attempt. 427 // Begins query for the current name. Makes the first attempt.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 net_log_.EndEventWithNetErrorCode( 477 net_log_.EndEventWithNetErrorCode(
490 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 478 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
491 // Try next suffix. 479 // Try next suffix.
492 qnames_.pop_front(); 480 qnames_.pop_front();
493 if (qnames_.empty()) { 481 if (qnames_.empty()) {
494 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL); 482 return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
495 } else { 483 } else {
496 result = StartQuery(); 484 result = StartQuery();
497 } 485 }
498 break; 486 break;
487 case ERR_CONNECTION_REFUSED:
499 case ERR_DNS_TIMED_OUT: 488 case ERR_DNS_TIMED_OUT:
500 if (MoreAttemptsAllowed()) { 489 if (MoreAttemptsAllowed()) {
501 result = MakeAttempt(); 490 result = MakeAttempt();
502 } else { 491 } else {
503 return result; 492 return result;
504 } 493 }
505 break; 494 break;
506 default: 495 default:
507 // Server failure. 496 // Server failure.
508 DCHECK(result.attempt); 497 DCHECK(result.attempt);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 } // namespace 573 } // namespace
585 574
586 // static 575 // static
587 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 576 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
588 DnsSession* session) { 577 DnsSession* session) {
589 return scoped_ptr<DnsTransactionFactory>( 578 return scoped_ptr<DnsTransactionFactory>(
590 new DnsTransactionFactoryImpl(session)); 579 new DnsTransactionFactoryImpl(session));
591 } 580 }
592 581
593 } // namespace net 582 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698