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

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

Issue 10826229: [net/dns] Reuse pre-connected sockets in DnsTransaction to add entropy to source ports. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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
« no previous file with comments | « net/dns/dns_session.cc ('k') | no next file » | 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
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 socket_(socket.Pass()), 71 socket_lease_(socket_lease.Pass()),
75 server_(server),
76 query_(query.Pass()), 72 query_(query.Pass()),
77 callback_(callback) { 73 callback_(callback) {
78 } 74 }
79 75
80 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 76 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
81 // and calls |callback| upon completion. 77 // and calls |callback| upon completion.
82 int Start() { 78 int Start() {
83 DCHECK_EQ(STATE_NONE, next_state_); 79 DCHECK_EQ(STATE_NONE, next_state_);
84 next_state_ = STATE_CONNECT; 80 next_state_ = STATE_SEND_QUERY;
85 return DoLoop(OK); 81 return DoLoop(OK);
86 } 82 }
87 83
88 const DnsQuery* query() const { 84 const DnsQuery* query() const {
89 return query_.get(); 85 return query_.get();
90 } 86 }
91 87
92 const DatagramClientSocket* socket() const { 88 const DatagramClientSocket* socket() const {
93 return socket_.get(); 89 return socket_lease_->socket();
94 } 90 }
95 91
96 // Returns the response or NULL if has not received a matching response from 92 // Returns the response or NULL if has not received a matching response from
97 // the server. 93 // the server.
98 const DnsResponse* response() const { 94 const DnsResponse* response() const {
99 const DnsResponse* resp = response_.get(); 95 const DnsResponse* resp = response_.get();
100 return (resp != NULL && resp->IsValid()) ? resp : NULL; 96 return (resp != NULL && resp->IsValid()) ? resp : NULL;
101 } 97 }
102 98
103 // Returns a Value representing the received response, along with a reference 99 // Returns a Value representing the received response, along with a reference
104 // to the NetLog source source of the UDP socket used. The request must have 100 // to the NetLog source source of the UDP socket used. The request must have
105 // completed before this is called. 101 // completed before this is called.
106 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const { 102 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
107 DCHECK(response_->IsValid()); 103 DCHECK(response_->IsValid());
108 104
109 DictionaryValue* dict = new DictionaryValue(); 105 DictionaryValue* dict = new DictionaryValue();
110 dict->SetInteger("rcode", response_->rcode()); 106 dict->SetInteger("rcode", response_->rcode());
111 dict->SetInteger("answer_count", response_->answer_count()); 107 dict->SetInteger("answer_count", response_->answer_count());
112 socket_->NetLog().source().AddToEventParameters(dict); 108 socket()->NetLog().source().AddToEventParameters(dict);
113 return dict; 109 return dict;
114 } 110 }
115 111
116 private: 112 private:
117 enum State { 113 enum State {
118 STATE_CONNECT,
119 STATE_SEND_QUERY, 114 STATE_SEND_QUERY,
120 STATE_SEND_QUERY_COMPLETE, 115 STATE_SEND_QUERY_COMPLETE,
121 STATE_READ_RESPONSE, 116 STATE_READ_RESPONSE,
122 STATE_READ_RESPONSE_COMPLETE, 117 STATE_READ_RESPONSE_COMPLETE,
123 STATE_NONE, 118 STATE_NONE,
124 }; 119 };
125 120
121 DatagramClientSocket* my_socket() {
122 return socket_lease_->socket();
123 }
124
126 int DoLoop(int result) { 125 int DoLoop(int result) {
127 CHECK_NE(STATE_NONE, next_state_); 126 CHECK_NE(STATE_NONE, next_state_);
128 int rv = result; 127 int rv = result;
129 do { 128 do {
130 State state = next_state_; 129 State state = next_state_;
131 next_state_ = STATE_NONE; 130 next_state_ = STATE_NONE;
132 switch (state) { 131 switch (state) {
133 case STATE_CONNECT:
134 rv = DoConnect();
135 break;
136 case STATE_SEND_QUERY: 132 case STATE_SEND_QUERY:
137 rv = DoSendQuery(); 133 rv = DoSendQuery();
138 break; 134 break;
139 case STATE_SEND_QUERY_COMPLETE: 135 case STATE_SEND_QUERY_COMPLETE:
140 rv = DoSendQueryComplete(rv); 136 rv = DoSendQueryComplete(rv);
141 break; 137 break;
142 case STATE_READ_RESPONSE: 138 case STATE_READ_RESPONSE:
143 rv = DoReadResponse(); 139 rv = DoReadResponse();
144 break; 140 break;
145 case STATE_READ_RESPONSE_COMPLETE: 141 case STATE_READ_RESPONSE_COMPLETE:
146 rv = DoReadResponseComplete(rv); 142 rv = DoReadResponseComplete(rv);
147 break; 143 break;
148 default: 144 default:
149 NOTREACHED(); 145 NOTREACHED();
150 break; 146 break;
151 } 147 }
152 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 148 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
153 149
154 return rv; 150 return rv;
155 } 151 }
156 152
157 int DoConnect() {
158 next_state_ = STATE_SEND_QUERY;
159 return socket_->Connect(server_);
160 }
161
162 int DoSendQuery() { 153 int DoSendQuery() {
163 next_state_ = STATE_SEND_QUERY_COMPLETE; 154 next_state_ = STATE_SEND_QUERY_COMPLETE;
164 return socket_->Write(query_->io_buffer(), 155 return my_socket()->Write(query_->io_buffer(),
165 query_->io_buffer()->size(), 156 query_->io_buffer()->size(),
166 base::Bind(&DnsUDPAttempt::OnIOComplete, 157 base::Bind(&DnsUDPAttempt::OnIOComplete,
167 base::Unretained(this))); 158 base::Unretained(this)));
168 } 159 }
169 160
170 int DoSendQueryComplete(int rv) { 161 int DoSendQueryComplete(int rv) {
171 DCHECK_NE(ERR_IO_PENDING, rv); 162 DCHECK_NE(ERR_IO_PENDING, rv);
172 if (rv < 0) 163 if (rv < 0)
173 return rv; 164 return rv;
174 165
175 // Writing to UDP should not result in a partial datagram. 166 // Writing to UDP should not result in a partial datagram.
176 if (rv != query_->io_buffer()->size()) 167 if (rv != query_->io_buffer()->size())
177 return ERR_MSG_TOO_BIG; 168 return ERR_MSG_TOO_BIG;
178 169
179 next_state_ = STATE_READ_RESPONSE; 170 next_state_ = STATE_READ_RESPONSE;
180 return OK; 171 return OK;
181 } 172 }
182 173
183 int DoReadResponse() { 174 int DoReadResponse() {
184 next_state_ = STATE_READ_RESPONSE_COMPLETE; 175 next_state_ = STATE_READ_RESPONSE_COMPLETE;
185 response_.reset(new DnsResponse()); 176 response_.reset(new DnsResponse());
186 return socket_->Read(response_->io_buffer(), 177 return my_socket()->Read(response_->io_buffer(),
187 response_->io_buffer()->size(), 178 response_->io_buffer()->size(),
188 base::Bind(&DnsUDPAttempt::OnIOComplete, 179 base::Bind(&DnsUDPAttempt::OnIOComplete,
189 base::Unretained(this))); 180 base::Unretained(this)));
190 } 181 }
191 182
192 int DoReadResponseComplete(int rv) { 183 int DoReadResponseComplete(int rv) {
193 DCHECK_NE(ERR_IO_PENDING, rv); 184 DCHECK_NE(ERR_IO_PENDING, rv);
194 if (rv < 0) 185 if (rv < 0)
195 return rv; 186 return rv;
196 187
197 DCHECK(rv); 188 DCHECK(rv);
198 if (!response_->InitParse(rv, *query_)) { 189 if (!response_->InitParse(rv, *query_)) {
199 // TODO(szym): Consider making this reaction less aggressive. 190 // TODO(szym): Consider making this reaction less aggressive.
(...skipping 16 matching lines...) Expand all
216 } 207 }
217 208
218 void OnIOComplete(int rv) { 209 void OnIOComplete(int rv) {
219 rv = DoLoop(rv); 210 rv = DoLoop(rv);
220 if (rv != ERR_IO_PENDING) 211 if (rv != ERR_IO_PENDING)
221 callback_.Run(rv); 212 callback_.Run(rv);
222 } 213 }
223 214
224 State next_state_; 215 State next_state_;
225 216
226 scoped_ptr<DatagramClientSocket> socket_; 217 scoped_ptr<DnsSession::SocketLease> socket_lease_;
227 IPEndPoint server_;
228 scoped_ptr<DnsQuery> query_; 218 scoped_ptr<DnsQuery> query_;
229 219
230 scoped_ptr<DnsResponse> response_; 220 scoped_ptr<DnsResponse> response_;
231 221
232 CompletionCallback callback_; 222 CompletionCallback callback_;
233 223
234 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 224 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
235 }; 225 };
236 226
237 // ---------------------------------------------------------------------------- 227 // ----------------------------------------------------------------------------
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 367
378 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv); 368 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
379 callback.Run(this, result.rv, response); 369 callback.Run(this, result.rv, response);
380 } 370 }
381 371
382 // Makes another attempt at the current name, |qnames_.front()|, using the 372 // Makes another attempt at the current name, |qnames_.front()|, using the
383 // next nameserver. 373 // next nameserver.
384 AttemptResult MakeAttempt() { 374 AttemptResult MakeAttempt() {
385 unsigned attempt_number = attempts_.size(); 375 unsigned attempt_number = attempts_.size();
386 376
387 #if defined(OS_WIN)
388 // Avoid the Windows firewall warning about explicit UDP binding.
389 // TODO(szym): Reuse a pool of pre-bound sockets. http://crbug.com/107413
390 DatagramSocket::BindType bind_type = DatagramSocket::DEFAULT_BIND;
391 #else
392 DatagramSocket::BindType bind_type = DatagramSocket::RANDOM_BIND;
393 #endif
394
395 scoped_ptr<DatagramClientSocket> socket(
396 session_->socket_factory()->CreateDatagramClientSocket(
397 bind_type,
398 base::Bind(&base::RandInt),
399 net_log_.net_log(),
400 net_log_.source()));
401
402 uint16 id = session_->NextQueryId(); 377 uint16 id = session_->NextQueryId();
403 scoped_ptr<DnsQuery> query; 378 scoped_ptr<DnsQuery> query;
404 if (attempts_.empty()) { 379 if (attempts_.empty()) {
405 query.reset(new DnsQuery(id, qnames_.front(), qtype_)); 380 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
406 } else { 381 } else {
407 query.reset(attempts_[0]->query()->CloneWithNewId(id)); 382 query.reset(attempts_[0]->query()->CloneWithNewId(id));
408 } 383 }
409 384
410 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
411 socket->NetLog().source().ToEventParametersCallback());
412
413 const DnsConfig& config = session_->config(); 385 const DnsConfig& config = session_->config();
414 386
415 unsigned server_index = first_server_index_ + 387 unsigned server_index = first_server_index_ +
416 (attempt_number % config.nameservers.size()); 388 (attempt_number % config.nameservers.size());
417 389
418 DnsUDPAttempt* attempt = new DnsUDPAttempt( 390 DnsUDPAttempt* attempt = new DnsUDPAttempt(
419 socket.Pass(), 391 session_->AllocateSocket(server_index),
420 config.nameservers[server_index],
421 query.Pass(), 392 query.Pass(),
422 base::Bind(&DnsTransactionImpl::OnAttemptComplete, 393 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
423 base::Unretained(this), 394 base::Unretained(this),
424 attempt_number)); 395 attempt_number));
425 396
397 net_log_.AddEvent(
398 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
399 attempt->socket()->NetLog().source().ToEventParametersCallback());
400
426 attempts_.push_back(attempt); 401 attempts_.push_back(attempt);
427 402
428 int rv = attempt->Start(); 403 int rv = attempt->Start();
429 if (rv == ERR_IO_PENDING) { 404 if (rv == ERR_IO_PENDING) {
430 timer_.Stop(); 405 timer_.Stop();
431 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 406 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
432 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 407 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
433 } 408 }
434 return AttemptResult(rv, attempt); 409 return AttemptResult(rv, attempt);
435 } 410 }
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 } // namespace 554 } // namespace
580 555
581 // static 556 // static
582 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 557 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
583 DnsSession* session) { 558 DnsSession* session) {
584 return scoped_ptr<DnsTransactionFactory>( 559 return scoped_ptr<DnsTransactionFactory>(
585 new DnsTransactionFactoryImpl(session)); 560 new DnsTransactionFactoryImpl(session));
586 } 561 }
587 562
588 } // namespace net 563 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_session.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698