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

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: 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 next_state_ = STATE_CONNECT; 81 next_state_ = STATE_SEND_QUERY;
86 return DoLoop(OK); 82 return DoLoop(OK);
87 } 83 }
88 84
89 const DnsQuery* query() const { 85 const DnsQuery* query() const {
90 return query_.get(); 86 return query_.get();
91 } 87 }
92 88
93 const DatagramClientSocket* socket() const { 89 const BoundNetLog& socket_net_log() const {
94 return socket_.get(); 90 return socket_lease_->socket()->NetLog();
95 } 91 }
96 92
97 // 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
98 // the server. 94 // the server.
99 const DnsResponse* response() const { 95 const DnsResponse* response() const {
100 const DnsResponse* resp = response_.get(); 96 const DnsResponse* resp = response_.get();
101 return (resp != NULL && resp->IsValid()) ? resp : NULL; 97 return (resp != NULL && resp->IsValid()) ? resp : NULL;
102 } 98 }
103 99
104 // Returns a Value representing the received response, along with a reference 100 // Returns a Value representing the received response, along with a reference
105 // 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
106 // completed before this is called. 102 // completed before this is called.
107 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { 103 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
108 DCHECK(response_->IsValid()); 104 DCHECK(response_->IsValid());
109 105
110 DictionaryValue* dict = new DictionaryValue(); 106 DictionaryValue* dict = new DictionaryValue();
111 dict->SetInteger("rcode", response_->rcode()); 107 dict->SetInteger("rcode", response_->rcode());
112 dict->SetInteger("answer_count", response_->answer_count()); 108 dict->SetInteger("answer_count", response_->answer_count());
113 socket_->NetLog().source().AddToEventParameters(dict); 109 socket_net_log().source().AddToEventParameters(dict);
114 return dict; 110 return dict;
115 } 111 }
116 112
117 private: 113 private:
118 enum State { 114 enum State {
119 STATE_CONNECT,
120 STATE_SEND_QUERY, 115 STATE_SEND_QUERY,
121 STATE_SEND_QUERY_COMPLETE, 116 STATE_SEND_QUERY_COMPLETE,
122 STATE_READ_RESPONSE, 117 STATE_READ_RESPONSE,
123 STATE_READ_RESPONSE_COMPLETE, 118 STATE_READ_RESPONSE_COMPLETE,
124 STATE_NONE, 119 STATE_NONE,
125 }; 120 };
126 121
122 DatagramClientSocket* socket() {
123 return socket_lease_->socket();
124 }
125
127 int DoLoop(int result) { 126 int DoLoop(int result) {
128 CHECK_NE(STATE_NONE, next_state_); 127 CHECK_NE(STATE_NONE, next_state_);
129 int rv = result; 128 int rv = result;
130 do { 129 do {
131 State state = next_state_; 130 State state = next_state_;
132 next_state_ = STATE_NONE; 131 next_state_ = STATE_NONE;
133 switch (state) { 132 switch (state) {
134 case STATE_CONNECT:
135 rv = DoConnect();
136 break;
137 case STATE_SEND_QUERY: 133 case STATE_SEND_QUERY:
138 rv = DoSendQuery(); 134 rv = DoSendQuery();
139 break; 135 break;
140 case STATE_SEND_QUERY_COMPLETE: 136 case STATE_SEND_QUERY_COMPLETE:
141 rv = DoSendQueryComplete(rv); 137 rv = DoSendQueryComplete(rv);
142 break; 138 break;
143 case STATE_READ_RESPONSE: 139 case STATE_READ_RESPONSE:
144 rv = DoReadResponse(); 140 rv = DoReadResponse();
145 break; 141 break;
146 case STATE_READ_RESPONSE_COMPLETE: 142 case STATE_READ_RESPONSE_COMPLETE:
147 rv = DoReadResponseComplete(rv); 143 rv = DoReadResponseComplete(rv);
148 break; 144 break;
149 default: 145 default:
150 NOTREACHED(); 146 NOTREACHED();
151 break; 147 break;
152 } 148 }
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 DoConnect() {
162 next_state_ = STATE_SEND_QUERY;
163 return socket_->Connect(server_);
164 }
165
166 int DoSendQuery() { 157 int DoSendQuery() {
167 next_state_ = STATE_SEND_QUERY_COMPLETE; 158 next_state_ = STATE_SEND_QUERY_COMPLETE;
168 return socket_->Write(query_->io_buffer(), 159 return socket()->Write(query_->io_buffer(),
169 query_->io_buffer()->size(), 160 query_->io_buffer()->size(),
170 base::Bind(&DnsUDPAttempt::OnIOComplete, 161 base::Bind(&DnsUDPAttempt::OnIOComplete,
171 base::Unretained(this))); 162 base::Unretained(this)));
172 } 163 }
173 164
174 int DoSendQueryComplete(int rv) { 165 int DoSendQueryComplete(int rv) {
175 DCHECK_NE(ERR_IO_PENDING, rv); 166 DCHECK_NE(ERR_IO_PENDING, rv);
176 if (rv < 0) 167 if (rv < 0)
177 return rv; 168 return rv;
178 169
179 // Writing to UDP should not result in a partial datagram. 170 // Writing to UDP should not result in a partial datagram.
180 if (rv != query_->io_buffer()->size()) 171 if (rv != query_->io_buffer()->size())
181 return ERR_MSG_TOO_BIG; 172 return ERR_MSG_TOO_BIG;
182 173
183 next_state_ = STATE_READ_RESPONSE; 174 next_state_ = STATE_READ_RESPONSE;
184 return OK; 175 return OK;
185 } 176 }
186 177
187 int DoReadResponse() { 178 int DoReadResponse() {
188 next_state_ = STATE_READ_RESPONSE_COMPLETE; 179 next_state_ = STATE_READ_RESPONSE_COMPLETE;
189 response_.reset(new DnsResponse()); 180 response_.reset(new DnsResponse());
190 return socket_->Read(response_->io_buffer(), 181 return socket()->Read(response_->io_buffer(),
191 response_->io_buffer()->size(), 182 response_->io_buffer()->size(),
192 base::Bind(&DnsUDPAttempt::OnIOComplete, 183 base::Bind(&DnsUDPAttempt::OnIOComplete,
193 base::Unretained(this))); 184 base::Unretained(this)));
194 } 185 }
195 186
196 int DoReadResponseComplete(int rv) { 187 int DoReadResponseComplete(int rv) {
197 DCHECK_NE(ERR_IO_PENDING, rv); 188 DCHECK_NE(ERR_IO_PENDING, rv);
198 if (rv < 0) 189 if (rv < 0)
199 return rv; 190 return rv;
200 191
201 DCHECK(rv); 192 DCHECK(rv);
202 if (!response_->InitParse(rv, *query_)) { 193 if (!response_->InitParse(rv, *query_)) {
203 // Other implementations simply ignore mismatched responses. Since each 194 // Other implementations simply ignore mismatched responses. Since each
(...skipping 19 matching lines...) Expand all
223 214
224 void OnIOComplete(int rv) { 215 void OnIOComplete(int rv) {
225 rv = DoLoop(rv); 216 rv = DoLoop(rv);
226 if (rv != ERR_IO_PENDING) 217 if (rv != ERR_IO_PENDING)
227 callback_.Run(rv); 218 callback_.Run(rv);
228 } 219 }
229 220
230 State next_state_; 221 State next_state_;
231 bool received_malformed_response_; 222 bool received_malformed_response_;
232 223
233 scoped_ptr<DatagramClientSocket> socket_; 224 scoped_ptr<DnsSession::SocketLease> socket_lease_;
234 IPEndPoint server_;
235 scoped_ptr<DnsQuery> query_; 225 scoped_ptr<DnsQuery> query_;
236 226
237 scoped_ptr<DnsResponse> response_; 227 scoped_ptr<DnsResponse> response_;
238 228
239 CompletionCallback callback_; 229 CompletionCallback callback_;
240 230
241 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 231 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
242 }; 232 };
243 233
244 // ---------------------------------------------------------------------------- 234 // ----------------------------------------------------------------------------
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 374
385 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 375 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
386 callback.Run(this, result.rv, response); 376 callback.Run(this, result.rv, response);
387 } 377 }
388 378
389 // Makes another attempt at the current name, |qnames_.front()|, using the 379 // Makes another attempt at the current name, |qnames_.front()|, using the
390 // next nameserver. 380 // next nameserver.
391 AttemptResult MakeAttempt() { 381 AttemptResult MakeAttempt() {
392 unsigned attempt_number = attempts_.size(); 382 unsigned attempt_number = attempts_.size();
393 383
394 #if defined(OS_WIN)
395 // Avoid the Windows firewall warning about explicit UDP binding.
396 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413
397 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND;
398 #else
399 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND;
400 #endif
401
402 scoped_ptr<DatagramClientSocket> socket(
403 session_->socket_factory()->CreateDatagramClientSocket(
404 bind_type,
405 base::Bind(&base::RandInt),
406 net_log_.net_log(),
407 net_log_.source()));
408
409 uint16 id = session_->NextQueryId(); 384 uint16 id = session_->NextQueryId();
410 scoped_ptr<DnsQuery> query; 385 scoped_ptr<DnsQuery> query;
411 if (attempts_.empty()) { 386 if (attempts_.empty()) {
412 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 387 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
413 } else { 388 } else {
414 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 389 query.reset(attempts_[0]->query()->CloneWithNewId(id));
415 } 390 }
416 391
417 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
418 socket->NetLog().source().ToEventParametersCallback());
419
420 const DnsConfig& config = session_->config(); 392 const DnsConfig& config = session_->config();
421 393
422 unsigned server_index = first_server_index_ + 394 unsigned server_index = first_server_index_ +
423 (attempt_number % config.nameservers.size()); 395 (attempt_number % config.nameservers.size());
424 396
425 DnsUDPAttempt* attempt = new DnsUDPAttempt( 397 DnsUDPAttempt* attempt = new DnsUDPAttempt(
426 socket.Pass(), 398 session_->AllocateSocket(server_index, net_log_.source()),
427 config.nameservers[server_index],
428 query.Pass(), 399 query.Pass(),
429 base::Bind(&DnsTransactionImpl::OnAttemptComplete, 400 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
430 base::Unretained(this), 401 base::Unretained(this),
431 attempt_number)); 402 attempt_number));
432 403
404 net_log_.AddEvent(
405 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
406 attempt->socket_net_log().source().ToEventParametersCallback());
407
433 attempts_.push_back(attempt); 408 attempts_.push_back(attempt);
434 409
435 int rv = attempt->Start(); 410 int rv = attempt->Start();
436 if (rv == ERR_IO_PENDING) { 411 if (rv == ERR_IO_PENDING) {
437 timer_.Stop(); 412 timer_.Stop();
438 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 413 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
439 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 414 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
440 } 415 }
441 return AttemptResult(rv, attempt); 416 return AttemptResult(rv, attempt);
442 } 417 }
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 } // namespace 564 } // namespace
590 565
591 // static 566 // static
592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 567 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
593 DnsSession* session) { 568 DnsSession* session) {
594 return scoped_ptr<DnsTransactionFactory>( 569 return scoped_ptr<DnsTransactionFactory>(
595 new DnsTransactionFactoryImpl(session)); 570 new DnsTransactionFactoryImpl(session));
596 } 571 }
597 572
598 } // namespace net 573 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698